Compare commits

...

388 Commits

Author SHA1 Message Date
Miku AuahDark 55feb38fa1 Release 11.5 hotfix 1. 2023-12-29 13:51:37 +08:00
Miku AuahDark 6811eca7d2 Artifact unstripped .so files. 2023-12-29 13:32:16 +08:00
Miku AuahDark d1f74df686 Don't set the intent to null, only set the intent data to null.
Issue #260.
2023-12-25 12:23:18 +08:00
Miku AuahDark c3ed3b454b Sanitize destination filename from content URI.
Fixes #257.
2023-12-23 13:08:00 +08:00
Miku AuahDark 8a3d635cdb LOVE Loader: Add missing FLAG_GRANT_READ_URI_PERMISSION flag. 2023-12-23 12:58:55 +08:00
Miku AuahDark a81931be2c Merge pull request #259 from marclurr/fix-embedding
Fix embedding
2023-12-10 17:57:26 +08:00
Mark 7a0068535b Remove unreachable code 2023-12-09 14:52:26 +00:00
Mark 034a6d6361 initialise needToCopyGameInArchive inside onCreate based on the value
of embed
2023-12-09 12:29:23 +00:00
Miku AuahDark 7a32a370f9 Release 11.5. 2023-12-03 20:46:00 +08:00
Miku AuahDark 8687928a33 Update LOVE submodule. 2023-11-27 12:52:04 +08:00
Miku AuahDark 6d67b15e79 SDL: Disable building Android audio subsystems. 2023-11-25 22:38:28 +08:00
Miku AuahDark ecb5076b3d Update LOVE submodule. 2023-11-25 22:32:44 +08:00
Miku AuahDark 3b80a5a766 Update SDL to 2.28.5. 2023-11-25 22:31:57 +08:00
Miku AuahDark 69cfcd25fb Rebuild LuaJIT for ARMv7 and x86.
Previous build was compiled for Android Lollipop. It must be compiled for Jelly Bean instead.
2023-11-25 22:07:01 +08:00
Miku AuahDark 8bbe71a6bb Add <LuaJIT>/android/<arch> to exported include directories. 2023-11-25 21:49:56 +08:00
Miku AuahDark d9ea1f60a5 Rebuild LuaJIT after 044d5b5. 2023-11-25 21:43:50 +08:00
Miku AuahDark a3b1903250 Use LuaJIT build script from Megasource's 12.x branch. 2023-11-25 21:43:06 +08:00
Miku AuahDark 044d5b5e34 Update LuaJIT to LuaJIT/LuaJIT@43d0a19. 2023-11-25 21:41:59 +08:00
Miku AuahDark abd98a1378 Replace Python script with Unix Shell and Powershell script.
Fixes #246.
2023-11-25 18:04:19 +08:00
Miku AuahDark 86dbfffcfc Restore old behavior of launching LOVE from launcher after ae465f8.
The old behavior is to re-start no-game screen when launching LOVE from app launcher for non-embed builds.
2023-11-15 12:33:41 +08:00
Miku AuahDark b2686d98e5 Update LOVE submodule. 2023-11-15 12:26:52 +08:00
Miku AuahDark 11d99352dc Fixed minor issue with LOVE Loader launcher. 2023-11-15 12:25:48 +08:00
Miku AuahDark f2970f47b1 Potentially fix unexpected "love.filedropped" event when launching .love files.
Issue #254
2023-11-15 11:47:07 +08:00
Miku AuahDark 8a882cabc0 Add notice about AGP bug for 3rd-party modules. 2023-09-27 12:48:53 +08:00
Miku AuahDark f7bc09eac0 Update Gradle to 8.1. 2023-09-26 15:59:30 +08:00
Miku AuahDark 8b77791aeb Apply LOVE 11.x-specific patch to SDL2. 2023-09-26 15:49:26 +08:00
Miku AuahDark eac9c7dc6a Update SDL to 2.28.3. 2023-09-26 15:48:40 +08:00
Miku AuahDark d257a3b987 Update compile SDK version and NDK version.
* Target API level 34.

* Update NDK to r25b. This will be the last NDK update to LOVE 11.x as future NDK dropped support for Android KitKat and earlier.
2023-09-26 14:25:00 +08:00
Miku AuahDark af732a0f47 Update LOVE submodule to love2d/love@2deb627. 2023-09-26 13:44:01 +08:00
Miku AuahDark 9b9cc15813 Recompile LuaJIT for Android with debug information. 2023-06-01 15:38:14 +08:00
Miku AuahDark eeb47f70c0 Update LOVE Submodule. 2023-06-01 15:38:13 +08:00
Miku AuahDark 729c355674 Minor fix from LuaJIT upstream.
LuaJIT/LuaJIT@224129a8e6
2023-06-01 15:38:13 +08:00
Miku AuahDark 81ff3acca7 Merge pull request #249 from MikuAuahDark/selector
Provide App To Select *.love File to Open
2023-04-19 14:25:26 +08:00
Miku AuahDark 0b106828b2 Initial "Loader" launcher. 2023-04-18 13:20:56 +08:00
Miku AuahDark 5187166c3d Update LuaJIT to LuaJIT/LuaJIT@1c27912705. 2023-04-18 10:25:19 +08:00
Miku AuahDark c8ebfc3427 Update copyright to 2023. 2023-04-18 10:05:14 +08:00
Miku AuahDark bda684ae1c Simplify isNativeLibsExtracted() 2023-04-18 09:50:11 +08:00
Miku AuahDark 7ee3735d1a Apply LOVE 11.x-specific patch to SDL2. 2023-04-18 09:39:33 +08:00
Miku AuahDark 55853d5850 Update SDL to 2.26.5. 2023-04-18 09:37:23 +08:00
Miku AuahDark f9eca86935 Minor dependency and readme update. 2023-04-17 21:09:38 +08:00
Miku AuahDark 5d34bf94f3 Update version. 2023-04-16 15:42:13 +08:00
Miku AuahDark acb97d6f87 Update LOVE Submodule. 2023-04-16 15:40:58 +08:00
Miku AuahDark a1868f713d Perform minor changes. 2023-04-16 15:39:44 +08:00
Miku AuahDark 569df256e3 Upgrade to AGP 8.0 2023-04-16 14:53:12 +08:00
Miku AuahDark 349c1e3dda Apply recommended changes by Android Studio. 2023-04-16 14:42:12 +08:00
Miku AuahDark 75fd79b37a Update Android Gradle Plugin. 2023-04-16 14:26:24 +08:00
Miku AuahDark 187e408d0b Update GitHub Actions dependencies. 2023-02-12 14:03:45 +08:00
Miku AuahDark eddaf2d70a Addendum to #243 and #244
* Revert configurable activity name. Always use "org.love2d.android.GameActivity"

* Delete unnecessary AndroidManifext.xml for embed variant.

* Workaround non-UTF-8 app.name in gradle.properties. See gradle.properties for more information.
2023-02-12 13:22:29 +08:00
flamendless a0740420e8 Fix the previous PR's error (#244)
* Abstract configurable values to gradle.properties

* Remove gms in AndroidManifest

* Fix AndroidManifest
2023-02-06 20:50:46 +08:00
flamendless 69dcd4b63b Abstract configurable values to gradle.properties (#243)
* Abstract configurable values to gradle.properties

* Remove gms in AndroidManifest
2023-02-03 20:57:42 +08:00
Miku AuahDark a46d4211e6 Update LOVE submodule. 2023-01-01 15:18:26 +08:00
Miku AuahDark d72a5e4f1e Compile OpenAL-soft with hidden visibility by default. 2023-01-01 14:16:36 +08:00
Miku AuahDark ca0fe2c4ca Update README with new SDK and NDK version requirements. 2022-10-31 00:00:10 +08:00
Miku AuahDark feb20972b5 Update Gradle to 7.5.1 and AGP to 7.3.1 2022-10-30 23:52:48 +08:00
Miku AuahDark 63d53f3584 Android 13 build compatibility. 2022-10-30 23:47:32 +08:00
Miku AuahDark bed7d5c826 Add assert include file. 2022-10-30 22:19:22 +08:00
Miku AuahDark 542560bb2d Update LOVE submodule. 2022-10-30 22:03:33 +08:00
Miku AuahDark 8e61af7669 Update LOVE submodule. 2022-01-20 20:51:55 +08:00
Miku AuahDark 612a0d0d0c AssetManager: Use directory name without trailing slash when calling AssetManager.list()
It seems that earlier version of Android (probably Android 8) returns empty files if the
passed path in AssetManager.list() contains trailing slash.
2022-01-18 14:27:04 +08:00
Miku AuahDark 2cd3d319d0 Update README.md 2022-01-12 12:14:24 +08:00
Miku AuahDark b367b3733d Release 11.4 2022-01-05 00:48:12 +08:00
Miku AuahDark efaf0f7aa4 Update copyright year to 2022. 2022-01-01 10:44:50 +08:00
Miku AuahDark 8164f11ecb Update submodule. 2021-12-31 10:32:41 +08:00
Miku AuahDark 7ec4135598 LuaJIT: Update to LuaJIT/LuaJIT@a91d0d9d3b 2021-12-31 01:56:38 +08:00
Miku AuahDark 8ad534d227 SDL: Apply libsdl-org/SDL@2363ddc330 2021-12-30 15:19:02 +08:00
Miku AuahDark ba88c4107f SDL: Apply libsdl-org/SDL@a1e992b110 2021-12-30 15:17:07 +08:00
Miku AuahDark 645bae0831 Fixed /sdcard/Android/data/org.love2d.android/files/games/lovegame lookup.
See #194 for more information.
2021-12-28 14:48:34 +08:00
Miku AuahDark 9076e124fe Update LOVE submodule. 2021-12-12 10:06:50 +08:00
Miku AuahDark fd966a7298 Update target SDK to Android 12
We can't update NDK yet because it drops supports for Android Jelly Bean.
2021-12-05 14:26:58 +08:00
Miku AuahDark 17f92a71aa Update gradle library dependencies.
* AGP to 7.0.3
* AndroidX AppCompat to 1.4.0
2021-12-05 14:08:25 +08:00
Miku AuahDark 91ba32e893 Fix gradle wrapper inconsistencies. 2021-12-05 14:04:43 +08:00
Miku AuahDark 2f5394098c Increase minimum SDK version to API 16.
Don't think anyone uses ICS nowadays?
2021-12-05 13:54:00 +08:00
Miku AuahDark 17ec687714 Apply love-specific SDL2 patches to fix black screen. 2021-12-05 13:49:46 +08:00
Miku AuahDark cd0747806d Change how "embed" flag is passed. 2021-12-05 13:49:23 +08:00
Miku AuahDark b17ba72668 Remove hidapi from getLibraries.
libsdl-org/SDL@5b646cd19e
2021-12-05 13:12:35 +08:00
Miku AuahDark 06e4082dfb Apply love-specific SDL2 patches.
Hopefully this will be the last time.
2021-12-05 13:12:01 +08:00
Miku AuahDark 4001bdab19 Update SDL to 2.0.18 2021-12-05 12:52:45 +08:00
Miku AuahDark cd2280386e Update GitHub Actions steps to reflect newly refactored flavor. 2021-12-05 12:46:31 +08:00
Miku AuahDark b6cb0d037e Minor cleanup to GameActivity. 2021-12-05 12:03:23 +08:00
Miku AuahDark c9831be4a4 Refactor AndroidManifest.
Playstore flavor is now removed. Instead, another "record" flavor added:
* `embedNoRecord` - Embed version without recording support.
* `embedRecord` - Embed version with recording support.
* `normalNoRecord` - Normal version without recording support.
* `normalRecord` - Normal version with recording support.
2021-12-05 11:44:47 +08:00
Miku AuahDark a3fc057064 Revert "Implement partial "Share to LOVE" support." 2021-12-05 10:08:17 +08:00
Miku AuahDark a3ea2d5ca0 Update LuaJIT to LuaJIT/LuaJIT@b4b2dce9fc 2021-11-13 14:42:25 +08:00
Miku AuahDark c802045cb2 Update LOVE submodule. 2021-11-05 15:31:54 +08:00
Miku AuahDark 25de1b5de3 Remove redundant GameActivity.getAssetManager() 2021-11-05 13:59:46 +08:00
Miku AuahDark ab850bfc5d Implement GameActivity.buildFileLookup 2021-11-05 13:58:02 +08:00
Miku AuahDark 80078b3046 Update LOVE submodule. 2021-11-02 17:58:57 +08:00
Miku AuahDark ba0f568f15 Improve GameActivity.getCRequirePath() 2021-11-02 17:42:56 +08:00
Miku AuahDark 444a61b945 Add GameActivity.getCRequirePath()
Used by love.filesystem C loader later.
2021-11-01 20:32:10 +08:00
Miku AuahDark 52a80a4e54 Forgot to add .gitignore 2021-11-01 17:53:11 +08:00
Miku AuahDark 383fe4aec6 Initial modular 3rd-party C libs system. 2021-11-01 17:50:36 +08:00
Miku AuahDark b3d9ceb314 Do not obfuscate SDL Java wrappers.
Fixes #217
2021-10-13 19:19:31 +08:00
Miku AuahDark 61ed34b4c7 Reorder GitHub Actions checkout step. 2021-10-11 20:14:10 +08:00
Miku AuahDark 56ab3cef77 Try to silence some Play Console warnings.
Issue #215
2021-10-11 20:07:16 +08:00
Miku AuahDark ae0d89458a Add x86_64 abiFilters for debug.
This workaround problems on debugging/running from Android Studio. See #208
2021-08-21 14:37:25 +08:00
Miku AuahDark ab03301730 Update Gradle build system.
Highlights:
* At least JDK 11 and/or Android Studio 2020.3.1 is now required.
* Update AGP to 7.0 and Gradle to 7.2.
* Replace jcenter() repository with mavenCentral()

Known Issue:
* Currently NDK 22 can't be used to compile yet as GLSLang has compile errors.
2021-08-20 09:41:36 +08:00
Miku AuahDark 89c9fc0a70 Update love2d/love@1e69a8c485
to trigger new workflow run.
2021-08-07 14:08:27 +08:00
Miku AuahDark f507d58891 Use lld linker when linking everything. 2021-05-09 16:35:44 +08:00
Miku AuahDark 552376fc7a Remove x86-specific compile options for Theora
Turns out they're unsupported.
2021-05-09 16:31:18 +08:00
Miku AuahDark 1ff59f59e5 Recompile LuaJIT binaries with -fPIC and lld linker and rewrite build_instructions.bat 2021-05-09 16:30:18 +08:00
Miku AuahDark df01c4568b Update LOVE to love2d/love@e9c58c8192 2021-05-08 22:43:16 +08:00
Miku AuahDark 5862a884bd Update to LOVE to love2d/love@22455276f6 2021-02-06 23:03:47 +08:00
Miku AuahDark d023500320 Only copy game archive if it's requested. 2021-02-06 22:09:47 +08:00
Miku AuahDark 0480f4bac7 Add getAssetManager() method.
This method will be called from C++ side.
2021-02-06 19:30:08 +08:00
Miku AuahDark 59153900ad Update Android Gradle plugin to 4.1.1 2021-02-06 19:08:06 +08:00
Miku AuahDark 0008f9b49e Fix compile error. 2021-02-06 18:54:19 +08:00
Miku AuahDark c315ddff8b Fixed crash when plugging physical keyboard or joystick. 2021-01-21 17:03:43 +08:00
Miku AuahDark 7da70d9786 SDL: Apply https://hg.libsdl.org/SDL/rev/a8e6474302ea
Issue #198
2021-01-14 14:55:03 +08:00
Miku AuahDark ac3ce6af68 Reapply e1f6ce34f0
https://github.com/love2d/love-android/issues/200#issuecomment-757976093
2021-01-12 13:57:04 +08:00
Miku AuahDark 05150585bf Update LÖVE to love2d/love@4ebe64afe1
Issue #200
2021-01-09 23:47:42 +08:00
Miku AuahDark 5b51e05895 Add missing Android.mk for LuaJIT 2021-01-09 11:42:05 +08:00
Miku AuahDark e94fe1a70d Add missing x86-64 LuaJIT static library. 2021-01-05 10:14:58 +08:00
Miku AuahDark d59818bf69 Update LuaJIT to LuaJIT/LuaJIT@1e66d0f9e6 2021-01-05 10:13:12 +08:00
Miku AuahDark f56e03b47c Upload normal debug APK as artifacts too. 2020-12-25 23:10:36 +08:00
Miku AuahDark cf608eda1d Update submodule to love2d/love@9c4db00e94 2020-12-25 23:10:00 +08:00
Miku AuahDark aaae1f4392 Look in /sdcard/lovegame too in Android 9 and earlier for backward compatibility.
See #194 for further explanation about this change.
2020-12-25 23:06:41 +08:00
Miku AuahDark 71c07360a5 Update LOVE submodule love2d/love@57a2a88a09 2020-12-24 23:00:03 +08:00
Miku AuahDark 596cffc9dc Rename openURL -> openURLFromLOVE
It's probably a good idea to remove this function in 12.0 and replace
it by calls to SDL_OpenURL() in LOVE C++ code instead.
2020-12-24 22:48:58 +08:00
Miku AuahDark 0fe970a575 Apply the current love-specific patches. 2020-12-24 22:48:29 +08:00
Miku AuahDark 7ff727cc2d Update SDL to 2.0.14 2020-12-24 20:55:12 +08:00
Miku AuahDark c97bc90527 Rename "Alc" to "alc"
This caught me off-guard.
2020-12-24 20:33:33 +08:00
Miku AuahDark b96fd660f9 Pass sample rate and frames/buffer to opensl_latency.cpp to be used with Oboe later. 2020-12-24 20:08:47 +08:00
Miku AuahDark 321fd15d99 Add low latency audio feature in manifest.
... but make it optional
2020-12-24 15:18:57 +08:00
Miku AuahDark dfe836d39c Update OpenAL-soft to 1.21.0
This allows OpenAL-soft to use Oboe backend which uses AAudio in Android 8
or OpenSLES in earlier Android version. This switch is necessary for
Android 11 compatibility as OpenSLES is now deprecated in Android 11.

Plus, we also have low latency audio for free.
2020-12-24 15:01:23 +08:00
Miku AuahDark 96f7387ac5 Upload each APK as separate artifacts. 2020-12-23 22:19:05 +08:00
Miku AuahDark 1c0565b56e Update readme. 2020-12-23 21:44:40 +08:00
Miku AuahDark 9c94f41470 Ensure app/src/main/assets directory exist. 2020-12-23 21:24:19 +08:00
Miku AuahDark 5b9fbeacb5 Update GitHub actions workflow. 2020-12-19 20:45:06 +08:00
Miku AuahDark 0e41ef20b3 Android 11.0 compatibility (#195)
* Update dependencies and target SDK
* Update Gradle to 6.6.1
* Update target API level to 30
* Update AGP to 4.0.1
* Update Android Build Dependencies (androidx.appcompat:appcompat:1.2.0, androidx.multidex:multidex:2.0.1)
* Update readme
* Move /sdcard/lovegame directory. (closes #194)
* Potentially fixes black screen when reopening LOVE from app drawer (fixes #190)
* Downloader cleanup.
* Merge SDL AndroidManifest.xml to LOVE
* Implement partial "Share to LOVE" support.
* Enable resizeableActivity
2020-10-10 01:33:06 +08:00
Miku AuahDark 6c754106ea Revert "Increase target API level to 29 (Android 10.0)"
This reverts commit f0abf9b537.

See #194
2020-10-06 20:47:56 +08:00
Miku AuahDark f0abf9b537 Increase target API level to 29 (Android 10.0) 2020-06-27 19:49:55 +08:00
Miku AuahDark 31d7affd91 Remove setImmersiveMode code as it conflicts with SDL's immersive mode code.
Fixes #191
2020-06-22 12:57:38 +08:00
Miku AuahDark 20329a65a6 Do not use ID 1 for request code
As it's reserved by SDL for its Android_JNI_RequestPermission
2020-05-05 11:26:25 +08:00
Miku AuahDark 8a964146c1 Update SDL to 2.0.12 2020-05-05 10:31:43 +08:00
Miku AuahDark b1740eb4b6 Add license.txt and license notice to each Java files. 2020-02-01 00:37:34 +08:00
Miku AuahDark cb56ef28fb Update and cleanup readme. 2020-02-01 00:01:27 +08:00
Miku AuahDark ba299eeafb Fix embed flavor not starting up. 2020-01-31 23:20:49 +08:00
Miku AuahDark 3370e38eea Testing the Actions. 2020-01-31 22:12:12 +08:00
Miku AuahDark 7999e17a76 Exclude "Download" service/activity from embed flavor. 2020-01-31 21:34:21 +08:00
Miku AuahDark 5a80990790 Perform handleIntent conditional whetever it's embed build or not. 2020-01-31 14:58:53 +08:00
Miku AuahDark 62684832a6 Generate 3 different flavors: normal, playstore, embed. 2020-01-31 14:46:34 +08:00
Miku AuahDark 01c8018c36 Merge commit 'e721960f7e52fcadd7e0f4bda977b879adb12433'
Add 11.3 changelog.
2020-01-29 22:51:03 +08:00
Miku AuahDark 1fe71865f6 Update readme. 2020-01-29 22:42:52 +08:00
Miku AuahDark fa276ea4d8 Detect LOVE submodule first before building. 2019-11-24 17:36:32 +08:00
Miku AuahDark e721960f7e Update README 2019-11-17 11:50:36 +08:00
Martin Felis 18c9b3c401 Disable microphone for PlayStore build. 2019-10-29 22:59:28 +01:00
Miku AuahDark face22cff4 Release 11.3 2019-10-27 23:19:47 +08:00
Miku AuahDark 8b93b1eea2 Remove problematic dimens.xml when compiling. 2019-10-20 12:07:24 +08:00
Miku AuahDark 29821438ad Update APK manifest to 11.3 2019-10-10 23:23:28 +08:00
Miku AuahDark a199d54b50 Merge branch '11.x_submodule' into 0.11.x 2019-10-10 23:09:15 +08:00
Miku AuahDark 61ef9802a3 Really fix Martin's SDL hack. 2019-10-10 23:00:46 +08:00
Miku AuahDark ee81c4262d Unstable changes: Update SDL to 2.0.10
Bug: Martin's hack of restarting SDL no longer works in this SDL version
so more matches to LOVE central repository will be come soon.
2019-10-10 22:26:54 +08:00
Miku AuahDark 4be53bca65 Make LOVE as submodule 2019-10-08 15:13:08 +08:00
Alex Szpakowski c89ac83e37 Fix some readme syntax issues 2019-09-29 12:28:04 -03:00
Alex Szpakowski 29e49d9048 Merge pull request #1 from MikuAuahDark/micsupport
Recording support for Android (Java side)
2019-09-29 09:21:37 -03:00
Miku AuahDark 8c701dd3a4 Add microphone permission to AndroidManifest.xml 2019-09-29 15:25:01 +08:00
Miku AuahDark 59a5fcb875 Fixed mic permission requested 3 times and dialog not showing. 2019-09-29 15:24:35 +08:00
Miku AuahDark 05e193ddbd Add function to retrieve and request mic permission. 2019-09-29 12:46:17 +08:00
Miku AuahDark 0380160775 Update README file. 2019-09-24 15:10:56 +08:00
Miku AuahDark 376ae96cb1 Merged in AuahDark/love-android-sdl2/java-fix (pull request #22)
Various fixes related to manifest and Java code.
2019-08-10 12:36:55 +00:00
Miku AuahDark 8186794a03 Remove SDL_android_main.c from LOVE Android.mk
A notice from SDL_android_main.c:
"As of SDL 2.0.6 this file is no longer necessary."
2019-08-10 16:27:41 +08:00
Miku AuahDark 54b29fca4f Update APK version to 11.2 2019-08-10 16:25:40 +08:00
Miku AuahDark 45507c5282 Fix download manager crashing in newer devices.
Request storage permission in Mashmallow until Pie. Also added support of
HTTPS URL.
2019-08-10 16:10:16 +08:00
Miku AuahDark f18cf70c15 Minor changes to GameActivity.
Nothing that may cause something break. Mainly reordering & line optmization
changes.
2019-08-10 16:01:52 +08:00
Miku AuahDark 5df17ba075 Modify AndroidManifest.xml again(?)
Moved WRITE_EXTERNAL_STORAGE maxSdkVersion to 28. Although t.externalstorage=true
needs WRITE_EXTERNAL_STORAGE for Android Jelly Bean and earlier, it's needed
for the game downloader to store files in Downloads folder. However the permission
to do it is unnecessary since Android Q (API 29).
See https://developer.android.com/reference/android/app/DownloadManager.Request#setDestinationInExternalPublicDir(java.lang.String,%2520java.lang.String)

Use per-activity theme instead of per-application theme. We need different
theme for the GameActivity and the DownloadActivity.
2019-08-10 15:59:26 +08:00
Miku AuahDark 5090a072b2 Minor manifest change and some GameActivity changes.
Fixed storage permission request and do not hardcode "game.love" as the cache output
file.
2019-07-26 13:01:25 +08:00
Miku AuahDark 117bba5ff2 Minor changes.
Remove vibrate permission string, use Manifest.permission.VIBRATE instead!

Fix code style.

Set gamePath to empty when it fails to detect any game.love
2019-07-20 21:33:52 +08:00
Miku AuahDark 78e88a7473 Override getMainSharedObject()
This theoretically allows LOVE libs not to be extracted in Marshmallow
and later by utilizing extractNativeLibs=false. However this is left to
users (developer) to decide whetever to use this or not.
2019-07-20 20:49:25 +08:00
Miku AuahDark 2529265eed Modify AndroidManifest.xml again.
The first change is to change the launch mode from singleTop to singleTask.
This hopefully fixes issue with love.filesystem initialization issue.

The second change is to change the accepted mime type to application/octet-stream.
2019-07-20 19:58:51 +08:00
Miku AuahDark a2c79d95e0 Flip the storage permission check. 2019-07-20 10:03:32 +08:00
Miku AuahDark f761e43904 Fix *.love file association in Nougat and later.
Note that the file association is rather hacky but I can't find any method
which is compatible in Nougat and later as file:// URI is banned there.
2019-07-10 12:10:36 +08:00
Miku AuahDark cd6463b4e4 Implement content:// URI 2019-07-10 10:14:10 +08:00
Miku AuahDark 9298bed843 Fix embedded game.love loading if there's no external storage permission given.
Mainly affect Android M and later devices.
2019-07-10 09:16:06 +08:00
Miku AuahDark 94d31aefc1 Only request storage permission on JB and older.
The permission to read local, application external directory is granted
implicitly in KitKat and later versions.
2019-07-10 09:00:13 +08:00
Miku AuahDark 8d71234114 Merged in AuahDark/love-android-sdl2/clean-include (pull request #21)
Clean external dependency include paths from LOVE Android.mk
2019-07-06 04:16:00 +00:00
Miku AuahDark 799956e002 Fix theoretical Theora x86-64 build. 2019-07-04 13:32:07 +08:00
Miku AuahDark f8d0890519 Cleanup ogg-family (vorbis, theora) includes.
This means only SDL remains that has paths hardcoded.
2019-07-04 12:53:44 +08:00
Miku AuahDark c065fe9e56 Update Theora codec
Add x86(-64)-optimized assembly. Unfortunately ARM-optimized assembly
can't be used. Please report this to Theora maintainers :(
2019-07-04 11:49:13 +08:00
Miku AuahDark 77c7570f55 Fix Mpg123 export include. 2019-07-04 10:38:44 +08:00
Miku AuahDark 6d5d8c4540 OpenAL-soft: link with Android log library.
It seems that in ARM64, liblog is added implicitly, but for other arch,
it must be added explicitly.

See https://github.com/MikuAuahDark/livesim3-love-android/issues/5
2019-07-04 10:24:30 +08:00
Miku AuahDark 456273ebf0 Clean include paths of external dependency
This way, LOVE Android.mk doesn't have to be modified in case new libraries
added or in case old libraries gets updated and their name is different.
2019-07-04 10:11:34 +08:00
Miku AuahDark 7c48033960 Merged in AuahDark/love-android-sdl2/als-1.19.1 (pull request #19)
Update OpenAL-soft to 1.19.1
2019-07-03 20:39:29 +00:00
Miku AuahDark b8beb8a1f4 Merged in AuahDark/love-android-sdl2/ft-2.8.1 (pull request #20)
Update FreeType to 2.8.1
2019-07-03 20:38:39 +00:00
Miku AuahDark c1399fc44a Remove version number from folder 2019-07-03 22:07:04 +08:00
Miku AuahDark 077c1a350b Remove version number from folder 2019-07-03 21:59:56 +08:00
Miku AuahDark 40ec52368b Use LOCAL_EXPORT_C_INCLUDES to manage include paths.
Better than hardcoding the include path in LOVE Android.mk
2019-07-02 21:21:19 +08:00
Miku AuahDark 605ddefd0e Update FreeType to 2.8.1 2019-07-02 20:57:08 +08:00
Tae Hanazono 2a23cbd16d Clean LOVE Android.mk and rename/fix detection variables. 2019-07-02 11:15:16 +08:00
Tae Hanazono 0ebc4d9271 Update OpenAL-soft to 1.19.1 2019-07-02 10:16:25 +08:00
Tae Hanazono 07149c0ba8 Fix log2f conflict. 2019-07-01 23:05:08 +08:00
Miku AuahDark 288f005d86 Merged in AuahDark/love-android-sdl2/love11-arm64 (pull request #15)
Add ARM64 ABI support
2019-07-01 13:28:00 +00:00
Miku AuahDark 49ad4632b6 Merged in AuahDark/love-android-sdl2/love113-safearea (pull request #17)
Implement `love.window.getSafeArea` for Android (Java changes)
2019-07-01 13:21:52 +00:00
Tae Hanazono 6eafa708f9 Fix setImmersiveMode using unsupported flags in some older devices. 2019-02-09 18:53:42 +08:00
Tae Hanazono 53d24a1b5f Added method to retrieve safe area insets. 2019-02-08 23:56:23 +08:00
Tae Hanazono 3b7407ab34 Fix onResume using unsupported flags in some older devices. 2019-02-08 20:20:37 +08:00
Tae Hanazono e203f7ae4c Modify LOVE build.gradle
Again, two changes. First change is to add "arm64-v8a" to NDK abiFilters.
This is needed to really generate ARM64 binaries inside the APK.

The second change is to exclude libSDL2.so from the resulting APK. Since
LOVE statically links with SDL2, then there's no reason to have libSDL2.so
lying around inside the APK. It's also save the APK size a little bit.
2018-12-14 23:40:10 +08:00
Tae Hanazono 1349f27bd8 Modify OpenAL-soft Android.mk
The comment is self-explanatory.
2018-12-14 23:36:31 +08:00
Tae Hanazono 9a11b88572 Modify LOVE Android.mk
There are two changes in here. First change is to tell Android build
system to use NEON instruction support. Slime already wrote a
NEON-optimized matrix multiplication function which is already in love main
source code (see link below for related commit)
https://bitbucket.org/rude/love/commits/e61734b33581a485743ea79b87d02f8aeb77693e

The problem is that not all ARMv7 devices do support NEON instruction, but
I don't even think if such device exist in 2018 (or even in 2019). ARM64
guarantee NEON instruction support, so it's all good for ARM64.

The second change is to define "HAVE_SOCKLEN_T=1" only when building ARM64.
This is needed because LuaSocket (or enet, I don't remember exactly)
redefines socklen_t and this cause compiler error.
2018-12-14 23:25:32 +08:00
Tae Hanazono f88e0ba4b9 Start ARM64 support: build LuaJIT for arm64-v8a
I don't use the buildandroid.sh for this because it forces the host
compiler to 32-bit (-m32), but we do really need 64-bit host compiler to
build LuaJIT for ARM64 (also I'm in Windows).

So, I used Android NDK standalone toolchain then invoke make like this:
make CROSS=aarch64-linux-android- TARGET_SYS=Linux TARGET_CFLAGS="-D__ANDROID_API__=21" amalg

Then the resulting libluajit.a is copied to android/arm64-v8a/libluajit.a
2018-12-14 23:14:11 +08:00
Martin Felis 2fd01541c2 Updated buildscript for LuaJIT 2018-12-13 09:06:40 +01:00
Martin Felis fc85623f10 Fixed build settings (thanks to Tae Hanazono!) 2018-12-10 22:46:42 +01:00
Martin Felis 692ce8bb51 Updated build system to use compileSdkVersion 28. 2018-12-07 22:39:06 +01:00
Martin Felis 0394a380c4 Added missing file from LÖVE main 2018-12-07 19:58:06 +01:00
Martin Felis 0000c326a8 Updated LÖVE code to tag 11.2 (changeset 55dc225ee2) 2018-12-07 18:34:41 +01:00
Martin Felis 34e88d43ae merged 2018-12-07 17:57:07 +01:00
Martin Felis 94c8a99ddc Properly ask and check for permissions on android >= 23.
On the first run it will ask for permission and block the LÖVE thread until
it has been granted. Thanks to Tae Hanzano for the initial draft.
2018-12-07 17:32:01 +01:00
Martin Felis 1ea86d3305 Properly using SDL 2.0.9 paths and android 26 compatibility layers. 2018-12-07 17:24:32 +01:00
Martin Felis 696fae730c Merge branch 'sdl2_2.0.9_fix' into 0.11.x 2018-12-07 17:03:21 +01:00
Martin Felis a19404a902 Re-applied patch to restart native thread. Also 2018-11-18 23:55:14 +01:00
Martin Felis e2c44417d1 Renamed SDL2 directory (already contains 2.0.9 sources) 2018-11-18 22:29:36 +01:00
Martin Felis e23fb2c8ea Renamed SDL2 directory (already contains 2.0.9 sources) 2018-11-18 22:23:51 +01:00
Martin Felis 4de76a9c52 preparing update of SDL to 2.0.9 2018-11-18 22:21:57 +01:00
Martin Felis 973f9eef89 Updated buildToolsVersion to 28.0.3 and Android Gradle Plugin to 3.2.1 2018-11-18 12:29:55 +01:00
Martin Felis 0ac43aa717 Updated love sources to changeset 0ab246b5045d and updated android version 2018-04-15 21:22:56 +02:00
Martin Felis c186a70b14 Updated love sources to changeset 0ab246b5045d and updated android version 2018-04-15 21:22:56 +02:00
Martin Felis 7fbf155d82 Setting target SDK to 22 to mark app as legacy app which gets storage permissions without having to write request code 2018-04-15 11:05:23 +02:00
Martin Felis 7ad34c64f4 Setting target SDK to 22 to mark app as legacy app which gets storage permissions without having to write request code 2018-04-15 11:05:23 +02:00
Martin Felis 3df1807c6f Fix for #159 2018-04-08 21:03:05 +02:00
Martin Felis 29a493a54b Fix for #159 2018-04-08 21:03:05 +02:00
Martin Felis c979f65152 New version: 11.0. Also bumped minSdkVersion to 14 to be in sync with used SDL2 version 2018-04-01 22:52:58 +02:00
Martin Felis 75306e8e63 New version: 11.0. Also bumped minSdkVersion to 14 to be in sync with used SDL2 version 2018-04-01 22:52:58 +02:00
Martin Felis 1dba069683 Updated LÖVE to 11.0 tag (6504209dc45b) 2018-04-01 22:45:58 +02:00
Martin Felis ec8b710a93 Updated LÖVE to 11.0 tag (6504209dc45b) 2018-04-01 22:45:58 +02:00
Martin Felis 408778fb8f Minor adjustments for 0.11.0-alpha1 2018-03-31 19:48:40 +02:00
Martin Felis 45ae52f55e Minor adjustments for 0.11.0-alpha1 2018-03-31 19:48:40 +02:00
Martin Felis f8241c1b65 Updated LÖVE to changeset c303c1f52ea6 2018-03-30 21:42:03 +02:00
Martin Felis 91295b7506 Updated LÖVE to changeset c303c1f52ea6 2018-03-30 21:42:03 +02:00
Martin Felis 4d8f4f70ce Initial works to support 0.11.x, disabled armeabi builds, using now clang and libc++ instead of gnustl 2018-02-02 21:10:33 +01:00
Martin Felis ebd4a0ad4f Initial works to support 0.11.x, disabled armeabi builds, using now clang and libc++ instead of gnustl 2018-02-02 21:10:33 +01:00
Martin Felis f40577c9cb Upgraded OpenAL-Soft to 0.18.2 2018-02-01 15:53:05 +01:00
Martin Felis ac443d7e2f Upgraded OpenAL-Soft to 0.18.2 2018-02-01 15:53:05 +01:00
Martin Felis fd60978b7b Merge branch 'master' into 0.10.x 2018-01-24 10:17:36 +01:00
Martin Felis 8c7772cfa4 Merge branch 'master' into 0.10.x 2018-01-24 10:17:36 +01:00
Martin Felis 6ed3ba3810 Adjusted SDLActivity.java to allow restarting of the native thread 2018-01-23 21:27:41 +01:00
Martin Felis 21ff4b2188 Adjusted SDLActivity.java to allow restarting of the native thread 2018-01-23 21:27:41 +01:00
Martin Felis ba269a5062 Copied SDL2 2.0.7+ (changeset b359333bdc52) and adjusted gradle to use the new directory layout of the SDL2 android project 2018-01-23 21:22:56 +01:00
Martin Felis 4ffea15ffc Copied SDL2 2.0.7+ (changeset b359333bdc52) and adjusted gradle to use the new directory layout of the SDL2 android project 2018-01-23 21:22:56 +01:00
Martin Felis 74d83c0c13 Cleaned up formatting of Java code 2018-01-23 15:28:20 +01:00
Martin Felis 906a7cc00b Cleaned up formatting of Java code 2018-01-23 15:28:20 +01:00
Martin Felis f12ab60594 merge 2018-01-23 15:22:57 +01:00
Martin Felis 5f4aeb2d71 merge 2018-01-23 15:22:57 +01:00
Martin Felis fb34e99d9a merge 2018-01-22 22:57:29 +01:00
Martin Felis d62a4df5ac merge 2018-01-22 22:57:29 +01:00
Martin Felis ad5db40a9d Merge branch 'setSource_mount_order' 2018-01-22 22:52:36 +01:00
Martin Felis 406d0c04e2 Merge branch 'setSource_mount_order' 2018-01-22 22:52:36 +01:00
Martin Felis a00675c4cc Cleaned up logic of loading games on the Java side of the App 2018-01-22 22:52:16 +01:00
Martin Felis 0afdf271a2 Cleaned up logic of loading games on the Java side of the App 2018-01-22 22:52:16 +01:00
Martin Felis 7ebcf9494e Merge https://bitbucket.org/cigumo/love-android-sdl2/branch/master into setSource_mount_order 2018-01-22 13:28:18 +01:00
Martin Felis cff1a295a6 Merge https://bitbucket.org/cigumo/love-android-sdl2/branch/master into setSource_mount_order 2018-01-22 13:28:18 +01:00
Tiago Shibata 234bc83aa2 Merged in tiagokcshibata/love-android-sdl2 (pull request #8)
Add GameActivity.hasBackgroundMusic

Approved-by: Tiago Shibata <tiago.shibata@tapps.com.br>
Approved-by: Bart van Strien <bart.bes+projects@gmail.com>
2018-01-22 12:18:17 +00:00
Tiago Shibata 84dc89e264 Merged in tiagokcshibata/love-android-sdl2 (pull request #8)
Add GameActivity.hasBackgroundMusic

Approved-by: Tiago Shibata <tiago.shibata@tapps.com.br>
Approved-by: Bart van Strien <bart.bes+projects@gmail.com>
2018-01-22 12:18:17 +00:00
Martin Felis a22628bc1b Updgraded SDL2 to version 2.0.7 2017-12-26 22:04:21 +01:00
Martin Felis 487f00201e Updgraded SDL2 to version 2.0.7 2017-12-26 22:04:21 +01:00
Martin Felis 1fe6d7b640 Removed physfs, updated LÖVE to changeset 7bb02207faa6 2017-12-26 16:42:40 +01:00
Martin Felis 204945586e Removed physfs, updated LÖVE to changeset 7bb02207faa6 2017-12-26 16:42:40 +01:00
Martin Felis 004ccf4f9c Upgraded physfs to 3.0.1 2017-12-26 14:20:42 +01:00
Martin Felis f68cf2fcc4 Upgraded physfs to 3.0.1 2017-12-26 14:20:42 +01:00
Martin Felis f6c360c809 Updated gradle scripts so that it uses newer gradle version 2017-12-26 13:37:35 +01:00
Martin Felis 391429367d Updated gradle scripts so that it uses newer gradle version 2017-12-26 13:37:35 +01:00
cigumo baa595bd51 Changes Filesystem::setSource mount order on Android
Simplifies the way setSource is handled on Android. It tries to mount
first and if that fails it will copy to memory and mount.

The /sdcard/lovegame fallback is moved to GameActivity.java.

Also a flag is added (mustCacheArchive) that will copy the game.love
file to the cache dir, so it can be mounted directly and not loaded to
memory, which does not work for large .love files.

The Filesystem.cpp change was also submitted to rude/love repo in this
push request: https://bitbucket.org/rude/love/pull-requests/99
2017-11-16 19:53:41 -03:00
cigumo 957330d722 Changes Filesystem::setSource mount order on Android
Simplifies the way setSource is handled on Android. It tries to mount
first and if that fails it will copy to memory and mount.

The /sdcard/lovegame fallback is moved to GameActivity.java.

Also a flag is added (mustCacheArchive) that will copy the game.love
file to the cache dir, so it can be mounted directly and not loaded to
memory, which does not work for large .love files.

The Filesystem.cpp change was also submitted to rude/love repo in this
push request: https://bitbucket.org/rude/love/pull-requests/99
2017-11-16 19:53:41 -03:00
Tiago Koji Castro Shibata ecaf3f7f45 Add GameActivity.getMusicStreamVolume 2017-07-10 16:09:28 -03:00
Tiago Koji Castro Shibata b3db9d4839 Add GameActivity.getMusicStreamVolume 2017-07-10 16:09:28 -03:00
Martin Felis a1aca69aa4 Slight adjustments on how to build with the new gradle build system 2017-05-11 23:04:55 +02:00
Martin Felis 646de828b9 Slight adjustments on how to build with the new gradle build system 2017-05-11 23:04:55 +02:00
Martin Felis 0ffa7f7db7 Merge branch 'master' of ssh://bitbucket.org/MartinFelis/love-android-sdl2 2017-05-11 22:52:40 +02:00
Martin Felis 7d7e1cb1f9 Merge branch 'master' of ssh://bitbucket.org/MartinFelis/love-android-sdl2 2017-05-11 22:52:40 +02:00
Henrique Gemignani ee59b69e01 Merged in henriquegemignani_/love-android-sdl2/gradle (pull request #7)
Change buildsystem to Gradle / Android Studio
2017-05-11 20:51:48 +00:00
Henrique Gemignani 0ac0e39287 Merged in henriquegemignani_/love-android-sdl2/gradle (pull request #7)
Change buildsystem to Gradle / Android Studio
2017-05-11 20:51:48 +00:00
Henrique Gemignani Passos Lima 49d7b402a7 Use 'org.love2d.android' package name for the library. 2017-02-19 16:14:34 -03:00
Henrique Gemignani Passos Lima 529b897fed Use 'org.love2d.android' package name for the library. 2017-02-19 16:14:34 -03:00
Henrique Gemignani Passos Lima 7ef92ea876 Readme changes. 2017-02-19 16:08:49 -03:00
Henrique Gemignani Passos Lima 40b2aa6e6a Readme changes. 2017-02-19 16:08:49 -03:00
Henrique Gemignani Passos Lima 7c8b022dcb Make gradlew work. 2017-02-19 16:05:14 -03:00
Henrique Gemignani Passos Lima dbdefdd86a Make gradlew work. 2017-02-19 16:05:14 -03:00
Henrique Gemignani Passos Lima c931228238 Update gitignore with x86 luajit 2017-02-19 15:56:46 -03:00
Henrique Gemignani Passos Lima 15474cab41 Update gitignore with x86 luajit 2017-02-19 15:56:46 -03:00
Henrique Gemignani Passos Lima 2a0c579ebf Fix build on windows. 2017-02-19 15:56:10 -03:00
Henrique Gemignani Passos Lima af039516c0 Fix build on windows. 2017-02-19 15:56:10 -03:00
Henrique Gemignani Passos Lima cc457787f4 Fix build.gradle and add gradle/Android Studio entries to gitignore 2017-02-19 10:48:35 -03:00
Henrique Gemignani Passos Lima 76230b01f9 Fix build.gradle and add gradle/Android Studio entries to gitignore 2017-02-19 10:48:35 -03:00
Henrique Gemignani Passos Lima 3c922b0ae8 Move the java code. 2017-02-19 10:41:46 -03:00
Henrique Gemignani Passos Lima ab888ac39f Move the java code. 2017-02-19 10:41:46 -03:00
Henrique Gemignani Passos Lima fdb360a557 Move JNI folder. 2017-02-19 13:39:42 +00:00
Henrique Gemignani Passos Lima d32e6ada77 Move JNI folder. 2017-02-19 13:39:42 +00:00
Henrique Gemignani Passos Lima 46d624851b Fix JNI gitignore. 2017-02-19 10:38:07 -03:00
Henrique Gemignani Passos Lima 00cfe30282 Adding love libproject. 2017-02-19 10:32:44 -03:00
Henrique Gemignani Passos Lima 0cf41c2792 Removing more old files. 2017-02-19 10:28:28 -03:00
Henrique Gemignani Passos Lima 803786eee9 Initial files for gradle build. 2017-02-19 10:27:00 -03:00
Martin Felis c025e5eab4 Imported official LÖVE 0.10.2 release version 2016-11-01 20:21:18 +01:00
Martin Felis 35cd9f1900 Preparation for 0.10.2 release 2016-10-30 21:27:26 +01:00
Martin Felis 70f63954ed Applied LÖVE related patches to SDL2 2016-10-30 21:26:13 +01:00
Martin Felis f87d73671f updated SDLActivity to version from SDL2 2.0.5 2016-10-30 21:10:10 +01:00
Martin Felis 967840db16 Updated LÖVE codebase to 6d245a253bab 2016-10-30 19:08:36 +01:00
Martin Felis 6dedec28a2 Updated SDL to version 2.0.5 2016-10-22 22:10:28 +02:00
Martin Felis 2358b45c27 Merge commit '42093cf' 2016-08-30 23:11:50 +02:00
Martin Felis 08b116c09f Fixed linking errors due to using newer toolchain (4.9) 2016-08-30 23:08:04 +02:00
Martin Felis e9a3b2ac59 Merged in orangeudav/love-android-sdl2/orangeudav/update-to-actual-version-of-ndk-at-2016-1470408661381 (pull request #6)
Update to actual version of NDK at 2016
2016-08-25 06:53:49 +02:00
orangeudav 7345a01f56 Update to actual version of NDK at 2016 2016-08-05 14:51:10 +00:00
Martin Felis 42093cfbe9 Updated changes.txt from the 0.10.1 release 2016-02-14 16:18:59 +01:00
Martin Felis 8244228004 OpenGL ES fix and proper sizes for the icons 2016-02-14 14:14:31 +01:00
Martin Felis 7459285690 New release 0.10.1 2016-02-14 00:30:25 +01:00
Martin Felis 7aaeb1485e LuaJIT build script also builds for x86 and added the binary. First step to optional support of x86 android devices 2016-01-20 22:53:06 +01:00
Martin Felis 5e410bca8e Updated to latest LÖVE code (29f0bad6be9d), which adds the externalstorage config flag to conf.lua. Note: one cannot switch between internal and external storage after running the app! 2016-01-17 14:12:09 +01:00
Martin Felis 19e0b12363 Only enable vibration if we have the proper permissions (fixes #122) 2016-01-17 13:45:47 +01:00
Martin Felis 24387a8450 Updated SDL2 to the 2.0.4 release version 2016-01-17 13:22:47 +01:00
Martin Felis 962c894908 Release cleanup 2015-12-22 16:02:02 +01:00
Martin Felis 26a6c423f9 Updated to latest LÖVE code 2f5d329b07d7 (android: disable JIT by default as it may cause performance problems) 2015-12-22 10:06:57 +01:00
Martin Felis 08d51fbf28 Updated LÖVE source to changeset da332813bc05 2015-12-20 22:52:22 +01:00
Martin Felis eac5db7e10 Updated README.md for 0.10.0-alpha2 2015-12-09 23:52:09 +01:00
Martin Felis 28d2d92645 Updated LuaJIT to latest 2.1 version 2015-12-09 22:51:28 +01:00
Martin Felis 66685a2ade Updated LÖVE source to revision cff5bc8604bd 2015-12-09 22:19:41 +01:00
Martin Felis 8f5ee4a05e added building of the theora library 2015-12-09 12:41:20 +01:00
fysx 686e1d5f3e Update LÖVE to changeset 7cb21c8bdd64 (pre 0.10.0) 2015-12-01 23:07:34 +01:00
fysx 7e877716d6 Updated SDL2 to changeset 69a5f3a540af (dev version of 2.0.4) 2015-12-01 22:29:54 +01:00
fysx ec5f068b19 Updated OpenAL to version 1.16.0 2015-11-29 15:27:32 +01:00
fysx 8308a524bc Updated libogg to 1.3.2 and libvorbis to 1.3.5 2015-11-28 22:14:03 +01:00
fysx 4439a193d6 Fixed issue #115 (compatibility with Android 2.3 devices) 2015-11-28 21:58:50 +01:00
fysx 9cbddc2f5e Updated to latest love-android code (b615972822cb) 2015-08-13 17:21:53 +02:00
fysx f3dd769e98 Using latest love-android branch (9a508a54700d) 2015-08-13 11:12:17 +02:00
fysx c91dbb6957 Forcing use of GCC 4.8 to prevent compiling issues 2015-07-15 11:10:46 +02:00
fysx 198c2d28de new version: 0.10.0-alpha. Warning: this uses the not yet released 0.10.0 API of LÖVE. 0.9.2 games likely don't work! 2015-07-03 19:40:31 +02:00
fysx 357a7237a4 Using latest android branch of LÖVE (6d14516b05c9) that now syncs with default (woooo!) 2015-07-03 19:09:18 +02:00
fysx 1924bbdeeb updated changelog for 0.9.2a 2015-04-10 16:01:39 +02:00
fysx d783f5afa1 Preparing 0.9.2a release 2015-04-10 15:59:27 +02:00
fysx 7eb7db1a85 Imported latest love-android code 8e93b946d920 that fixes ParticleSystem:clone 2015-04-10 15:45:46 +02:00
fysx 8af8dffad4 fixed README markup 2015-04-10 11:55:14 +02:00
fysx a0efc89a7d preparing release 0.9.2 2015-04-10 11:43:31 +02:00
fysx c30e788393 properly detect whether we are in "fullscreen" (i.e. immersive) on Android 2015-02-19 00:15:31 +01:00
fysx 168357e1ad fixed #104: loading of multiple .love files 2015-02-18 10:33:54 +01:00
fysx d6f1d8bd70 imported changes from love-0.9.2 2015-02-16 00:37:14 +01:00
fysx 3cfecd46d9 added Download section to README.md 2015-02-15 23:21:53 +01:00
fysx f31760c445 made love.window.setFullscreen() work 2015-02-02 22:42:08 +01:00
fysx d0f866e4b0 fixed build for latest love-android version 2015-01-22 20:57:57 +01:00
fysx 542c029666 updated to latest love-android (changeset 7b5f223900b) 2015-01-22 10:48:45 +01:00
fysx 31cd05551e renamed setBorderless to setImmersive and linked it to the fullscreen mode 2015-01-20 22:11:56 +01:00
fysx 42f6beaa7e Allowing enabling and disabling of immersive mode via borderless setting and love.window.setMode() 2015-01-20 16:01:43 +01:00
fysx 36216c16be fixed immersive mode when resuming 2015-01-20 14:36:57 +01:00
fysx 013df025d0 fix for #91 and #98: printing of non-number and non-string values 2015-01-16 22:13:33 +01:00
fysx 535a8256ee Using immersive mode by default 2015-01-16 20:41:03 +01:00
fysx b732d6cc12 replaced tabs with spaces 2015-01-16 20:40:23 +01:00
fysx 54215b7ce4 refactored loading of games on android 2015-01-16 20:00:51 +01:00
fysx fd9e9758a9 Using latest changeset 593639000823 of love-android 2015-01-16 12:31:11 +01:00
fysx f46115e794 ignoring *.orig files from mercurial merges 2015-01-16 12:30:43 +01:00
fysx 29a3e4b566 fixed APP_PLATFORM warning 2015-01-13 20:57:00 +01:00
fysx 02dc18a587 fixed compilation with Android NDK r10 2015-01-11 22:23:12 +01:00
fysx a034220b10 tried to list dependent softwares and licenses 2014-11-12 10:37:43 +01:00
fysx 72b2fcd4eb Added loading of games by opening the main.lua file 2014-10-22 11:54:04 +02:00
fysx b20f7e7302 Stop the vibrator when the app is paused (e.g. when device is switched off or app goes in background) 2014-10-22 11:26:52 +02:00
fysx 6b1fae429b not calling exit(retval) when main ends 2014-10-21 12:21:02 +02:00
fysx 4ec2e26985 updated to latest SDL2 (f9244b2a151) 2014-10-21 12:20:26 +02:00
fysx 8df94d2a8a Properly pausing OpenAL device using the extension alcDevicePauseSOFT (fixes #83) 2014-09-09 10:29:56 +02:00
fysx 70eef137ae updated OpenAL-Soft to version 1.16.0 2014-09-08 21:17:12 +02:00
fysx 4f11bd0e7b fixed #82: was using wrong argument to query module instance 2014-08-31 14:14:15 +02:00
fysx 5048f3ff8c properly increased android:versionCode 2014-08-28 15:28:57 +02:00
fysx 66f600b5ab New version: 0.9.1b 2014-08-28 11:52:30 +02:00
fysx 659b312121 fixed mousepress event coordinates 2014-08-28 11:44:32 +02:00
fysx b875fffedb updated from latest love-android (228a26ab99bb) 2014-08-28 10:55:10 +02:00
fysx 45b1fc2509 fixed compilation and removed some unneeded files 2014-08-27 23:33:50 +02:00
fysx c6ac06c366 actual update to latest mobile-common 2014-08-27 23:23:26 +02:00
fysx abb819335b updated to latest mobile-common (0cf55b7da58e), removed libtiff, libpng, libmng, devil, jasper, jpeg-8d, added libturbo-jpeg 2014-08-27 23:19:11 +02:00
Martin Felis aba2f47b31 removed printing redirect tag from [LOVE2D] to [LOVE] 2014-08-18 19:04:40 +02:00
Martin Felis ea459a43da removed random text 2014-08-18 19:03:55 +02:00
Martin Felis 6110de0fa8 implemented love.system.vibrate(seconds) 2014-08-18 18:47:13 +02:00
Martin Felis 8f20cb7cc5 added print redirect to SDL_Log (fixes #40) 2014-08-18 16:23:39 +02:00
Martin Felis b25af54383 Merged in PabloMayobre/love-android-sdl2/PabloMayobre/same-as-4c481f993306-use-app_process-as-1405185954174 (pull request #3)
Same as  4c481f9933. Use 'app_process' as executable name (should fix #71 and #23)

Thanks!!
2014-07-12 21:47:41 +02:00
Pablo Mayobre c27f19c141 Same as 4c481f9933. Use 'app_process' as executable name (should fix #71 and #23) 2014-07-12 17:25:58 +00:00
fysx d1ad6cc5a3 fixed README markdown syntax 2014-07-01 17:08:55 +02:00
fysx afe33f06d2 Updated Readme for tag 0.9.1a 2014-07-01 17:06:27 +02:00
fysx 70cb26bb2a bumped version to 0.9.1a 2014-05-25 16:34:53 +02:00
fysx 8cb7bac09f using latest SDL_androidgl.c that removes some calls to eglWaitXXX() calls 2014-05-25 16:30:27 +02:00
fysx 49265f0596 using latest love-android @ changeset 8659be0e75a3 2014-05-25 16:27:34 +02:00
fysx 1d29da2d80 preparing release 0.9.1 2014-05-12 21:43:03 +02:00
fysx 6459889d32 fixed loading of jpegs by reverting libjpeg to version 8d 2014-05-12 00:08:20 +02:00
fysx 6be242ef03 newly generated graphics.lua.h (should actually fix #31) 2014-05-03 17:26:21 +02:00
fysx 97d9154e48 updated to latest mobile-common (should fix love.touch index problems) 2014-05-03 14:13:40 +02:00
fysx c40250e565 fix for #31 2014-05-03 14:06:28 +02:00
fysx 684adff826 updated manifest for 0.9.1-RC1 version 2014-04-04 13:24:10 +02:00
fysx ec9be8a383 removed duplicate entries in AndroidManifest.xml 2014-04-04 13:09:39 +02:00
fysx d637b5c11d updated SDLActivity.java 2014-04-04 13:06:32 +02:00
fysx adc4042d8b deleted stale file 2014-04-04 11:38:13 +02:00
fysx e96eef4435 Using latest love-android branch (e263d91d136d) 2014-04-04 11:37:36 +02:00
fysx 8acfb8d91a Disabled building of dynamic library for SDL2 2014-04-04 11:35:52 +02:00
fysx cc829bdd1e added code to support the upcoming love.system.openURL 2014-04-03 18:20:37 +02:00
fysx 7593d64761 Upgraded SDL2 to version 2.0.3 2014-04-03 16:45:01 +02:00
fysx f09239788a fixed markdown in README 2014-02-23 15:28:17 +01:00
fysx c0fd9a6e1b beta2 2014-02-23 15:21:29 +01:00
fysx 539ca8d4f2 fixed opening of .love files when URL is entered in Chrome 2014-02-23 14:51:33 +01:00
fysx fab725ad8b using identity 'unnamed' if none is specified in conf.lua(fixes issue #46) 2014-02-20 22:31:59 +01:00
8789 changed files with 1419417 additions and 1723315 deletions
+50
View File
@@ -0,0 +1,50 @@
name: build
on: [push, pull_request]
jobs:
build-android:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Setup Java 17
uses: actions/setup-java@v3
with:
distribution: adopt-hotspot
java-version: 17
cache: gradle
- name: Build
run: bash ./gradlew assembleNormalRecord assembleEmbedRelease bundleNormalNoRecordRelease bundleEmbedRecordRelease bundleEmbedNoRecordRelease
- name: Artifact (Normal debug APK)
uses: actions/upload-artifact@v3
with:
name: love-android-debug.apk
path: app/build/outputs/apk/normalRecord/debug/app-normal-record-debug.apk
- name: Artifact (Normal unsigned APK)
uses: actions/upload-artifact@v3
with:
name: love-android.apk
path: app/build/outputs/apk/normalRecord/release/app-normal-record-release-unsigned.apk
- name: Artifact (Normal AAB w/o recording)
uses: actions/upload-artifact@v3
with:
name: love-android-ps.aab
path: app/build/outputs/bundle/normalNoRecordRelease/app-normal-noRecord-release.aab
- name: Artifact (Embed AAB)
uses: actions/upload-artifact@v3
with:
name: love-android-embed-record.aab
path: app/build/outputs/bundle/embedRecordRelease/app-embed-record-release.aab
- name: Artifact (Embed AAB w/o recording)
uses: actions/upload-artifact@v3
with:
name: love-android-embed.aab
path: app/build/outputs/bundle/embedNoRecordRelease/app-embed-noRecord-release.aab
- name: Artifact (Debug symbols)
uses: actions/upload-artifact@v3
with:
name: love-android-unstripped-debugsyms
path: love/build/intermediates/library_jni
+17 -15
View File
@@ -12,20 +12,22 @@ local.properties
*.o
*.so
*.a
*.orig
*.rej
!jni/LuaJIT-2.0.1/android/armeabi/libluajit.a
!jni/LuaJIT-2.0.1/android/armeabi-v7a/libluajit.a
jni/LuaJIT-2.0.1/buildandroid.sh
jni/LuaJIT-2.0.1/src/host/buildvm
jni/LuaJIT-2.0.1/src/host/buildvm_arch.h
jni/LuaJIT-2.0.1/src/host/minilua
jni/LuaJIT-2.0.1/src/jit/vmdef.lua
jni/LuaJIT-2.0.1/src/libluajit.a
jni/LuaJIT-2.0.1/src/lj_bcdef.h
jni/LuaJIT-2.0.1/src/lj_ffdef.h
jni/LuaJIT-2.0.1/src/lj_folddef.h
jni/LuaJIT-2.0.1/src/lj_libdef.h
jni/LuaJIT-2.0.1/src/lj_recdef.h
jni/LuaJIT-2.0.1/src/lj_vm.s
jni/LuaJIT-2.0.1/src/luajit
# Downloaded gradle wrapper
.gradle
# Android Studio project files
.idea
*.iml
# Gradle build files
build
.externalNativeBuild
.cxx
# love-android specific
!app/src/main/assets/
app/src/main/assets/game.love
+3
View File
@@ -0,0 +1,3 @@
[submodule "love/src/jni/love"]
path = love/src/jni/love
url = https://github.com/love2d/love
-53
View File
@@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>love_android_sdl2</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/[Löve] Generate Internal Scripts.launch</value>
</dictionary>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/ndk-build.launch</value>
</dictionary>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
-68
View File
@@ -1,68 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="org.love2d.android"
android:versionCode="10"
android:versionName="0.9.0-beta1"
android:installLocation="auto" xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- Allow writing to external storage -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="LÖVE for Android"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
<service android:name=".DownloadService" />
<activity
android:name="GameActivity"
android:configChanges="orientation|screenSize"
android:label="LÖVE for Android"
android:screenOrientation="landscape" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="tv.ouya.intent.category.GAME"/>
</intent-filter>
</activity>
<activity
android:name="GameActivity"
android:configChanges="orientation|screenSize"
android:screenOrientation="landscape" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:mimeType="application/x-love-game" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:mimeType="*/*" />
<data android:pathPattern=".*\\.love" />
<data android:host="*" />
</intent-filter>
</activity>
<activity
android:name="DownloadActivity"
android:noHistory="true" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="*" />
<data android:pathPattern=".*\\.love" />
</intent-filter>
</activity>
</application>
<!-- Android 2.3.3 -->
<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="18" />
<!-- OpenGL ES 2.0 -->
<uses-feature android:glEsVersion="0x00020000" />
</manifest>
+169 -19
View File
@@ -1,37 +1,191 @@
Android Port of LÖVE, the awesome 2D game engine LÖVE (http://love2d.org)
Copyright (c) 2013-2014 Martin Felis <martin@fysx.org>
Android Port of LÖVE, an awesome 2D game engine for Lua (http://love2d.org)
Copyright (c) 2006-2023 LOVE Development Team
![Build Status](https://github.com/love2d/love-android/workflows/build/badge.svg)
Download:
---------
You can download pre-built Android packages from https://github.com/love2d/love/releases/latest that allow
you to run .love files by opening them using a file manager of your choice.
Important:
----------
If you want to build from source, make sure to clone the submodules too. Often errors include missing
liblove.so and "Missing LÖVE" error when building. A proper way to clone this repository is:
```
git clone --recurse-submodules https://github.com/love2d/love-android
```
Add `-b <branch/tag name>` and `--depth 1` if needed.
If you already cloned the repository but forgot to initialize the submodules, execute:
```
git submodule sync --recursive
git submodule update --init --force --recursive
```
In the repository directory. For the last command, add `--depth 1` if needed.
Instructions:
-------------
For detailed instructions please refer to the [wiki](wiki).
Detailed instructions can be viewed at https://github.com/love2d/love-android/wiki
Quick Start:
------------
Install the Android NDK and the Android SDK with SDK API 12 and run
Before you start, install JDK 17 (not later not earlier). If you intend to build from Android Studio, skip this step as
Android Studio bundles its own JDK 17.
ndk-build
Install Android SDK with SDK API 34 (34.x.y) and Android NDK 25.2.9519653, set the environment variable
`ANDROID_SDK_ROOT` to your Android SDK location and run:
and after that
```
$ ./gradlew assembleNormalRecord
```
ant debug
in the root folder of this project. This should give you an .apk file in the `app/build/outputs/apk/normalRecord`
subdirectory that you can then sign and install on your phone. The `normalRecord` .apk variant is what you normally have
when downloading APK from https://love2d.org.
in the root folder of this project or load the project using Eclipse and
compile/run it using Eclipse.
If you want to put your game inside the APK, you can either:
This should give you a .apk file in the bin/ subdirectory that you can then
install on your phone.
1. Put all your games in `app/src/embed/assets` such that your `main.lua` path is `app/src/embed/assets/main.lua`; or
2. Put your zipped \*.love in `app/src/embed/assets` with name `game.love`
And change the application id, application version string and codes, application display name, and the icons (see
[Game Packaging Wiki](https://github.com/love2d/love-android/wiki/Game-Packaging). Afterwards,
run either `gradlew assembleEmbedNoRecordRelease` (or `gradlew assembleEmbedRecordRelease` if your game uses microphone) to
generate APK which you can install or `gradlew bundleEmbedNoRecordRelease` (or `gradlew bundleEmbedRecordRelease`) to generate
AAB which you can upload to Play Store.
Alternatively, you can install Android Studio **2022.3.1** or later. After opening it for the first time, open its SDK Manager
and on the tab "SDK Tools", tick "Show Package Details" then select NDK (Side By Side) version 25.2.9519653. After that, open
the repository root.
Notice: Previously, the embed + APKTool method is preferred, but recent announcements by Google render that method obsolete.
Bugs:
-----
Bugs and feature requests should be reported to the [issue
tracker](issues).
Bugs and/or feature requests should be reported to the issue tracker at:
* https://github.com/love2d/love-android/issues - LÖVE-Android-specific issues
* https://github.com/love2d/love/issues - for LÖVE in general
Note: If in doubt, fill an issue report to https://github.com/love2d/love/issues. We'll transfer the issue to this repository as needed.
Changelog:
----------
11.5:
* Contains all relevant changes for desktop LÖVE [11.5](https://love2d.org/wiki/11.5).
* Fixed audio in Android still playing in the background in certain cases. ([love2d/love#1828](https://github.com/love2d/love/issues/1828))
11.4:
* Contains all relevant changes for desktop LÖVE [11.4](https://love2d.org/wiki/11.4).
* Changed how LOVE looks for game due to Android restrictions.
* Fixed "pointer too large" and "bad lightuserdata" issue when compiling LOVE with recent Android SDK and running LOVE on Android 11 and later.
* For Developers: Added experimental support for 3rd-party Lua modules. Please refer to `love/src/jni/lua-modules` for more information.
* For Packaging: Added experimental fusing method. [See the FAQ for details](https://github.com/love2d/love-android/wiki/FAQ---Frequently-Asked-Questions#whats-experimental-fusing-method).
11.3:
* Contains all relevant changes for desktop LÖVE [11.3](https://love2d.org/wiki/11.3).
* Added support for microphone recording on Android. **This is disabled in Play Store builds**.
* Added t.audio.mic (`false` by default). On Android, setting it to true requests microphone recording permission from the user.
* Fixed performance regression on Android devices with Adreno GPU.
* Fixed video playback support on Android devices with Adreno GPU.
11.2:
* Contains all relevant changes for desktop LÖVE [11.2](https://love2d.org/wiki/11.2).
* Added support for ARM64 devices to comply with Play Store requirements.
* Fixed `love.system.openURL` crashing in some cases.
* Changed target SDK to 28 so it comply with Play Store requirements.
0.10.2:
* Contains all relevant changes for desktop LÖVE [0.10.2](https://love2d.org/wiki/0.10.2).
* Upgrade of SDL2 to 2.0.5 (fixes an issue with the accelerometer)
0.10.1:
* Contains all relevant changes for desktop LÖVE [0.10.1](https://love2d.org/wiki/0.10.1).
* Added a new love.conf flag t.externalstorage, which determines whether files are saved in internal or external storage on Android devices.
* Fixed audio on Android to pause when the app is inactive, and resume when the app becomes active again.
* Fixed a driver bug on some Android devices which caused all objects to show up as black.
* Fixed love.graphics.clear(colortable) causing crashes on OpenGL ES 2 systems when a Canvas is active.
* New icons
0.10.0:
* first official release!
* Disabled JIT by default as it can cause performance problems. To enable JIT call jit.on()
0.10.0-alpha2:
* Update to the next love API 0.10.0 (not yet officially released)
* Added building of libtheora
* Updated LuaJIT from 2.0.1 to 2.1
* Fixed a compatibility issue with Android 2.3 devices
* Updated libogg from 1.3.2. to 1.3.5
* Updated OpenAL to 1.17.0
* Updated SDL2 to a dev version of 2.0.4
0.9.2a:
* Added bugfix for ParticleSystem:clone
0.9.2:
* updated API to match that of LÖVE 0.9.2
* love.window.setFullscreen can be used to switch between regular and immersive mode without status and navbar
* added loading of games by opening a main.lua file
* quitting LÖVE now conforms to the Android application lifecycle
* stop vibrator when app is paused
* fixed battery drain by properly pausing OpenAL device
* fixed printing of non-number and non-string values
* fixed compilation of Android NDK r10
* fixed compilation warnings concerning ```APP_PLATFORM```
* old instance is shut down when opening a new game (note: it may crash when opening games at a high frequency, e.g. more than 2 per second)
* updated OpenAL-Soft to version 1.16.0
* updated to newer SDL version (f9244b2a151)
0.9.1b:
* added love.system.vibrate(seconds)
* print statements are now redirected to logcat. Output is prefixed with "[LOVE] "
* removed DevIL, libpng, libjpeg, libmng, and libtiff
* pngs are loaded using lodepng and jpegs using libturbo-jpeg
* repeatedly fixed a bug which caused Release builds to crash
* update to latest mobile-common branch
0.9.1a:
* using latest SDL\_androidgl.c (fixes some random performance issues)
* using latest love-android @ changeset 8659be0e75a3 (adds support for
compressed textures)
0.9.1:
* uses 0.9.1 API
* fixed crash on Moto G (and possibly other devices). This was a nasty bug that would just show a blue screen without an error message. The bug was resolved using the help of headchant
* fixed loading of jpegs (it probably hasn't worked up to now)
* fixed issues with looping over active touches. This fix was sponsored by slime!
beta2:
* fixed bug with canvases
* fixed writing of files when no identity in conf.lua was set
* added file association (somewhat experimental)
beta1:
* fixed nasty crash on startup bug
@@ -70,9 +224,5 @@ alpha7:
License:
--------
This project contains code from multiple projects using various licenses.
Please look into the folders of jni/<projectname>/ for the respective
licenses.
As for the other code and build system files, these are published under the
zlib license (same as LÖVE).
This project contains code from multiple projects using various licenses. Please look at LOVE
[license.txt](https://github.com/love2d/love/blob/master/license.txt) for the respective licenses.
+72
View File
@@ -0,0 +1,72 @@
import java.nio.charset.StandardCharsets
apply plugin: 'com.android.application'
android {
namespace "org.love2d.android.executable"
ndkVersion '25.2.9519653'
defaultConfig {
applicationId project.properties["app.application_id"]
versionCode project.properties["app.version_code"].toInteger()
versionName project.properties["app.version_name"]
minSdk 16
compileSdk 34
targetSdk 34
def getAppName = {
def nameArray = project.properties["app.name_byte_array"]
def name = project.properties["app.name"]
if (name != null && nameArray != null) {
throw new Exception("Only define either `app.name` or `app.name_byte_array` in gradle.properties, but not both!")
}
if (name == null) {
def nameArraySplit = nameArray.split(",")
def nameBytes = new byte[nameArraySplit.length]
def count = 0
for (String s: nameArraySplit) {
nameBytes[count++] = (byte) Integer.parseInt(s)
}
return new String(nameBytes, StandardCharsets.UTF_8)
}
return name
}
manifestPlaceholders = [
NAME:getAppName(),
ORIENTATION:project.properties["app.orientation"],
]
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
flavorDimensions = ['mode', 'recording']
productFlavors {
normal {
dimension 'mode'
}
embed {
dimension 'mode'
}
record {
dimension 'recording'
}
noRecord {
dimension 'recording'
}
}
lint {
abortOnError false
}
}
dependencies {
api 'androidx.multidex:multidex:2.0.1'
api fileTree(dir: 'libs', include: ['*.jar'])
api 'androidx.appcompat:appcompat:1.6.1'
api project(':love')
}
+20
View File
@@ -0,0 +1,20 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/diglet/android-sdk-macosx/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-keep class org.love2d.android.GameActivity { *; }
-keep class org.libsdl.app.** { *; }
+4
View File
@@ -0,0 +1,4 @@
Add your game.love in this folder then
$ ./gradlew bundleEmbed
or
$ ./gradlew assembleEmbed
+47
View File
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" />
<!-- OpenGL ES 2.0 -->
<uses-feature android:glEsVersion="0x00020000" />
<!-- Touchscreen support -->
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<!-- Game controller support -->
<uses-feature android:name="android.hardware.bluetooth" android:required="false" />
<uses-feature android:name="android.hardware.gamepad" android:required="false" />
<uses-feature android:name="android.hardware.usb.host" android:required="false" />
<!-- External mouse input events -->
<uses-feature android:name="android.hardware.type.pc" android:required="false" />
<!-- Low latency audio -->
<uses-feature android:name="android.hardware.audio.low_latency" android:required="false" />
<uses-feature android:name="android.hardware.audio.pro" android:required="false" />
<application
android:allowBackup="true"
android:icon="@drawable/love"
android:label="${NAME}"
android:usesCleartextTraffic="true" >
<activity
android:name="org.love2d.android.GameActivity"
android:exported="true"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden|navigation"
android:label="${NAME}"
android:launchMode="singleInstance"
android:screenOrientation="${ORIENTATION}"
android:resizeableActivity="false"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="tv.ouya.intent.category.GAME" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
</activity>
</application>
</manifest>
+5
View File
@@ -0,0 +1,5 @@
values/generated_strings.xml
values/generated_integers.xml
drawable-*/icon.png
drawable-*/notificationicon.png
mipmap-*/ic_launcher.png
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>
+11
View File
@@ -0,0 +1,11 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
>
<uses-permission android:name="android.permission.RECORD_AUDIO" tools:node="remove" />
</manifest>
+68
View File
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" >
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" tools:replace="maxSdkVersion" />
<application tools:node="merge">
<service android:name="org.love2d.android.DownloadService" />
<activity
android:name="org.love2d.android.GameActivity"
tools:node="merge" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:mimeType="*/*" />
<data android:pathPattern=".*\\.love" />
<data android:host="*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="content" />
<data android:mimeType="application/x-love-game" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="content" />
<data android:mimeType="application/octet-stream" />
</intent-filter>
</activity>
<activity
android:name="org.love2d.android.DownloadActivity"
android:exported="true"
android:noHistory="true"
android:theme="@android:style/Theme.NoTitleBar" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http"
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.love" />
<data android:scheme="https"
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.love" />
</intent-filter>
</activity>
<activity
android:name="org.love2d.android.SelectorActivity"
android:label="LÖVE Loader"
android:exported="true"
android:enabled="@bool/selector_active"
android:theme="@style/Theme.AppCompat.NoActionBar" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="tv.ouya.intent.category.GAME" />
</intent-filter>
</activity>
</application>
</manifest>
+35
View File
@@ -0,0 +1,35 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
allprojects {
repositories {
google()
mavenCentral()
}
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xlint:deprecation"
}
}
}
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.1.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
repositories {
google()
mavenCentral()
}
-93
View File
@@ -1,93 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This should be changed to the name of your project -->
<project name="love_android_sdl2" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="ant.properties" />
<!-- if sdk.dir was not set from one of the property file, then
get it from the ANDROID_HOME env var.
This must be done before we load project.properties since
the proguard config can use sdk.dir -->
<property environment="env" />
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
<isset property="env.ANDROID_HOME" />
</condition>
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
unless="sdk.dir"
/>
<!--
Import per project custom build rules if present at the root of the project.
This is the place to put custom intermediary targets such as:
-pre-build
-pre-compile
-post-compile (This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir})
-post-package
-post-build
-pre-clean
-->
<import file="custom_rules.xml" optional="true" />
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: 1 -->
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>
+19
View File
@@ -0,0 +1,19 @@
# To set the application display name, only define either `app.name` or `app.name_byte_array`.
# For a rule of thumb:
# * Use `app.name` if your app name doesn't contain any non-ANSI characters.
# * Otherwise, convert your app name to UTF-8 byte array, comma delimited, and put
# it in `app.name_byte_array`
#app.name=LÖVE for Android
app.name_byte_array=76,195,150,86,69,32,102,111,114,32,65,110,100,114,111,105,100
app.application_id=org.love2d.android
app.orientation=landscape
app.version_code=32
app.version_name=11.5a
# No need to modify anything past this line!
android.enableJetifier=false
android.useAndroidX=true
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=true
android.nonFinalResIds=true
Binary file not shown.
+6
View File
@@ -0,0 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored Executable
+244
View File
@@ -0,0 +1,244 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
Vendored
+92
View File
@@ -0,0 +1,92 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
-9
View File
@@ -1,9 +0,0 @@
# Uncomment this if you're using STL in your project
# See CPLUSPLUS-SUPPORT.html in the NDK documentation for more information
# APP_STL := stlport_static
APP_STL := gnustl_shared
APP_ABI := armeabi armeabi-v7a
APP_CPPFLAGS := -frtti
APP_LDFLAGS := -llog -landroid -lz
# APP_OPTIM := debug
-8
View File
@@ -1,8 +0,0 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libluajit
LOCAL_SRC_FILES := android/$(TARGET_ARCH_ABI)/libluajit.a
include $(PREBUILT_STATIC_LIBRARY)
-56
View File
@@ -1,56 +0,0 @@
===============================================================================
LuaJIT -- a Just-In-Time Compiler for Lua. http://luajit.org/
Copyright (C) 2005-2013 Mike Pall. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
[ MIT license: http://www.opensource.org/licenses/mit-license.php ]
===============================================================================
[ LuaJIT includes code from Lua 5.1/5.2, which has this license statement: ]
Copyright (C) 1994-2012 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
===============================================================================
[ LuaJIT includes code from dlmalloc, which has this license statement: ]
This is a version (aka dlmalloc) of malloc/free/realloc written by
Doug Lea and released to the public domain, as explained at
http://creativecommons.org/licenses/publicdomain
===============================================================================
-149
View File
@@ -1,149 +0,0 @@
##############################################################################
# LuaJIT top level Makefile for installation. Requires GNU Make.
#
# Please read doc/install.html before changing any variables!
#
# Suitable for POSIX platforms (Linux, *BSD, OSX etc.).
# Note: src/Makefile has many more configurable options.
#
# ##### This Makefile is NOT useful for Windows! #####
# For MSVC, please follow the instructions given in src/msvcbuild.bat.
# For MinGW and Cygwin, cd to src and run make with the Makefile there.
#
# Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
##############################################################################
MAJVER= 2
MINVER= 0
RELVER= 1
VERSION= $(MAJVER).$(MINVER).$(RELVER)
ABIVER= 5.1
##############################################################################
#
# Change the installation path as needed. This automatically adjusts
# the paths in src/luaconf.h, too. Note: PREFIX must be an absolute path!
#
export PREFIX= /usr/local
##############################################################################
DPREFIX= $(DESTDIR)$(PREFIX)
INSTALL_BIN= $(DPREFIX)/bin
INSTALL_LIB= $(DPREFIX)/lib
INSTALL_SHARE= $(DPREFIX)/share
INSTALL_INC= $(DPREFIX)/include/luajit-$(MAJVER).$(MINVER)
INSTALL_LJLIBD= $(INSTALL_SHARE)/luajit-$(VERSION)
INSTALL_JITLIB= $(INSTALL_LJLIBD)/jit
INSTALL_LMODD= $(INSTALL_SHARE)/lua
INSTALL_LMOD= $(INSTALL_LMODD)/$(ABIVER)
INSTALL_CMODD= $(INSTALL_LIB)/lua
INSTALL_CMOD= $(INSTALL_CMODD)/$(ABIVER)
INSTALL_MAN= $(INSTALL_SHARE)/man/man1
INSTALL_PKGCONFIG= $(INSTALL_LIB)/pkgconfig
INSTALL_TNAME= luajit-$(VERSION)
INSTALL_TSYMNAME= luajit
INSTALL_ANAME= libluajit-$(ABIVER).a
INSTALL_SONAME= libluajit-$(ABIVER).so.$(MAJVER).$(MINVER).$(RELVER)
INSTALL_SOSHORT= libluajit-$(ABIVER).so
INSTALL_DYLIBNAME= libluajit-$(ABIVER).$(MAJVER).$(MINVER).$(RELVER).dylib
INSTALL_DYLIBSHORT1= libluajit-$(ABIVER).dylib
INSTALL_DYLIBSHORT2= libluajit-$(ABIVER).$(MAJVER).dylib
INSTALL_PCNAME= luajit.pc
INSTALL_STATIC= $(INSTALL_LIB)/$(INSTALL_ANAME)
INSTALL_DYN= $(INSTALL_LIB)/$(INSTALL_SONAME)
INSTALL_SHORT1= $(INSTALL_LIB)/$(INSTALL_SOSHORT)
INSTALL_SHORT2= $(INSTALL_LIB)/$(INSTALL_SOSHORT)
INSTALL_T= $(INSTALL_BIN)/$(INSTALL_TNAME)
INSTALL_TSYM= $(INSTALL_BIN)/$(INSTALL_TSYMNAME)
INSTALL_PC= $(INSTALL_PKGCONFIG)/$(INSTALL_PCNAME)
INSTALL_DIRS= $(INSTALL_BIN) $(INSTALL_LIB) $(INSTALL_INC) $(INSTALL_MAN) \
$(INSTALL_PKGCONFIG) $(INSTALL_JITLIB) $(INSTALL_LMOD) $(INSTALL_CMOD)
UNINSTALL_DIRS= $(INSTALL_JITLIB) $(INSTALL_LJLIBD) $(INSTALL_INC) \
$(INSTALL_LMOD) $(INSTALL_LMODD) $(INSTALL_CMOD) $(INSTALL_CMODD)
RM= rm -f
MKDIR= mkdir -p
RMDIR= rmdir 2>/dev/null
SYMLINK= ln -sf
INSTALL_X= install -m 0755
INSTALL_F= install -m 0644
UNINSTALL= $(RM)
LDCONFIG= ldconfig -n
SED_PC= sed -e "s|^prefix=.*|prefix=$(PREFIX)|"
FILE_T= luajit
FILE_A= libluajit.a
FILE_SO= libluajit.so
FILE_MAN= luajit.1
FILE_PC= luajit.pc
FILES_INC= lua.h lualib.h lauxlib.h luaconf.h lua.hpp luajit.h
FILES_JITLIB= bc.lua v.lua dump.lua dis_x86.lua dis_x64.lua dis_arm.lua \
dis_ppc.lua dis_mips.lua dis_mipsel.lua bcsave.lua vmdef.lua
ifeq (,$(findstring Windows,$(OS)))
ifeq (Darwin,$(shell uname -s))
INSTALL_SONAME= $(INSTALL_DYLIBNAME)
INSTALL_SHORT1= $(INSTALL_LIB)/$(INSTALL_DYLIBSHORT1)
INSTALL_SHORT2= $(INSTALL_LIB)/$(INSTALL_DYLIBSHORT2)
LDCONFIG= :
endif
endif
##############################################################################
INSTALL_DEP= src/luajit
default all $(INSTALL_DEP):
@echo "==== Building LuaJIT $(VERSION) ===="
$(MAKE) -C src
@echo "==== Successfully built LuaJIT $(VERSION) ===="
install: $(INSTALL_DEP)
@echo "==== Installing LuaJIT $(VERSION) to $(PREFIX) ===="
$(MKDIR) $(INSTALL_DIRS)
cd src && $(INSTALL_X) $(FILE_T) $(INSTALL_T)
cd src && test -f $(FILE_A) && $(INSTALL_F) $(FILE_A) $(INSTALL_STATIC) || :
$(RM) $(INSTALL_TSYM) $(INSTALL_DYN) $(INSTALL_SHORT1) $(INSTALL_SHORT2)
cd src && test -f $(FILE_SO) && \
$(INSTALL_X) $(FILE_SO) $(INSTALL_DYN) && \
$(LDCONFIG) $(INSTALL_LIB) && \
$(SYMLINK) $(INSTALL_SONAME) $(INSTALL_SHORT1) && \
$(SYMLINK) $(INSTALL_SONAME) $(INSTALL_SHORT2) || :
cd etc && $(INSTALL_F) $(FILE_MAN) $(INSTALL_MAN)
cd etc && $(SED_PC) $(FILE_PC) > $(FILE_PC).tmp && \
$(INSTALL_F) $(FILE_PC).tmp $(INSTALL_PC) && \
$(RM) $(FILE_PC).tmp
cd src && $(INSTALL_F) $(FILES_INC) $(INSTALL_INC)
cd src/jit && $(INSTALL_F) $(FILES_JITLIB) $(INSTALL_JITLIB)
$(SYMLINK) $(INSTALL_TNAME) $(INSTALL_TSYM)
@echo "==== Successfully installed LuaJIT $(VERSION) to $(PREFIX) ===="
uninstall:
@echo "==== Uninstalling LuaJIT $(VERSION) from $(PREFIX) ===="
$(UNINSTALL) $(INSTALL_TSYM) $(INSTALL_T) $(INSTALL_STATIC) $(INSTALL_DYN) $(INSTALL_SHORT1) $(INSTALL_SHORT2) $(INSTALL_MAN)/$(FILE_MAN) $(INSTALL_PC)
for file in $(FILES_JITLIB); do \
$(UNINSTALL) $(INSTALL_JITLIB)/$$file; \
done
for file in $(FILES_INC); do \
$(UNINSTALL) $(INSTALL_INC)/$$file; \
done
$(LDCONFIG) $(INSTALL_LIB)
$(RMDIR) $(UNINSTALL_DIRS) || :
@echo "==== Successfully uninstalled LuaJIT $(VERSION) from $(PREFIX) ===="
##############################################################################
amalg:
@echo "Building LuaJIT $(VERSION)"
$(MAKE) -C src amalg
clean:
$(MAKE) -C src clean
.PHONY: all install amalg clean
##############################################################################
-16
View File
@@ -1,16 +0,0 @@
README for LuaJIT 2.0.1
-----------------------
LuaJIT is a Just-In-Time (JIT) compiler for the Lua programming language.
Project Homepage: http://luajit.org/
LuaJIT is Copyright (C) 2005-2013 Mike Pall.
LuaJIT is free software, released under the MIT license.
See full Copyright Notice in the COPYRIGHT file or in luajit.h.
Documentation for LuaJIT is available in HTML format.
Please point your favorite browser to:
doc/luajit.html
Binary file not shown.
Binary file not shown.
-58
View File
@@ -1,58 +0,0 @@
#!/bin/bash
#================================================================#
# Build script based on
# https://github.com/moai/moai-dev/blob/master/ant/libmoai/jni/luajit/build.sh
#================================================================#
host_os=`uname -s | tr "[:upper:]" "[:lower:]"`
host_arch=`uname -m`
if [ -f android/armeabi/libluajit.a ] &&
[ -f android/armeabi-v7a/libluajit.a ]; then
echo "LuaJIT Already built"
exit 0
fi
NDK_BUILD_LOCATION=${ANDROID_NDK}
if [[ x$NDK_BUILD_LOCATION = "x" ]]; then
echo "The Android NDK must be on your path."
exit 1
fi
NDK="${NDK_BUILD_LOCATION%/ndk-build}"
if [[ x$NDK = "x" ]]; then
echo "The Android NDK must be on your path."
exit 1
fi
NDKABI=8
NDKVER=$NDK/toolchains/arm-linux-androideabi-4.6
NDKP=$NDKVER/prebuilt/${host_os}-${host_arch}/bin/arm-linux-androideabi-
NDKF="--sysroot $NDK/platforms/android-$NDKABI/arch-arm"
CFLAGS=""
buildLuaJIT()
{
arch="$1"
ndkarch="$2"
DESTDIR=../android/$arch
mkdir -p $DESTDIR 2>/dev/null
rm "$DESTDIR"/*.a 2>/dev/null
make clean
make HOST_CC="gcc -m32" CROSS=$NDKP TARGET_SYS=Linux TARGET_FLAGS="$NDKF $ndkarch" TARGET_CFLAGS="$CFLAGS" libluajit.a
if [ -f libluajit.a ]; then
mv libluajit.a $DESTDIR/libluajit.a
fi;
}
cd src
# Android/ARM, armeabi (ARMv5TE soft-float), Android 2.2+ (Froyo)
buildLuaJIT armeabi
# Android/ARM, armeabi-v7a (ARMv7 VFP), Android 4.0+ (ICS)
buildLuaJIT armeabi-v7a "-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -Wl,--fix-cortex-a8"
make clean
-862
View File
@@ -1,862 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>LuaJIT Change History</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Author" content="Mike Pall">
<meta name="Copyright" content="Copyright (C) 2005-2013, Mike Pall">
<meta name="Language" content="en">
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
<style type="text/css">
div.major { max-width: 600px; padding: 1em; margin: 1em 0 1em 0; }
</style>
</head>
<body>
<div id="site">
<a href="http://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
</div>
<div id="head">
<h1>LuaJIT Change History</h1>
</div>
<div id="nav">
<ul><li>
<a href="luajit.html">LuaJIT</a>
<ul><li>
<a href="http://luajit.org/download.html">Download <span class="ext">&raquo;</span></a>
</li><li>
<a href="install.html">Installation</a>
</li><li>
<a href="running.html">Running</a>
</li></ul>
</li><li>
<a href="extensions.html">Extensions</a>
<ul><li>
<a href="ext_ffi.html">FFI Library</a>
<ul><li>
<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
</li><li>
<a href="ext_ffi_api.html">ffi.* API</a>
</li><li>
<a href="ext_ffi_semantics.html">FFI Semantics</a>
</li></ul>
</li><li>
<a href="ext_jit.html">jit.* Library</a>
</li><li>
<a href="ext_c_api.html">Lua/C API</a>
</li></ul>
</li><li>
<a href="status.html">Status</a>
<ul><li>
<a class="current" href="changes.html">Changes</a>
</li></ul>
</li><li>
<a href="faq.html">FAQ</a>
</li><li>
<a href="http://luajit.org/performance.html">Performance <span class="ext">&raquo;</span></a>
</li><li>
<a href="http://wiki.luajit.org/">Wiki <span class="ext">&raquo;</span></a>
</li><li>
<a href="http://luajit.org/list.html">Mailing List <span class="ext">&raquo;</span></a>
</li></ul>
</div>
<div id="main">
<p>
This is a list of changes between the released versions of LuaJIT.<br>
The current <span style="color: #0000c0;">stable version</span> is <strong>LuaJIT&nbsp;2.0.1</strong>.<br>
</p>
<p>
Please check the
<a href="http://luajit.org/changes.html"><span class="ext">&raquo;</span>&nbsp;Online Change History</a>
to see whether newer versions are available.
</p>
<div class="major" style="background: #d0d0ff;">
<h2 id="LuaJIT-2.0.1">LuaJIT 2.0.1 &mdash; 2013-02-19</h2>
<ul>
<li>Don't clear frame for out-of-memory error.</li>
<li>Leave hook when resume catches error thrown from hook.</li>
<li>Add missing GC steps for template table creation.</li>
<li>Fix discharge order of comparisons in Lua parser.</li>
<li>Improve buffer handling for <tt>io.read()</tt>.</li>
<li>OSX: Add support for Mach-O object files to <tt>-b</tt> option.</li>
<li>Fix PS3 port.</li>
<li>Fix/enable Xbox 360 port.</li>
<li>x86/x64: Always mark ref for shift count as non-weak.</li>
<li>x64: Don't fuse implicitly 32-to-64 extended operands.</li>
<li>ARM: Fix armhf call argument handling.</li>
<li>ARM: Fix code generation for integer math.min/math.max.</li>
<li>PPC/e500: Fix <tt>lj_vm_floor()</tt> for Inf/NaN.</li>
<li>FFI: Change priority of table initializer variants for structs.</li>
<li>FFI: Fix code generation for bool call result check on x86/x64.</li>
<li>FFI: Load FFI library on-demand for bytecode with cdata literals.</li>
<li>FFI: Fix handling of qualified transparent structs/unions.</li>
</ul>
<h2 id="LuaJIT-2.0.0">LuaJIT 2.0.0 &mdash; 2012-11-08</h2>
<ul>
<li>Correctness and completeness:
<ul>
<li>Fix Android/x86 build.</li>
<li>Fix recording of equality comparisons with <tt>__eq</tt> metamethods.</li>
<li>Fix detection of immutable upvalues.</li>
<li>Replace error with PANIC for callbacks from JIT-compiled code.</li>
<li>Fix builtin string to number conversion for <tt>INT_MIN</tt>.</li>
<li>Don't create unneeded array part for template tables.</li>
<li>Fix <tt>CONV.num.int</tt> sinking.</li>
<li>Don't propagate implicitly widened number to index metamethods.</li>
<li>ARM: Fix ordered comparisons of number vs. non-number.</li>
<li>FFI: Fix code generation for replay of sunk float fields.</li>
<li>FFI: Fix signedness of bool.</li>
<li>FFI: Fix recording of bool call result check on x86/x64.</li>
<li>FFI: Fix stack-adjustment for <tt>__thiscall</tt> callbacks.</li>
</ul></li>
</ul>
<h2 id="LuaJIT-2.0.0-beta11">LuaJIT 2.0.0-beta11 &mdash; 2012-10-16</h2>
<ul>
<li>New features:
<ul>
<li>Use ARM VFP instructions, if available (build-time detection).</li>
<li>Add support for ARM hard-float EABI (<tt>armhf</tt>).</li>
<li>Add PS3 port.</li>
<li>Add many features from Lua&nbsp;5.2, e.g. <tt>goto</tt>/labels.
Refer to <a href="extensions.html#lua52">this list</a>.</li>
<li>FFI: Add parameterized C types.</li>
<li>FFI: Add support for copy constructors.</li>
<li>FFI: Equality comparisons never raise an error (treat as unequal instead).</li>
<li>FFI: Box all accessed or returned enums.</li>
<li>FFI: Check for <tt>__new</tt> metamethod when calling a constructor.</li>
<li>FFI: Handle <tt>__pairs</tt>/<tt>__ipairs</tt> metamethods for cdata objects.</li>
<li>FFI: Convert <tt>io.*</tt> file handle to <tt>FILE *</tt> pointer (but as a <tt>void *</tt>).</li>
<li>FFI: Detect and support type punning through unions.</li>
<li>FFI: Improve various error messages.</li>
</ul></li>
<li>Build-system reorganization:
<ul>
<li>Reorganize directory layout:<br>
<tt>lib/*</tt> &rarr; <tt>src/jit/*</tt><br>
<tt>src/buildvm_*.dasc</tt> &rarr; <tt>src/vm_*.dasc</tt><br>
<tt>src/buildvm_*.h</tt> &rarr; removed<br>
<tt>src/buildvm*</tt> &rarr; <tt>src/host/*</tt></li>
<li>Add minified Lua interpreter plus Lua BitOp (<tt>minilua</tt>) to run DynASM.</li>
<li>Change DynASM bit operations to use Lua BitOp</li>
<li>Translate only <tt>vm_*.dasc</tt> for detected target architecture.</li>
<li>Improve target detection for <tt>msvcbuild.bat</tt>.</li>
<li>Fix build issues on Cygwin and MinGW with optional MSys.</li>
<li>Handle cross-compiles with FPU/no-FPU or hard-fp/soft-fp ABI mismatch.</li>
<li>Remove some library functions for no-JIT/no-FFI builds.</li>
<li>Add uninstall target to top-level Makefile.</li>
</ul></li>
<li>Correctness and completeness:
<ul>
<li>Preserve snapshot #0 PC for all traces.</li>
<li>Fix argument checks for <tt>coroutine.create()</tt>.</li>
<li>Command line prints version and JIT status to <tt>stdout</tt>, not <tt>stderr</tt>.</li>
<li>Fix userdata <tt>__gc</tt> separations at Lua state close.</li>
<li>Fix <tt>TDUP</tt> to <tt>HLOAD</tt> forwarding for <tt>LJ_DUALNUM</tt> builds.</li>
<li>Fix buffer check in bytecode writer.</li>
<li>Make <tt>os.date()</tt> thread-safe.</li>
<li>Add missing declarations for MSVC intrinsics.</li>
<li>Fix dispatch table modifications for return hooks.</li>
<li>Workaround for MSVC conversion bug (<tt>double</tt> &rarr; <tt>uint32_t</tt> &rarr; <tt>int32_t</tt>).</li>
<li>Fix FOLD rule <tt>(i-j)-i => 0-j</tt>.</li>
<li>Never use DWARF unwinder on Windows.</li>
<li>Fix shrinking of direct mapped blocks in builtin allocator.</li>
<li>Limit recursion depth in <tt>string.match()</tt> et al.</li>
<li>Fix late despecialization of <tt>ITERN</tt> after loop has been entered.</li>
<li>Fix <tt>'f'</tt> and <tt>'L'</tt> options for <tt>debug.getinfo()</tt> and <tt>lua_getinfo()</tt>.</li>
<li>Fix <tt>package.searchpath()</tt>.</li>
<li>OSX: Change dylib names to be consistent with other platforms.</li>
<li>Android: Workaround for broken <tt>sprintf("%g",&nbsp;-0.0)</tt>.</li>
<li>x86: Remove support for ancient CPUs without <tt>CMOV</tt> (before Pentium Pro).</li>
<li>x86: Fix register allocation for calls returning register pair.</li>
<li>x86/x64: Fix fusion of unsigned byte comparisons with swapped operands.</li>
<li>ARM: Fix <tt>tonumber()</tt> argument check.</li>
<li>ARM: Fix modulo operator and <tt>math.floor()</tt>/<tt>math.ceil()</tt> for <tt>inf</tt>/<tt>nan</tt>.</li>
<li>ARM: Invoke SPLIT pass for leftover <tt>IR_TOBIT</tt>.</li>
<li>ARM: Fix BASE register coalescing.</li>
<li>PPC: Fix interpreter state setup in callbacks.</li>
<li>PPC: Fix <tt>string.sub()</tt> range check.</li>
<li>MIPS: Support generation of MIPS/MIPSEL bytecode object files.</li>
<li>MIPS: Fix calls to <tt>floor()</tt>/<tt>ceil()</tt><tt>/trunc()</tt>.</li>
<li>ARM/PPC: Detect more target architecture variants.</li>
<li>ARM/PPC/e500/MIPS: Fix tailcalls from fast functions, esp. <tt>tostring()</tt>.</li>
<li>ARM/PPC/MIPS: Fix rematerialization of FP constants.</li>
<li>FFI: Don't call <tt>FreeLibrary()</tt> on our own EXE/DLL.</li>
<li>FFI: Resolve metamethods for constructors, too.</li>
<li>FFI: Properly disable callbacks on iOS (would require executable memory).</li>
<li>FFI: Fix cdecl string parsing during recording.</li>
<li>FFI: Show address pointed to for <tt>tostring(ref)</tt>, too.</li>
<li>FFI: Fix alignment of C call argument/return structure.</li>
<li>FFI: Initialize all fields of standard types.</li>
<li>FFI: Fix callback handling when new C&nbsp;types are declared in callback.</li>
<li>FFI: Fix recording of constructors for pointers.</li>
<li>FFI: Always resolve metamethods for pointers to structs.</li>
<li>FFI: Correctly propagate alignment when interning nested types.</li>
</ul></li>
<li>Structural and performance enhancements:
<ul>
<li>Add allocation sinking and store sinking optimization.</li>
<li>Constify immutable upvalues.</li>
<li>Add builtin string to integer or FP number conversion. Improves cross-platform consistency and correctness.</li>
<li>Create string hash slots in template tables for non-const values, too. Avoids later table resizes.</li>
<li>Eliminate <tt>HREFK</tt> guard for template table references.</li>
<li>Add various new FOLD rules.</li>
<li>Don't use stack unwinding for <tt>lua_yield()</tt> (slow on x64).</li>
<li>ARM, PPC, MIPS: Improve <tt>XLOAD</tt> operand fusion and register hinting.</li>
<li>PPC, MIPS: Compile <tt>math.sqrt()</tt> to sqrt instruction, if available.</li>
<li>FFI: Fold <tt>KPTR</tt> + constant offset in SPLIT pass.</li>
<li>FFI: Optimize/inline <tt>ffi.copy()</tt> and <tt>ffi.fill()</tt>.</li>
<li>FFI: Compile and optimize array/struct copies.</li>
<li>FFI: Compile <tt>ffi.typeof(cdata|ctype)</tt>, <tt>ffi.sizeof()</tt>, <tt>ffi.alignof()</tt>, <tt>ffi.offsetof()</tt> and <tt>ffi.gc()</tt>.</li>
</ul></li>
</ul>
<h2 id="LuaJIT-2.0.0-beta10">LuaJIT 2.0.0-beta10 &mdash; 2012-05-09</h2>
<ul>
<li>New features:
<ul>
<li>The MIPS of LuaJIT is complete. It requires a CPU conforming to the
MIPS32&nbsp;R1 architecture with hardware FPU. O32 hard-fp ABI,
little-endian or big-endian.</li>
<li>Auto-detect target arch via cross-compiler. No need for
<tt>TARGET=arch</tt> anymore.</li>
<li>Make DynASM compatible with Lua 5.2.</li>
<li>From Lua 5.2: Try <tt>__tostring</tt> metamethod on non-string error
messages..</li>
</ul></li>
<li>Correctness and completeness:
<ul>
<li>Fix parsing of hex literals with exponents.</li>
<li>Fix bytecode dump for certain number constants.</li>
<li>Fix argument type in error message for relative arguments.</li>
<li>Fix argument error handling on Lua stacks without a frame.</li>
<li>Add missing mcode limit check in assembler backend.</li>
<li>Fix compilation on OpenBSD.</li>
<li>Avoid recursive GC steps after GC-triggered trace exit.</li>
<li>Replace <tt>&lt;unwind.h&gt;</tt> definitions with our own.</li>
<li>Fix OSX build issues. Bump minimum required OSX version to 10.4.</li>
<li>Fix discharge order of comparisons in Lua parser.</li>
<li>Ensure running <tt>__gc</tt> of userdata created in <tt>__gc</tt>
at state close.</li>
<li>Limit number of userdata <tt>__gc</tt> separations at state close.</li>
<li>Fix bytecode <tt>JMP</tt> slot range when optimizing
<tt>and</tt>/<tt>or</tt> with constant LHS.</li>
<li>Fix DSE of <tt>USTORE</tt>.</li>
<li>Make <tt>lua_concat()</tt> work from C&nbsp;hook with partial frame.</li>
<li>Add required PHIs for implicit conversions, e.g. via <tt>XREF</tt>
forwarding.</li>
<li>Add more comparison variants to Valgrind suppressions file.</li>
<li>Disable loading bytecode with an extra header (BOM or <tt>#!</tt>).</li>
<li>Fix PHI stack slot syncing.</li>
<li>ARM: Reorder type/value tests to silence Valgrind.</li>
<li>ARM: Fix register allocation for <tt>ldrd</tt>-optimized
<tt>HREFK</tt>.</li>
<li>ARM: Fix conditional branch fixup for <tt>OBAR</tt>.</li>
<li>ARM: Invoke SPLIT pass for <tt>double</tt> args in FFI call.</li>
<li>ARM: Handle all <tt>CALL*</tt> ops with <tt>double</tt> results in
SPLIT pass.</li>
<li>ARM: Fix rejoin of <tt>POW</tt> in SPLIT pass.</li>
<li>ARM: Fix compilation of <tt>math.sinh</tt>, <tt>math.cosh</tt>,
<tt>math.tanh</tt>.</li>
<li>ARM, PPC: Avoid pointless arg clearing in <tt>BC_IFUNCF</tt>.</li>
<li>PPC: Fix resume after yield from hook.</li>
<li>PPC: Fix argument checking for <tt>rawget()</tt>.</li>
<li>PPC: Fix fusion of floating-point <tt>XLOAD</tt>/<tt>XSTORE</tt>.</li>
<li>PPC: Fix <tt>HREFK</tt> code generation for huge tables.</li>
<li>PPC: Use builtin D-Cache/I-Cache sync code.</li>
</ul></li>
<li>FFI library:
<ul>
<li>Ignore empty statements in <tt>ffi.cdef()</tt>.</li>
<li>Ignore number parsing errors while skipping definitions.</li>
<li>Don't touch frame in callbacks with tailcalls to fast functions.</li>
<li>Fix library unloading on POSIX systems.</li>
<li>Finalize cdata before userdata when closing the state.</li>
<li>Change <tt>ffi.load()</tt> library name resolution for Cygwin.</li>
<li>Fix resolving of function name redirects on Windows/x86.</li>
<li>Fix symbol resolving error messages on Windows.</li>
<li>Fix blacklisting of C functions calling callbacks.</li>
<li>Fix result type of pointer difference.</li>
<li>Use correct PC in FFI metamethod error message.</li>
<li>Allow <tt>'typedef _Bool int BOOL;'</tt> for the Windows API.</li>
<li>Don't record test for bool result of call, if ignored.</li>
</ul></li>
</ul>
<h2 id="LuaJIT-2.0.0-beta9">LuaJIT 2.0.0-beta9 &mdash; 2011-12-14</h2>
<ul>
<li>New features:
<ul>
<li>PPC port of LuaJIT is complete. Default is the dual-number port
(usually faster). Single-number port selectable via <tt>src/Makefile</tt>
at build time.</li>
<li>Add FFI callback support.</li>
<li>Extend <tt>-b</tt> to generate <tt>.c</tt>, <tt>.h</tt> or <tt>.obj/.o</tt>
files with embedded bytecode.</li>
<li>Allow loading embedded bytecode with <tt>require()</tt>.</li>
<li>From Lua 5.2: Change to <tt>'\z'</tt> escape. Reject undefined escape
sequences.</li>
</ul></li>
<li>Correctness and completeness:
<ul>
<li>Fix OSX 10.7 build. Fix <tt>install_name</tt> and versioning on OSX.</li>
<li>Fix iOS build.</li>
<li>Install <tt>dis_arm.lua</tt>, too.</li>
<li>Mark installed shared library as executable.</li>
<li>Add debug option to <tt>msvcbuild.bat</tt> and improve error handling.</li>
<li>Fix data-flow analysis for iterators.</li>
<li>Fix forced unwinding triggered by external unwinder.</li>
<li>Record missing <tt>for</tt> loop slot loads (return to lower frame).</li>
<li>Always use ANSI variants of Windows system functions.</li>
<li>Fix GC barrier for multi-result table constructor (<tt>TSETM</tt>).</li>
<li>Fix/add various FOLD rules.</li>
<li>Add potential PHI for number conversions due to type instability.</li>
<li>Do not eliminate PHIs only referenced from other PHIs.</li>
<li>Correctly anchor implicit number to string conversions in Lua/C API.</li>
<li>Fix various stack limit checks.</li>
<li>x64: Use thread-safe exceptions for external unwinding (GCC platforms).</li>
<li>x64: Fix result type of cdata index conversions.</li>
<li>x64: Fix <tt>math.random()</tt> and <tt>bit.bswap()</tt> code generation.</li>
<li>x64: Fix <tt>lightuserdata</tt> comparisons.</li>
<li>x64: Always extend stack-passed arguments to pointer size.</li>
<li>ARM: Many fixes to code generation backend.</li>
<li>PPC/e500: Fix dispatch for binop metamethods.</li>
<li>PPC/e500: Save/restore condition registers when entering/leaving the VM.</li>
<li>PPC/e500: Fix write barrier in stores of strings to upvalues.</li>
</ul></li>
<li>FFI library:
<ul>
<li>Fix C comment parsing.</li>
<li>Fix snapshot optimization for cdata comparisons.</li>
<li>Fix recording of const/enum lookups in namespaces.</li>
<li>Fix call argument and return handling for <tt>I8/U8/I16/U16</tt> types.</li>
<li>Fix unfused loads of float fields.</li>
<li>Fix <tt>ffi.string()</tt> recording.</li>
<li>Save <tt>GetLastError()</tt> around <tt>ffi.load()</tt> and symbol
resolving, too.</li>
<li>Improve ld script detection in <tt>ffi.load()</tt>.</li>
<li>Record loads/stores to external variables in namespaces.</li>
<li>Compile calls to stdcall, fastcall and vararg functions.</li>
<li>Treat function ctypes like pointers in comparisons.</li>
<li>Resolve <tt>__call</tt> metamethod for pointers, too.</li>
<li>Record C function calls with bool return values.</li>
<li>Record <tt>ffi.errno()</tt>.</li>
<li>x86: Fix number to <tt>uint32_t</tt> conversion rounding.</li>
<li>x86: Fix 64 bit arithmetic in assembler backend.</li>
<li>x64: Fix struct-by-value calling conventions.</li>
<li>ARM: Ensure invocation of SPLIT pass for float conversions.</li>
</ul></li>
<li>Structural and performance enhancements:
<ul>
<li>Display trace types with <tt>-jv</tt> and <tt>-jdump</tt>.</li>
<li>Record isolated calls. But prefer recording loops over calls.</li>
<li>Specialize to prototype for non-monomorphic functions. Solves the
trace-explosion problem for closure-heavy programming styles.</li>
<li>Always generate a portable <tt>vmdef.lua</tt>. Easier for distros.</li>
</ul></li>
</ul>
<h2 id="LuaJIT-2.0.0-beta8">LuaJIT 2.0.0-beta8 &mdash; 2011-06-23</h2>
<ul>
<li>New features:
<ul>
<li>Soft-float ARM port of LuaJIT is complete.</li>
<li>Add support for bytecode loading/saving and <tt>-b</tt> command line
option.</li>
<li>From Lua 5.2: <tt>__len</tt> metamethod for tables
(disabled by default).</li>
</ul></li>
<li>Correctness and completeness:
<ul>
<li>ARM: Misc. fixes for interpreter.</li>
<li>x86/x64: Fix <tt>bit.*</tt> argument checking in interpreter.</li>
<li>Catch early out-of-memory in memory allocator initialization.</li>
<li>Fix data-flow analysis for paths leading to an upvalue close.</li>
<li>Fix check for missing arguments in <tt>string.format()</tt>.</li>
<li>Fix Solaris/x86 build (note: not a supported target).</li>
<li>Fix recording of loops with instable directions in side traces.</li>
<li>x86/x64: Fix fusion of comparisons with <tt>u8</tt>/<tt>u16</tt>
<tt>XLOAD</tt>.</li>
<li>x86/x64: Fix register allocation for variable shifts.</li>
</ul></li>
<li>FFI library:
<ul>
<li>Add <tt>ffi.errno()</tt>. Save <tt>errno</tt>/<tt>GetLastError()</tt>
around allocations etc.</li>
<li>Fix <tt>__gc</tt> for VLA/VLS cdata objects.</li>
<li>Fix recording of casts from 32 bit cdata pointers to integers.</li>
<li><tt>tonumber(cdata)</tt> returns <tt>nil</tt> for non-numbers.</li>
<li>Show address pointed to for <tt>tostring(pointer)</tt>.</li>
<li>Print <tt>NULL</tt> pointers as <tt>"cdata&lt;... *&gt;: NULL"</tt>.</li>
<li>Support <tt>__tostring</tt> metamethod for pointers to structs, too.</li>
</ul></li>
<li>Structural and performance enhancements:
<ul>
<li>More tuning for loop unrolling heuristics.</li>
<li>Flatten and compress in-memory debug info (saves ~70%).</li>
</ul></li>
</ul>
<h2 id="LuaJIT-2.0.0-beta7">LuaJIT 2.0.0-beta7 &mdash; 2011-05-05</h2>
<ul>
<li>New features:
<ul>
<li>ARM port of the LuaJIT interpreter is complete.</li>
<li>FFI library: Add <tt>ffi.gc()</tt>, <tt>ffi.metatype()</tt>,
<tt>ffi.istype()</tt>.</li>
<li>FFI library: Resolve ld script redirection in <tt>ffi.load()</tt>.</li>
<li>From Lua 5.2: <tt>package.searchpath()</tt>, <tt>fp:read("*L")</tt>,
<tt>load(string)</tt>.</li>
<li>From Lua 5.2, disabled by default: empty statement,
<tt>table.unpack()</tt>, modified <tt>coroutine.running()</tt>.</li>
</ul></li>
<li>Correctness and completeness:
<ul>
<li>FFI library: numerous fixes.</li>
<li>Fix type mismatches in store-to-load forwarding.</li>
<li>Fix error handling within metamethods.</li>
<li>Fix <tt>table.maxn()</tt>.</li>
<li>Improve accuracy of <tt>x^-k</tt> on x64.</li>
<li>Fix code generation for Intel Atom in x64 mode.</li>
<li>Fix narrowing of POW.</li>
<li>Fix recording of retried fast functions.</li>
<li>Fix code generation for <tt>bit.bnot()</tt> and multiplies.</li>
<li>Fix error location within cpcall frames.</li>
<li>Add workaround for old libgcc unwind bug.</li>
<li>Fix <tt>lua_yield()</tt> and <tt>getmetatable(lightuserdata)</tt> on x64.</li>
<li>Misc. fixes for PPC/e500 interpreter.</li>
<li>Fix stack slot updates for down-recursion.</li>
</ul></li>
<li>Structural and performance enhancements:
<ul>
<li>Add dual-number mode (int/double) for the VM. Enabled for ARM.</li>
<li>Improve narrowing of arithmetic operators and <tt>for</tt> loops.</li>
<li>Tune loop unrolling heuristics and increase trace recorder limits.</li>
<li>Eliminate dead slots in snapshots using bytecode data-flow analysis.</li>
<li>Avoid phantom stores to proxy tables.</li>
<li>Optimize lookups in empty proxy tables.</li>
<li>Improve bytecode optimization of <tt>and</tt>/<tt>or</tt> operators.</li>
</ul></li>
</ul>
<h2 id="LuaJIT-2.0.0-beta6">LuaJIT 2.0.0-beta6 &mdash; 2011-02-11</h2>
<ul>
<li>New features:
<ul>
<li>PowerPC/e500v2 port of the LuaJIT interpreter is complete.</li>
<li>Various minor features from Lua 5.2: Hex escapes in literals,
<tt>'\*'</tt> escape, reversible <tt>string.format("%q",s)</tt>,
<tt>"%g"</tt> pattern, <tt>table.sort</tt> checks callbacks,
<tt>os.exit(status|true|false[,close])</tt>.</li>
<li>Lua 5.2 <tt>__pairs</tt> and <tt>__ipairs</tt> metamethods
(disabled by default).</li>
<li>Initial release of the FFI library.</li>
</ul></li>
<li>Correctness and completeness:
<ul>
<li>Fix <tt>string.format()</tt> for non-finite numbers.</li>
<li>Fix memory leak when compiled to use the built-in allocator.</li>
<li>x86/x64: Fix unnecessary resize in <tt>TSETM</tt> bytecode.</li>
<li>Fix various GC issues with traces and <tt>jit.flush()</tt>.</li>
<li>x64: Fix fusion of indexes for array references.</li>
<li>x86/x64: Fix stack overflow handling for coroutine results.</li>
<li>Enable low-2GB memory allocation on FreeBSD/x64.</li>
<li>Fix <tt>collectgarbage("count")</tt> result if more than 2GB is in use.</li>
<li>Fix parsing of hex floats.</li>
<li>x86/x64: Fix loop branch inversion with trailing
<tt>HREF+NE/EQ</tt>.</li>
<li>Add <tt>jit.os</tt> string.</li>
<li><tt>coroutine.create()</tt> permits running C functions, too.</li>
<li>Fix OSX build to work with newer ld64 versions.</li>
<li>Fix bytecode optimization of <tt>and</tt>/<tt>or</tt> operators.</li>
</ul></li>
<li>Structural and performance enhancements:
<ul>
<li>Emit specialized bytecode for <tt>pairs()</tt>/<tt>next()</tt>.</li>
<li>Improve bytecode coalescing of <tt>nil</tt> constants.</li>
<li>Compile calls to vararg functions.</li>
<li>Compile <tt>select()</tt>.</li>
<li>Improve alias analysis, esp. for loads from allocations.</li>
<li>Tuning of various compiler heuristics.</li>
<li>Refactor and extend IR conversion instructions.</li>
<li>x86/x64: Various backend enhancements related to the FFI.</li>
<li>Add SPLIT pass to split 64 bit IR instructions for 32 bit CPUs.</li>
</ul></li>
</ul>
<h2 id="LuaJIT-2.0.0-beta5">LuaJIT 2.0.0-beta5 &mdash; 2010-08-24</h2>
<ul>
<li>Correctness and completeness:
<ul>
<li>Fix trace exit dispatch to function headers.</li>
<li>Fix Windows and OSX builds with LUAJIT_DISABLE_JIT.</li>
<li>Reorganize and fix placement of generated machine code on x64.</li>
<li>Fix TNEW in x64 interpreter.</li>
<li>Do not eliminate PHIs for values only referenced from side exits.</li>
<li>OS-independent canonicalization of strings for non-finite numbers.</li>
<li>Fix <tt>string.char()</tt> range check on x64.</li>
<li>Fix <tt>tostring()</tt> resolving within <tt>print()</tt>.</li>
<li>Fix error handling for <tt>next()</tt>.</li>
<li>Fix passing of constant arguments to external calls on x64.</li>
<li>Fix interpreter argument check for two-argument SSE math functions.</li>
<li>Fix C frame chain corruption caused by <tt>lua_cpcall()</tt>.</li>
<li>Fix return from <tt>pcall()</tt> within active hook.</li>
</ul></li>
<li>Structural and performance enhancements:
<ul>
<li>Replace on-trace GC frame syncing with interpreter exit.</li>
<li>Improve hash lookup specialization by not removing dead keys during GC.</li>
<li>Turn traces into true GC objects.</li>
<li>Avoid starting a GC cycle immediately after library init.</li>
<li>Add weak guards to improve dead-code elimination.</li>
<li>Speed up string interning.</li>
</ul></li>
</ul>
<h2 id="LuaJIT-2.0.0-beta4">LuaJIT 2.0.0-beta4 &mdash; 2010-03-28</h2>
<ul>
<li>Correctness and completeness:
<ul>
<li>Fix precondition for on-trace creation of table keys.</li>
<li>Fix <tt>{f()}</tt> on x64 when table is resized.</li>
<li>Fix folding of ordered comparisons with same references.</li>
<li>Fix snapshot restores for multi-result bytecodes.</li>
<li>Fix potential hang when recording bytecode with nested closures.</li>
<li>Fix recording of <tt>getmetatable()</tt>, <tt>tonumber()</tt> and bad argument types.</li>
<li>Fix SLOAD fusion across returns to lower frames.</li>
</ul></li>
<li>Structural and performance enhancements:
<ul>
<li>Add array bounds check elimination. <tt>-Oabc</tt> is enabled by default.</li>
<li>More tuning for x64, e.g. smaller table objects.</li>
</ul></li>
</ul>
<h2 id="LuaJIT-2.0.0-beta3">LuaJIT 2.0.0-beta3 &mdash; 2010-03-07</h2>
<ul>
<li>LuaJIT x64 port:
<ul>
<li>Port integrated memory allocator to Linux/x64, Windows/x64 and OSX/x64.</li>
<li>Port interpreter and JIT compiler to x64.</li>
<li>Port DynASM to x64.</li>
<li>Many 32/64 bit cleanups in the VM.</li>
<li>Allow building the interpreter with either x87 or SSE2 arithmetics.</li>
<li>Add external unwinding and C++ exception interop (default on x64).</li>
</ul></li>
<li>Correctness and completeness:
<ul>
<li>Fix constructor bytecode generation for certain conditional values.</li>
<li>Fix some cases of ordered string comparisons.</li>
<li>Fix <tt>lua_tocfunction()</tt>.</li>
<li>Fix cutoff register in JMP bytecode for some conditional expressions.</li>
<li>Fix PHI marking algorithm for references from variant slots.</li>
<li>Fix <tt>package.cpath</tt> for non-default PREFIX.</li>
<li>Fix DWARF2 frame unwind information for interpreter on OSX.</li>
<li>Drive the GC forward on string allocations in the parser.</li>
<li>Implement call/return hooks (zero-cost if disabled).</li>
<li>Implement yield from C hooks.</li>
<li>Disable JIT compiler on older non-SSE2 CPUs instead of aborting.</li>
</ul></li>
<li>Structural and performance enhancements:
<ul>
<li>Compile recursive code (tail-, up- and down-recursion).</li>
<li>Improve heuristics for bytecode penalties and blacklisting.</li>
<li>Split CALL/FUNC recording and clean up fast function call semantics.</li>
<li>Major redesign of internal function call handling.</li>
<li>Improve FOR loop const specialization and integerness checks.</li>
<li>Switch to pre-initialized stacks. Avoid frame-clearing.</li>
<li>Colocation of prototypes and related data: bytecode, constants, debug info.</li>
<li>Cleanup parser and streamline bytecode generation.</li>
<li>Add support for weak IR references to register allocator.</li>
<li>Switch to compressed, extensible snapshots.</li>
<li>Compile returns to frames below the start frame.</li>
<li>Improve alias analysis of upvalues using a disambiguation hash value.</li>
<li>Compile floor/ceil/trunc to SSE2 helper calls or SSE4.1 instructions.</li>
<li>Add generic C call handling to IR and backend.</li>
<li>Improve KNUM fuse vs. load heuristics.</li>
<li>Compile various <tt>io.*()</tt> functions.</li>
<li>Compile <tt>math.sinh()</tt>, <tt>math.cosh()</tt>, <tt>math.tanh()</tt>
and <tt>math.random()</tt>.</li>
</ul></li>
</ul>
<h2 id="LuaJIT-2.0.0-beta2">LuaJIT 2.0.0-beta2 &mdash; 2009-11-09</h2>
<ul>
<li>Reorganize build system. Build static+shared library on POSIX.</li>
<li>Allow C++ exception conversion on all platforms
using a wrapper function.</li>
<li>Automatically catch C++ exceptions and rethrow Lua error
(DWARF2 only).</li>
<li>Check for the correct x87 FPU precision at strategic points.</li>
<li>Always use wrappers for libm functions.</li>
<li>Resurrect metamethod name strings before copying them.</li>
<li>Mark current trace, even if compiler is idle.</li>
<li>Ensure FILE metatable is created only once.</li>
<li>Fix type comparisons when different integer types are involved.</li>
<li>Fix <tt>getmetatable()</tt> recording.</li>
<li>Fix TDUP with dead keys in template table.</li>
<li><tt>jit.flush(tr)</tt> returns status.
Prevent manual flush of a trace that's still linked.</li>
<li>Improve register allocation heuristics for invariant references.</li>
<li>Compile the push/pop variants of <tt>table.insert()</tt> and
<tt>table.remove()</tt>.</li>
<li>Compatibility with MSVC <tt>link&nbsp/debug</tt>.</li>
<li>Fix <tt>lua_iscfunction()</tt>.</li>
<li>Fix <tt>math.random()</tt> when compiled with <tt>-fpic</tt> (OSX).</li>
<li>Fix <tt>table.maxn()</tt>.</li>
<li>Bump <tt>MACOSX_DEPLOYMENT_TARGET</tt> to <tt>10.4</tt></li>
<li><tt>luaL_check*()</tt> and <tt>luaL_opt*()</tt> now support
negative arguments, too.<br>
This matches the behavior of Lua 5.1, but not the specification.</li>
</ul>
<h2 id="LuaJIT-2.0.0-beta1">LuaJIT 2.0.0-beta1 &mdash; 2009-10-31</h2>
<ul>
<li>This is the first public release of LuaJIT 2.0.</li>
<li>The whole VM has been rewritten from the ground up, so there's
no point in listing differences over earlier versions.</li>
</ul>
</div>
<div class="major" style="background: #ffff80;">
<h2 id="LuaJIT-1.1.8">LuaJIT 1.1.8 &mdash; 2012-04-16</h2>
<ul>
<li>Merged with Lua 5.1.5. Also integrated fixes for all
<a href="http://www.lua.org/bugs.html#5.1.5"><span class="ext">&raquo;</span>&nbsp;<span class="ext">&raquo;</span>&nbsp;currently known bugs in Lua 5.1.5</a>.</li>
</ul>
<h2 id="LuaJIT-1.1.7">LuaJIT 1.1.7 &mdash; 2011-05-05</h2>
<ul>
<li>Added fixes for the
<a href="http://www.lua.org/bugs.html#5.1.4"><span class="ext">&raquo;</span>&nbsp;currently known bugs in Lua 5.1.4</a>.</li>
</ul>
<h2 id="LuaJIT-1.1.6">LuaJIT 1.1.6 &mdash; 2010-03-28</h2>
<ul>
<li>Added fixes for the
<a href="http://www.lua.org/bugs.html#5.1.4"><span class="ext">&raquo;</span>&nbsp;currently known bugs in Lua 5.1.4</a>.</li>
<li>Removed wrong GC check in <tt>jit_createstate()</tt>.
Thanks to Tim Mensch.</li>
<li>Fixed bad assertions while compiling <tt>table.insert()</tt> and
<tt>table.remove()</tt>.</li>
</ul>
<h2 id="LuaJIT-1.1.5">LuaJIT 1.1.5 &mdash; 2008-10-25</h2>
<ul>
<li>Merged with Lua 5.1.4. Fixes all
<a href="http://www.lua.org/bugs.html#5.1.3"><span class="ext">&raquo;</span>&nbsp;known bugs in Lua 5.1.3</a>.</li>
</ul>
<h2 id="LuaJIT-1.1.4">LuaJIT 1.1.4 &mdash; 2008-02-05</h2>
<ul>
<li>Merged with Lua 5.1.3. Fixes all
<a href="http://www.lua.org/bugs.html#5.1.2"><span class="ext">&raquo;</span>&nbsp;known bugs in Lua 5.1.2</a>.</li>
<li>Fixed possible (but unlikely) stack corruption while compiling
<tt>k^x</tt> expressions.</li>
<li>Fixed DynASM template for cmpss instruction.</li>
</ul>
<h2 id="LuaJIT-1.1.3">LuaJIT 1.1.3 &mdash; 2007-05-24</h2>
<ul>
<li>Merged with Lua 5.1.2. Fixes all
<a href="http://www.lua.org/bugs.html#5.1.1"><span class="ext">&raquo;</span>&nbsp;known bugs in Lua 5.1.1</a>.</li>
<li>Merged pending Lua 5.1.x fixes: "return -nil" bug, spurious count hook call.</li>
<li>Remove a (sometimes) wrong assertion in <tt>luaJIT_findpc()</tt>.</li>
<li>DynASM now allows labels for displacements and <tt>.aword</tt>.</li>
<li>Fix some compiler warnings for DynASM glue (internal API change).</li>
<li>Correct naming for SSSE3 (temporarily known as SSE4) in DynASM and x86 disassembler.</li>
<li>The loadable debug modules now handle redirection to stdout
(e.g. <tt>-j&nbsp;trace=-</tt>).</li>
</ul>
<h2 id="LuaJIT-1.1.2">LuaJIT 1.1.2 &mdash; 2006-06-24</h2>
<ul>
<li>Fix MSVC inline assembly: use only local variables with
<tt>lua_number2int()</tt>.</li>
<li>Fix "attempt to call a thread value" bug on Mac OS X:
make values of consts used as lightuserdata keys unique
to avoid joining by the compiler/linker.</li>
</ul>
<h2 id="LuaJIT-1.1.1">LuaJIT 1.1.1 &mdash; 2006-06-20</h2>
<ul>
<li>Merged with Lua 5.1.1. Fixes all
<a href="http://www.lua.org/bugs.html#5.1"><span class="ext">&raquo;</span>&nbsp;known bugs in Lua 5.1</a>.</li>
<li>Enforce (dynamic) linker error for EXE/DLL version mismatches.</li>
<li>Minor changes to DynASM: faster pre-processing, smaller encoding
for some immediates.</li>
</ul>
<p>
This release is in sync with Coco 1.1.1 (see the
<a href="http://coco.luajit.org/changes.html"><span class="ext">&raquo;</span>&nbsp;Coco Change History</a>).
</p>
<h2 id="LuaJIT-1.1.0">LuaJIT 1.1.0 &mdash; 2006-03-13</h2>
<ul>
<li>Merged with Lua 5.1 (final).</li>
<li>New JIT call frame setup:
<ul>
<li>The C stack is kept 16 byte aligned (faster).
Mandatory for Mac OS X on Intel, too.</li>
<li>Faster calling conventions for internal C helper functions.</li>
<li>Better instruction scheduling for function prologue, OP_CALL and
OP_RETURN.</li>
</ul></li>
<li>Miscellaneous optimizations:
<ul>
<li>Faster loads of FP constants. Remove narrow-to-wide store-to-load
forwarding stalls.</li>
<li>Use (scalar) SSE2 ops (if the CPU supports it) to speed up slot moves
and FP to integer conversions.</li>
<li>Optimized the two-argument form of <tt>OP_CONCAT</tt> (<tt>a..b</tt>).</li>
<li>Inlined <tt>OP_MOD</tt> (<tt>a%b</tt>).
With better accuracy than the C variant, too.</li>
<li>Inlined <tt>OP_POW</tt> (<tt>a^b</tt>). Unroll <tt>x^k</tt> or
use <tt>k^x = 2^(log2(k)*x)</tt> or call <tt>pow()</tt>.</li>
</ul></li>
<li>Changes in the optimizer:
<ul>
<li>Improved hinting for table keys derived from table values
(<tt>t1[t2[x]]</tt>).</li>
<li>Lookup hinting now works with arbitrary object types and
supports index chains, too.</li>
<li>Generate type hints for arithmetic and comparison operators,
OP_LEN, OP_CONCAT and OP_FORPREP.</li>
<li>Remove several hint definitions in favour of a generic COMBINE hint.</li>
<li>Complete rewrite of <tt>jit.opt_inline</tt> module
(ex <tt>jit.opt_lib</tt>).</li>
</ul></li>
<li>Use adaptive deoptimization:
<ul>
<li>If runtime verification of a contract fails, the affected
instruction is recompiled and patched on-the-fly.
Regular programs will trigger deoptimization only occasionally.</li>
<li>This avoids generating code for uncommon fallback cases
most of the time. Generated code is up to 30% smaller compared to
LuaJIT&nbsp;1.0.3.</li>
<li>Deoptimization is used for many opcodes and contracts:
<ul>
<li>OP_CALL, OP_TAILCALL: type mismatch for callable.</li>
<li>Inlined calls: closure mismatch, parameter number and type mismatches.</li>
<li>OP_GETTABLE, OP_SETTABLE: table or key type and range mismatches.</li>
<li>All arithmetic and comparison operators, OP_LEN, OP_CONCAT,
OP_FORPREP: operand type and range mismatches.</li>
</ul></li>
<li>Complete redesign of the debug and traceback info
(bytecode &harr; mcode) to support deoptimization.
Much more flexible and needs only 50% of the space.</li>
<li>The modules <tt>jit.trace</tt>, <tt>jit.dumphints</tt> and
<tt>jit.dump</tt> handle deoptimization.</li>
</ul></li>
<li>Inlined many popular library functions
(for commonly used arguments only):
<ul>
<li>Most <tt>math.*</tt> functions (the 18 most used ones)
[2x-10x faster].</li>
<li><tt>string.len</tt>, <tt>string.sub</tt> and <tt>string.char</tt>
[2x-10x faster].</li>
<li><tt>table.insert</tt>, <tt>table.remove</tt> and <tt>table.getn</tt>
[3x-5x faster].</li>
<li><tt>coroutine.yield</tt> and <tt>coroutine.resume</tt>
[3x-5x faster].</li>
<li><tt>pairs</tt>, <tt>ipairs</tt> and the corresponding iterators
[8x-15x faster].</li>
</ul></li>
<li>Changes in the core and loadable modules and the stand-alone executable:
<ul>
<li>Added <tt>jit.version</tt>, <tt>jit.version_num</tt>
and <tt>jit.arch</tt>.</li>
<li>Reorganized some internal API functions (<tt>jit.util.*mcode*</tt>).</li>
<li>The <tt>-j dump</tt> output now shows JSUB names, too.</li>
<li>New x86 disassembler module written in pure Lua. No dependency
on ndisasm anymore. Flexible API, very compact (500 lines)
and complete (x87, MMX, SSE, SSE2, SSE3, SSSE3, privileged instructions).</li>
<li><tt>luajit -v</tt> prints the LuaJIT version and copyright
on a separate line.</li>
</ul></li>
<li>Added SSE, SSE2, SSE3 and SSSE3 support to DynASM.</li>
<li>Miscellaneous doc changes. Added a section about
<a href="install.html#embedding">embedding LuaJIT</a>.</li>
</ul>
<p>
This release is in sync with Coco 1.1.0 (see the
<a href="http://coco.luajit.org/changes.html"><span class="ext">&raquo;</span>&nbsp;Coco Change History</a>).
</p>
</div>
<div class="major" style="background: #ffffd0;">
<h2 id="LuaJIT-1.0.3">LuaJIT 1.0.3 &mdash; 2005-09-08</h2>
<ul>
<li>Even more docs.</li>
<li>Unified closure checks in <tt>jit.*</tt>.</li>
<li>Fixed some range checks in <tt>jit.util.*</tt>.</li>
<li>Fixed __newindex call originating from <tt>jit_settable_str()</tt>.</li>
<li>Merged with Lua 5.1 alpha (including early bug fixes).</li>
</ul>
<p>
This is the first public release of LuaJIT.
</p>
<h2 id="LuaJIT-1.0.2">LuaJIT 1.0.2 &mdash; 2005-09-02</h2>
<ul>
<li>Add support for flushing the Valgrind translation cache <br>
(<tt>MYCFLAGS= -DUSE_VALGRIND</tt>).</li>
<li>Add support for freeing executable mcode memory to the <tt>mmap()</tt>-based
variant for POSIX systems.</li>
<li>Reorganized the C&nbsp;function signature handling in
<tt>jit.opt_lib</tt>.</li>
<li>Changed to index-based hints for inlining C&nbsp;functions.
Still no support in the backend for inlining.</li>
<li>Hardcode <tt>HEAP_CREATE_ENABLE_EXECUTE</tt> value if undefined.</li>
<li>Misc. changes to the <tt>jit.*</tt> modules.</li>
<li>Misc. changes to the Makefiles.</li>
<li>Lots of new docs.</li>
<li>Complete doc reorg.</li>
</ul>
<p>
Not released because Lua 5.1 alpha came out today.
</p>
<h2 id="LuaJIT-1.0.1">LuaJIT 1.0.1 &mdash; 2005-08-31</h2>
<ul>
<li>Missing GC step in <tt>OP_CONCAT</tt>.</li>
<li>Fix result handling for C &ndash;> JIT calls.</li>
<li>Detect CPU feature bits.</li>
<li>Encode conditional moves (<tt>fucomip</tt>) only when supported.</li>
<li>Add fallback instructions for FP compares.</li>
<li>Add support for <tt>LUA_COMPAT_VARARG</tt>. Still disabled by default.</li>
<li>MSVC needs a specific place for the <tt>CALLBACK</tt> attribute
(David Burgess).</li>
<li>Misc. doc updates.</li>
</ul>
<p>
Interim non-public release.
Special thanks to Adam D. Moss for reporting most of the bugs.
</p>
<h2 id="LuaJIT-1.0.0">LuaJIT 1.0.0 &mdash; 2005-08-29</h2>
<p>
This is the initial non-public release of LuaJIT.
</p>
</div>
<br class="flush">
</div>
<div id="foot">
<hr class="hide">
Copyright &copy; 2005-2013 Mike Pall
<span class="noprint">
&middot;
<a href="contact.html">Contact</a>
</span>
</div>
</body>
</html>
-102
View File
@@ -1,102 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Contact</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Author" content="Mike Pall">
<meta name="Copyright" content="Copyright (C) 2005-2013, Mike Pall">
<meta name="Language" content="en">
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
</head>
<body>
<div id="site">
<a href="http://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
</div>
<div id="head">
<h1>Contact</h1>
</div>
<div id="nav">
<ul><li>
<a href="luajit.html">LuaJIT</a>
<ul><li>
<a href="http://luajit.org/download.html">Download <span class="ext">&raquo;</span></a>
</li><li>
<a href="install.html">Installation</a>
</li><li>
<a href="running.html">Running</a>
</li></ul>
</li><li>
<a href="extensions.html">Extensions</a>
<ul><li>
<a href="ext_ffi.html">FFI Library</a>
<ul><li>
<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
</li><li>
<a href="ext_ffi_api.html">ffi.* API</a>
</li><li>
<a href="ext_ffi_semantics.html">FFI Semantics</a>
</li></ul>
</li><li>
<a href="ext_jit.html">jit.* Library</a>
</li><li>
<a href="ext_c_api.html">Lua/C API</a>
</li></ul>
</li><li>
<a href="status.html">Status</a>
<ul><li>
<a href="changes.html">Changes</a>
</li></ul>
</li><li>
<a href="faq.html">FAQ</a>
</li><li>
<a href="http://luajit.org/performance.html">Performance <span class="ext">&raquo;</span></a>
</li><li>
<a href="http://wiki.luajit.org/">Wiki <span class="ext">&raquo;</span></a>
</li><li>
<a href="http://luajit.org/list.html">Mailing List <span class="ext">&raquo;</span></a>
</li></ul>
</div>
<div id="main">
<p>
Please send general questions to the
<a href="http://luajit.org/list.html"><span class="ext">&raquo;</span>&nbsp;LuaJIT mailing list</a>.
You can also send any questions you have directly to me:
</p>
<script type="text/javascript">
<!--
var xS="@-:\" .0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ<abc>defghijklmnopqrstuvwxyz";function xD(s)
{var len=s.length;var r="";for(var i=0;i<len;i++)
{var c=s.charAt(i);var n=xS.indexOf(c);if(n!=-1)c=xS.charAt(69-n);r+=c;}
document.write("<"+"p>"+r+"<"+"/p>\n");}
//-->
</script>
<script type="text/javascript">
<!--
xD("fyZKB8xv\"FJytmz8.KAB0u52D")
//--></script>
<noscript>
<p><img src="img/contact.png" alt="Contact info in image" width="170" height="13">
</p>
</noscript>
<h2>Copyright</h2>
<p>
All documentation is
Copyright &copy; 2005-2013 Mike Pall.
</p>
<br class="flush">
</div>
<div id="foot">
<hr class="hide">
Copyright &copy; 2005-2013 Mike Pall
<span class="noprint">
&middot;
<a href="contact.html">Contact</a>
</span>
</div>
</body>
</html>
-407
View File
@@ -1,407 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Extensions</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Author" content="Mike Pall">
<meta name="Copyright" content="Copyright (C) 2005-2013, Mike Pall">
<meta name="Language" content="en">
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
<style type="text/css">
table.exc {
line-height: 1.2;
}
tr.exchead td {
font-weight: bold;
}
td.excplatform {
width: 48%;
}
td.exccompiler {
width: 29%;
}
td.excinterop {
width: 23%;
}
</style>
</head>
<body>
<div id="site">
<a href="http://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
</div>
<div id="head">
<h1>Extensions</h1>
</div>
<div id="nav">
<ul><li>
<a href="luajit.html">LuaJIT</a>
<ul><li>
<a href="http://luajit.org/download.html">Download <span class="ext">&raquo;</span></a>
</li><li>
<a href="install.html">Installation</a>
</li><li>
<a href="running.html">Running</a>
</li></ul>
</li><li>
<a class="current" href="extensions.html">Extensions</a>
<ul><li>
<a href="ext_ffi.html">FFI Library</a>
<ul><li>
<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
</li><li>
<a href="ext_ffi_api.html">ffi.* API</a>
</li><li>
<a href="ext_ffi_semantics.html">FFI Semantics</a>
</li></ul>
</li><li>
<a href="ext_jit.html">jit.* Library</a>
</li><li>
<a href="ext_c_api.html">Lua/C API</a>
</li></ul>
</li><li>
<a href="status.html">Status</a>
<ul><li>
<a href="changes.html">Changes</a>
</li></ul>
</li><li>
<a href="faq.html">FAQ</a>
</li><li>
<a href="http://luajit.org/performance.html">Performance <span class="ext">&raquo;</span></a>
</li><li>
<a href="http://wiki.luajit.org/">Wiki <span class="ext">&raquo;</span></a>
</li><li>
<a href="http://luajit.org/list.html">Mailing List <span class="ext">&raquo;</span></a>
</li></ul>
</div>
<div id="main">
<p>
LuaJIT is fully upwards-compatible with Lua 5.1. It supports all
<a href="http://www.lua.org/manual/5.1/manual.html#5"><span class="ext">&raquo;</span>&nbsp;standard Lua
library functions</a> and the full set of
<a href="http://www.lua.org/manual/5.1/manual.html#3"><span class="ext">&raquo;</span>&nbsp;Lua/C API
functions</a>.
</p>
<p>
LuaJIT is also fully ABI-compatible to Lua 5.1 at the linker/dynamic
loader level. This means you can compile a C&nbsp;module against the
standard Lua headers and load the same shared library from either Lua
or LuaJIT.
</p>
<p>
LuaJIT extends the standard Lua VM with new functionality and adds
several extension modules. Please note this page is only about
<em>functional</em> enhancements and not about performance enhancements,
such as the optimized VM, the faster interpreter or the JIT compiler.
</p>
<h2 id="modules">Extensions Modules</h2>
<p>
LuaJIT comes with several built-in extension modules:
</p>
<h3 id="bit"><tt>bit.*</tt> &mdash; Bitwise operations</h3>
<p>
LuaJIT supports all bitwise operations as defined by
<a href="http://bitop.luajit.org"><span class="ext">&raquo;</span>&nbsp;Lua BitOp</a>:
</p>
<pre class="code">
bit.tobit bit.tohex bit.bnot bit.band bit.bor bit.bxor
bit.lshift bit.rshift bit.arshift bit.rol bit.ror bit.bswap
</pre>
<p>
This module is a LuaJIT built-in &mdash; you don't need to download or
install Lua BitOp. The Lua BitOp site has full documentation for all
<a href="http://bitop.luajit.org/api.html"><span class="ext">&raquo;</span>&nbsp;Lua BitOp API functions</a>.
</p>
<p>
Please make sure to <tt>require</tt> the module before using any of
its functions:
</p>
<pre class="code">
local bit = require("bit")
</pre>
<p>
An already installed Lua BitOp module is ignored by LuaJIT.
This way you can use bit operations from both Lua and LuaJIT on a
shared installation.
</p>
<h3 id="ffi"><tt>ffi.*</tt> &mdash; FFI library</h3>
<p>
The <a href="ext_ffi.html">FFI library</a> allows calling external
C&nbsp;functions and the use of C&nbsp;data structures from pure Lua
code.
</p>
<h3 id="jit"><tt>jit.*</tt> &mdash; JIT compiler control</h3>
<p>
The functions in this module
<a href="ext_jit.html">control the behavior of the JIT compiler engine</a>.
</p>
<h3 id="c_api">C API extensions</h3>
<p>
LuaJIT adds some
<a href="ext_c_api.html">extra functions to the Lua/C API</a>.
</p>
<h2 id="library">Enhanced Standard Library Functions</h2>
<h3 id="xpcall"><tt>xpcall(f, err [,args...])</tt> passes arguments</h3>
<p>
Unlike the standard implementation in Lua 5.1, <tt>xpcall()</tt>
passes any arguments after the error function to the function
which is called in a protected context.
</p>
<h3 id="load"><tt>loadfile()</tt> etc. handle UTF-8 source code</h3>
<p>
Non-ASCII characters are handled transparently by the Lua source code parser.
This allows the use of UTF-8 characters in identifiers and strings.
A UTF-8 BOM is skipped at the start of the source code.
</p>
<h3 id="tostring"><tt>tostring()</tt> etc. canonicalize NaN and &plusmn;Inf</h3>
<p>
All number-to-string conversions consistently convert non-finite numbers
to the same strings on all platforms. NaN results in <tt>"nan"</tt>,
positive infinity results in <tt>"inf"</tt> and negative infinity results
in <tt>"-inf"</tt>.
</p>
<h3 id="tonumber"><tt>tonumber()</tt> etc. use builtin string to number conversion</h3>
<p>
All string-to-number conversions consistently convert integer and
floating-point inputs in decimal and hexadecimal on all platforms.
<tt>strtod()</tt> is <em>not</em> used anymore, which avoids numerous
problems with poor C library implementations. The builtin conversion
function provides full precision according to the IEEE-754 standard, it
works independently of the current locale and it supports hex floating-point
numbers (e.g. <tt>0x1.5p-3</tt>).
</p>
<h3 id="string_dump"><tt>string.dump(f [,strip])</tt> generates portable bytecode</h3>
<p>
An extra argument has been added to <tt>string.dump()</tt>. If set to
<tt>true</tt>, 'stripped' bytecode without debug information is
generated. This speeds up later bytecode loading and reduces memory
usage. See also the
<a href="running.html#opt_b"><tt>-b</tt> command line option</a>.
</p>
<p>
The generated bytecode is portable and can be loaded on any architecture
that LuaJIT supports, independent of word size or endianess. However the
bytecode compatibility versions must match. Bytecode stays compatible
for dot releases (x.y.0 &rarr; x.y.1), but may change with major or
minor releases (2.0 &rarr; 2.1) or between any beta release. Foreign
bytecode (e.g. from Lua 5.1) is incompatible and cannot be loaded.
</p>
<h3 id="math_random">Enhanced PRNG for <tt>math.random()</tt></h3>
<p>
LuaJIT uses a Tausworthe PRNG with period 2^223 to implement
<tt>math.random()</tt> and <tt>math.randomseed()</tt>. The quality of
the PRNG results is much superior compared to the standard Lua
implementation which uses the platform-specific ANSI rand().
</p>
<p>
The PRNG generates the same sequences from the same seeds on all
platforms and makes use of all bits in the seed argument.
<tt>math.random()</tt> without arguments generates 52 pseudo-random bits
for every call. The result is uniformly distributed between 0.0 and 1.0.
It's correctly scaled up and rounded for <tt>math.random(n&nbsp;[,m])</tt> to
preserve uniformity.
</p>
<h3 id="io"><tt>io.*</tt> functions handle 64&nbsp;bit file offsets</h3>
<p>
The file I/O functions in the standard <tt>io.*</tt> library handle
64&nbsp;bit file offsets. In particular this means it's possible
to open files larger than 2&nbsp;Gigabytes and to reposition or obtain
the current file position for offsets beyond 2&nbsp;GB
(<tt>fp:seek()</tt> method).
</p>
<h3 id="debug_meta"><tt>debug.*</tt> functions identify metamethods</h3>
<p>
<tt>debug.getinfo()</tt> and <tt>lua_getinfo()</tt> also return information
about invoked metamethods. The <tt>namewhat</tt> field is set to
<tt>"metamethod"</tt> and the <tt>name</tt> field has the name of
the corresponding metamethod (e.g. <tt>"__index"</tt>).
</p>
<h2 id="resumable">Fully Resumable VM</h2>
<p>
The LuaJIT VM is fully resumable. This means you can yield from a
coroutine even across contexts, where this would not possible with
the standard Lua&nbsp;5.1 VM: e.g. you can yield across <tt>pcall()</tt>
and <tt>xpcall()</tt>, across iterators and across metamethods.
</p>
<h2 id="lua52">Extensions from Lua 5.2</h2>
<p>
LuaJIT supports some language and library extensions from Lua&nbsp;5.2.
Features that are unlikely to break existing code are unconditionally
enabled:
</p>
<ul>
<li><tt>goto</tt> and <tt>::labels::</tt>.</li>
<li>Hex escapes <tt>'\x3F'</tt> and <tt>'\*'</tt> escape in strings.</li>
<li><tt>load(string|reader, chunkname [,mode [,env]])</tt>.
<tt>loadstring()</tt> is an alias.</li>
<li><tt>math.log(x [,base])</tt>.
<li><tt>string.rep(s, n [,sep])</tt>.
<li><tt>string.format()</tt>: <tt>%q</tt> reversible.
<tt>%s</tt> checks <tt>__tostring</tt>.
<tt>%a</tt> and <tt>"%A</tt> added.</li>
<li>String matching pattern <tt>%g</tt> added.</li>
<li><tt>io.read("*L")</tt>.</li>
<li><tt>io.lines()</tt> and <tt>file:lines()</tt> process
<tt>io.read()</tt> options.</li>
<li><tt>os.exit(status|true|false [,close])</tt>.</li>
<li><tt>package.searchpath(name, path [, sep [, rep]])</tt>.</li>
<li><tt>package.loadlib(name, "*")</tt>.</li>
<li><tt>debug.getinfo()</tt> returns <tt>nparams</tt> and <tt>isvararg</tt>
for option <tt>"u"</tt>.</li>
<li><tt>debug.getlocal()</tt> accepts function instead of level.</li>
<li><tt>debug.getlocal()</tt> and <tt>debug.setlocal()</tt> accept negative
indexes for varargs.</li>
<li><tt>debug.getupvalue()</tt> and <tt>debug.setupvalue()</tt> handle
C&nbsp;functions.</li>
<li><tt>debug.upvalueid()</tt> and <tt>debug.upvaluejoin()</tt>.</li>
<li>Command line option <tt>-E</tt>.</li>
<li>Command line checks <tt>__tostring</tt> for errors.</li>
</ul>
<p>
Other features are only enabled, if LuaJIT is built with
<tt>-DLUAJIT_ENABLE_LUA52COMPAT</tt>:
</p>
<ul>
<li><tt>goto</tt> is a keyword and not a valid variable name anymore.</li>
<li><tt>break</tt> can be placed anywhere. Empty statements (<tt>;;</tt>)
are allowed.</li>
<li><tt>__lt</tt>, <tt>__le</tt> are invoked for mixed types.</li>
<li><tt>__len</tt> for tables. <tt>rawlen()</tt> library function.</li>
<li><tt>pairs()</tt> and <tt>ipairs()</tt> check for <tt>__pairs</tt> and
<tt>__ipairs</tt>.</li>
<li><tt>coroutine.running()</tt> returns two results.</li>
<li><tt>table.pack()</tt> and <tt>table.unpack()</tt>
(same as <tt>unpack()</tt>).</li>
<li><tt>io.write()</tt> and <tt>file:write()</tt> return file handle
instead of <tt>true</tt>.</li>
<li><tt>os.execute()</tt> and <tt>pipe:close()</tt> return detailed
exit status.</li>
<li><tt>debug.setmetatable()</tt> returns object.</li>
<li><tt>debug.getuservalue()</tt> and <tt>debug.setuservalue()</tt>.</li>
<li>Remove <tt>math.mod()</tt>, <tt>string.gfind()</tt>.
</ul>
<p>
Note: this provides only partial compatibility with Lua 5.2 at the
language and Lua library level. LuaJIT is API+ABI-compatible with
Lua&nbsp;5.1, which prevents implementing features that would otherwise
break the Lua/C API and ABI (e.g. <tt>_ENV</tt>).
</p>
<h2 id="exceptions">C++ Exception Interoperability</h2>
<p>
LuaJIT has built-in support for interoperating with C++&nbsp;exceptions.
The available range of features depends on the target platform and
the toolchain used to compile LuaJIT:
</p>
<table class="exc">
<tr class="exchead">
<td class="excplatform">Platform</td>
<td class="exccompiler">Compiler</td>
<td class="excinterop">Interoperability</td>
</tr>
<tr class="odd separate">
<td class="excplatform">POSIX/x64, DWARF2 unwinding</td>
<td class="exccompiler">GCC 4.3+</td>
<td class="excinterop"><b style="color: #00a000;">Full</b></td>
</tr>
<tr class="even">
<td class="excplatform">Other platforms, DWARF2 unwinding</td>
<td class="exccompiler">GCC</td>
<td class="excinterop"><b style="color: #c06000;">Limited</b></td>
</tr>
<tr class="odd">
<td class="excplatform">Windows/x64</td>
<td class="exccompiler">MSVC or WinSDK</td>
<td class="excinterop"><b style="color: #00a000;">Full</b></td>
</tr>
<tr class="even">
<td class="excplatform">Windows/x86</td>
<td class="exccompiler">Any</td>
<td class="excinterop"><b style="color: #a00000;">No</b></td>
</tr>
<tr class="odd">
<td class="excplatform">Other platforms</td>
<td class="exccompiler">Other compilers</td>
<td class="excinterop"><b style="color: #a00000;">No</b></td>
</tr>
</table>
<p>
<b style="color: #00a000;">Full interoperability</b> means:
</p>
<ul>
<li>C++&nbsp;exceptions can be caught on the Lua side with <tt>pcall()</tt>,
<tt>lua_pcall()</tt> etc.</li>
<li>C++&nbsp;exceptions will be converted to the generic Lua error
<tt>"C++&nbsp;exception"</tt>, unless you use the
<a href="ext_c_api.html#mode_wrapcfunc">C&nbsp;call wrapper</a> feature.</li>
<li>It's safe to throw C++&nbsp;exceptions across non-protected Lua frames
on the C&nbsp;stack. The contents of the C++&nbsp;exception object
pass through unmodified.</li>
<li>Lua errors can be caught on the C++ side with <tt>catch(...)</tt>.
The corresponding Lua error message can be retrieved from the Lua stack.</li>
<li>Throwing Lua errors across C++ frames is safe. C++ destructors
will be called.</li>
</ul>
<p>
<b style="color: #c06000;">Limited interoperability</b> means:
</p>
<ul>
<li>C++&nbsp;exceptions can be caught on the Lua side with <tt>pcall()</tt>,
<tt>lua_pcall()</tt> etc.</li>
<li>C++&nbsp;exceptions will be converted to the generic Lua error
<tt>"C++&nbsp;exception"</tt>, unless you use the
<a href="ext_c_api.html#mode_wrapcfunc">C&nbsp;call wrapper</a> feature.</li>
<li>C++&nbsp;exceptions will be caught by non-protected Lua frames and
are rethrown as a generic Lua error. The C++&nbsp;exception object will
be destroyed.</li>
<li>Lua errors <b>cannot</b> be caught on the C++ side.</li>
<li>Throwing Lua errors across C++ frames will <b>not</b> call
C++ destructors.</li>
</ul>
<p>
<b style="color: #a00000;">No interoperability</b> means:
</p>
<ul>
<li>It's <b>not</b> safe to throw C++&nbsp;exceptions across Lua frames.</li>
<li>C++&nbsp;exceptions <b>cannot</b> be caught on the Lua side.</li>
<li>Lua errors <b>cannot</b> be caught on the C++ side.</li>
<li>Throwing Lua errors across C++ frames will <b>not</b> call
C++ destructors.</li>
<li>Additionally, on Windows/x86 with SEH-based C++&nbsp;exceptions:
it's <b>not</b> safe to throw a Lua error across any frames containing
a C++ function with any try/catch construct or using variables with
(implicit) destructors. This also applies to any functions which may be
inlined in such a function. It doesn't matter whether <tt>lua_error()</tt>
is called inside or outside of a try/catch or whether any object actually
needs to be destroyed: the SEH chain is corrupted and this will eventually
lead to the termination of the process.</li>
</ul>
<br class="flush">
</div>
<div id="foot">
<hr class="hide">
Copyright &copy; 2005-2013 Mike Pall
<span class="noprint">
&middot;
<a href="contact.html">Contact</a>
</span>
</div>
</body>
</html>
-184
View File
@@ -1,184 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Frequently Asked Questions (FAQ)</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Author" content="Mike Pall">
<meta name="Copyright" content="Copyright (C) 2005-2013, Mike Pall">
<meta name="Language" content="en">
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
<style type="text/css">
dd { margin-left: 1.5em; }
</style>
</head>
<body>
<div id="site">
<a href="http://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
</div>
<div id="head">
<h1>Frequently Asked Questions (FAQ)</h1>
</div>
<div id="nav">
<ul><li>
<a href="luajit.html">LuaJIT</a>
<ul><li>
<a href="http://luajit.org/download.html">Download <span class="ext">&raquo;</span></a>
</li><li>
<a href="install.html">Installation</a>
</li><li>
<a href="running.html">Running</a>
</li></ul>
</li><li>
<a href="extensions.html">Extensions</a>
<ul><li>
<a href="ext_ffi.html">FFI Library</a>
<ul><li>
<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
</li><li>
<a href="ext_ffi_api.html">ffi.* API</a>
</li><li>
<a href="ext_ffi_semantics.html">FFI Semantics</a>
</li></ul>
</li><li>
<a href="ext_jit.html">jit.* Library</a>
</li><li>
<a href="ext_c_api.html">Lua/C API</a>
</li></ul>
</li><li>
<a href="status.html">Status</a>
<ul><li>
<a href="changes.html">Changes</a>
</li></ul>
</li><li>
<a class="current" href="faq.html">FAQ</a>
</li><li>
<a href="http://luajit.org/performance.html">Performance <span class="ext">&raquo;</span></a>
</li><li>
<a href="http://wiki.luajit.org/">Wiki <span class="ext">&raquo;</span></a>
</li><li>
<a href="http://luajit.org/list.html">Mailing List <span class="ext">&raquo;</span></a>
</li></ul>
</div>
<div id="main">
<dl>
<dt>Q: Where can I learn more about LuaJIT and Lua?</dt>
<dd>
<ul style="padding: 0;">
<li>The <a href="http://luajit.org/list.html"><span class="ext">&raquo;</span>&nbsp;LuaJIT mailing list</a> focuses on topics
related to LuaJIT.</li>
<li>The <a href="http://wiki.luajit.org/"><span class="ext">&raquo;</span>&nbsp;LuaJIT wiki</a> gathers community
resources about LuaJIT.</li>
<li>News about Lua itself can be found at the
<a href="http://www.lua.org/lua-l.html"><span class="ext">&raquo;</span>&nbsp;Lua mailing list</a>.
The mailing list archives are worth checking out for older postings
about LuaJIT.</li>
<li>The <a href="http://lua.org"><span class="ext">&raquo;</span>&nbsp;main Lua.org site</a> has complete
<a href="http://www.lua.org/docs.html"><span class="ext">&raquo;</span>&nbsp;documentation</a> of the language
and links to books and papers about Lua.</li>
<li>The community-managed <a href="http://lua-users.org/wiki/"><span class="ext">&raquo;</span>&nbsp;Lua Wiki</a>
has information about diverse topics.</li>
</ul>
</dl>
<dl>
<dt>Q: Where can I learn more about the compiler technology used by LuaJIT?</dt>
<dd>
I'm planning to write more documentation about the internals of LuaJIT.
In the meantime, please use the following Google Scholar searches
to find relevant papers:<br>
Search for: <a href="http://scholar.google.com/scholar?q=Trace+Compiler"><span class="ext">&raquo;</span>&nbsp;Trace Compiler</a><br>
Search for: <a href="http://scholar.google.com/scholar?q=JIT+Compiler"><span class="ext">&raquo;</span>&nbsp;JIT Compiler</a><br>
Search for: <a href="http://scholar.google.com/scholar?q=Dynamic+Language+Optimizations"><span class="ext">&raquo;</span>&nbsp;Dynamic Language Optimizations</a><br>
Search for: <a href="http://scholar.google.com/scholar?q=SSA+Form"><span class="ext">&raquo;</span>&nbsp;SSA Form</a><br>
Search for: <a href="http://scholar.google.com/scholar?q=Linear+Scan+Register+Allocation"><span class="ext">&raquo;</span>&nbsp;Linear Scan Register Allocation</a><br>
Here is a list of the <a href="http://article.gmane.org/gmane.comp.lang.lua.general/58908"><span class="ext">&raquo;</span>&nbsp;innovative features in LuaJIT</a>.<br>
And, you know, reading the source is of course the only way to enlightenment. :-)
</dd>
</dl>
<dl>
<dt>Q: Why do I get this error: "attempt to index global 'arg' (a nil value)"?<br>
Q: My vararg functions fail after switching to LuaJIT!</dt>
<dd>LuaJIT is compatible to the Lua 5.1 language standard. It doesn't
support the implicit <tt>arg</tt> parameter for old-style vararg
functions from Lua 5.0.<br>Please convert your code to the
<a href="http://www.lua.org/manual/5.1/manual.html#2.5.9"><span class="ext">&raquo;</span>&nbsp;Lua 5.1
vararg syntax</a>.</dd>
</dl>
<dl>
<dt>Q: Why do I get this error: "bad FPU precision"?<br>
<dt>Q: I get weird behavior after initializing Direct3D.<br>
<dt>Q: Some FPU operations crash after I load a Delphi DLL.<br>
</dt>
<dd>
DirectX/Direct3D (up to version 9) sets the x87 FPU to single-precision
mode by default. This violates the Windows ABI and interferes with the
operation of many programs &mdash; LuaJIT is affected, too. Please make
sure you always use the <tt>D3DCREATE_FPU_PRESERVE</tt> flag when
initializing Direct3D.<br>
Direct3D version 10 or higher do not show this behavior anymore.
Consider testing your application with older versions, too.<br>
Similarly, the Borland/Delphi runtime modifies the FPU control word and
enables FP exceptions. Of course this violates the Windows ABI, too.
Please check the Delphi docs for the Set8087CW method.
</dl>
<dl>
<dt>Q: Sometimes Ctrl-C fails to stop my Lua program. Why?</dt>
<dd>The interrupt signal handler sets a Lua debug hook. But this is
currently ignored by compiled code (this will eventually be fixed). If
your program is running in a tight loop and never falls back to the
interpreter, the debug hook never runs and can't throw the
"interrupted!" error.<br> In the meantime you have to press Ctrl-C
twice to get stop your program. That's similar to when it's stuck
running inside a C function under the Lua interpreter.</dd>
</dl>
<dl>
<dt>Q: Why doesn't my favorite power-patch for Lua apply against LuaJIT?</dt>
<dd>Because it's a completely redesigned VM and has very little code
in common with Lua anymore. Also, if the patch introduces changes to
the Lua semantics, these would need to be reflected everywhere in the
VM, from the interpreter up to all stages of the compiler.<br> Please
use only standard Lua language constructs. For many common needs you
can use source transformations or use wrapper or proxy functions.
The compiler will happily optimize away such indirections.</dd>
</dl>
<dl>
<dt>Q: Lua runs everywhere. Why doesn't LuaJIT support my CPU?</dt>
<dd>Because it's a compiler &mdash; it needs to generate native
machine code. This means the code generator must be ported to each
architecture. And the fast interpreter is written in assembler and
must be ported, too. This is quite an undertaking.<br>
The <a href="install.html">install documentation</a> shows the supported
architectures. Other architectures will follow based on sufficient user
demand and/or sponsoring.</dd>
</dl>
<dl>
<dt>Q: When will feature X be added? When will the next version be released?</dt>
<dd>When it's ready.<br>
C'mon, it's open source &mdash; I'm doing it on my own time and you're
getting it for free. You can either contribute a patch or sponsor
the development of certain features, if they are important to you.
</dd>
</dl>
<br class="flush">
</div>
<div id="foot">
<hr class="hide">
Copyright &copy; 2005-2013 Mike Pall
<span class="noprint">
&middot;
<a href="contact.html">Contact</a>
</span>
</div>
</body>
</html>
-613
View File
@@ -1,613 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Installation</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Author" content="Mike Pall">
<meta name="Copyright" content="Copyright (C) 2005-2013, Mike Pall">
<meta name="Language" content="en">
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
<style type="text/css">
table.compat {
line-height: 1.2;
font-size: 80%;
}
table.compat td {
border: 1px solid #bfcfff;
height: 2.5em;
}
table.compat tr.compathead td {
font-weight: bold;
border-bottom: 2px solid #bfcfff;
}
tr.compathead td.compatos {
vertical-align: top;
}
table.compat td.compatcpu {
width: 18%;
border-right: 2px solid #bfcfff;
}
td.compatos {
width: 21%;
vertical-align: middle;
}
td.compatno {
background-color: #d0d0d0;
}
</style>
</head>
<body>
<div id="site">
<a href="http://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
</div>
<div id="head">
<h1>Installation</h1>
</div>
<div id="nav">
<ul><li>
<a href="luajit.html">LuaJIT</a>
<ul><li>
<a href="http://luajit.org/download.html">Download <span class="ext">&raquo;</span></a>
</li><li>
<a class="current" href="install.html">Installation</a>
</li><li>
<a href="running.html">Running</a>
</li></ul>
</li><li>
<a href="extensions.html">Extensions</a>
<ul><li>
<a href="ext_ffi.html">FFI Library</a>
<ul><li>
<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
</li><li>
<a href="ext_ffi_api.html">ffi.* API</a>
</li><li>
<a href="ext_ffi_semantics.html">FFI Semantics</a>
</li></ul>
</li><li>
<a href="ext_jit.html">jit.* Library</a>
</li><li>
<a href="ext_c_api.html">Lua/C API</a>
</li></ul>
</li><li>
<a href="status.html">Status</a>
<ul><li>
<a href="changes.html">Changes</a>
</li></ul>
</li><li>
<a href="faq.html">FAQ</a>
</li><li>
<a href="http://luajit.org/performance.html">Performance <span class="ext">&raquo;</span></a>
</li><li>
<a href="http://wiki.luajit.org/">Wiki <span class="ext">&raquo;</span></a>
</li><li>
<a href="http://luajit.org/list.html">Mailing List <span class="ext">&raquo;</span></a>
</li></ul>
</div>
<div id="main">
<p>
LuaJIT is only distributed as a source package. This page explains
how to build and install LuaJIT with different operating systems
and C&nbsp;compilers.
</p>
<p>
For the impatient (on POSIX systems):
</p>
<pre class="code">
make &amp;&amp; sudo make install
</pre>
<p>
LuaJIT currently builds out-of-the box on most systems.
Here's the compatibility matrix for the supported combinations of
operating systems, CPUs and compilers:
</p>
<table class="compat">
<tr class="compathead">
<td class="compatcpu">CPU / OS</td>
<td class="compatos"><a href="#posix">Linux</a> or<br><a href="#android">Android</a></td>
<td class="compatos"><a href="#posix">*BSD, Other</a></td>
<td class="compatos"><a href="#posix">OSX 10.4+</a> or<br><a href="#ios">iOS 3.0+</a></td>
<td class="compatos"><a href="#windows">Windows<br>XP/Vista/7</a></td>
</tr>
<tr class="odd separate">
<td class="compatcpu">x86 (32 bit)</td>
<td class="compatos">GCC 4.x<br>GCC 3.4</td>
<td class="compatos">GCC 4.x<br>GCC 3.4</td>
<td class="compatos">GCC 4.x<br>GCC 3.4</td>
<td class="compatos">MSVC, MSVC/EE<br>WinSDK<br>MinGW, Cygwin</td>
</tr>
<tr class="even">
<td class="compatcpu">x64 (64 bit)</td>
<td class="compatos">GCC 4.x</td>
<td class="compatos compatno">&nbsp;</td>
<td class="compatos">GCC 4.x</td>
<td class="compatos">MSVC + SDK v7.0<br>WinSDK v7.0</td>
</tr>
<tr class="odd">
<td class="compatcpu"><a href="#cross2">ARMv5+<br>ARM9E+</a></td>
<td class="compatos">GCC 4.2+</td>
<td class="compatos">GCC 4.2+</td>
<td class="compatos">GCC 4.2+</td>
<td class="compatos compatno">&nbsp;</td>
</tr>
<tr class="even">
<td class="compatcpu"><a href="#cross2">PPC</a></td>
<td class="compatos">GCC 4.3+</td>
<td class="compatos">GCC 4.3+<br>GCC 4.1 (<a href="#ps3">PS3</a>)</td>
<td class="compatos compatno">&nbsp;</td>
<td class="compatos">XEDK (<a href="#xbox360">Xbox 360</a>)</td>
</tr>
<tr class="odd">
<td class="compatcpu"><a href="#cross2">PPC/e500v2</a></td>
<td class="compatos">GCC 4.3+</td>
<td class="compatos">GCC 4.3+</td>
<td class="compatos compatno">&nbsp;</td>
<td class="compatos compatno">&nbsp;</td>
</tr>
<tr class="even">
<td class="compatcpu"><a href="#cross2">MIPS</a></td>
<td class="compatos">GCC 4.3+</td>
<td class="compatos">GCC 4.3+</td>
<td class="compatos compatno">&nbsp;</td>
<td class="compatos compatno">&nbsp;</td>
</tr>
</table>
<h2>Configuring LuaJIT</h2>
<p>
The standard configuration should work fine for most installations.
Usually there is no need to tweak the settings. The following files
hold all user-configurable settings:
</p>
<ul>
<li><tt>src/luaconf.h</tt> sets some configuration variables.</li>
<li><tt>Makefile</tt> has settings for <b>installing</b> LuaJIT (POSIX
only).</li>
<li><tt>src/Makefile</tt> has settings for <b>compiling</b> LuaJIT
under POSIX, MinGW or Cygwin.</li>
<li><tt>src/msvcbuild.bat</tt> has settings for compiling LuaJIT with
MSVC or WinSDK.</li>
</ul>
<p>
Please read the instructions given in these files, before changing
any settings.
</p>
<h2 id="posix">POSIX Systems (Linux, OSX, *BSD etc.)</h2>
<h3>Prerequisites</h3>
<p>
Depending on your distribution, you may need to install a package for
GCC, the development headers and/or a complete SDK. E.g. on a current
Debian/Ubuntu, install <tt>libc6-dev</tt> with the package manager.
</p>
<p>
Download the current source package of LuaJIT (pick the .tar.gz),
if you haven't already done so. Move it to a directory of your choice,
open a terminal window and change to this directory. Now unpack the archive
and change to the newly created directory:
</p>
<pre class="code">
tar zxf LuaJIT-2.0.1.tar.gz
cd LuaJIT-2.0.1</pre>
<h3>Building LuaJIT</h3>
<p>
The supplied Makefiles try to auto-detect the settings needed for your
operating system and your compiler. They need to be run with GNU Make,
which is probably the default on your system, anyway. Simply run:
</p>
<pre class="code">
make
</pre>
<p>
This always builds a native x86, x64 or PPC binary, depending on the host OS
you're running this command on. Check the section on
<a href="#cross">cross-compilation</a> for more options.
</p>
<p>
By default, modules are only searched under the prefix <tt>/usr/local</tt>.
You can add an extra prefix to the search paths by appending the
<tt>PREFIX</tt> option, e.g.:
</p>
<pre class="code">
make PREFIX=/home/myself/lj2
</pre>
<p>
Note for OSX: if the <tt>MACOSX_DEPLOYMENT_TARGET</tt> environment
variable is not set, then it's forced to <tt>10.4</tt>.
</p>
<h3>Installing LuaJIT</h3>
<p>
The top-level Makefile installs LuaJIT by default under
<tt>/usr/local</tt>, i.e. the executable ends up in
<tt>/usr/local/bin</tt> and so on. You need root privileges
to write to this path. So, assuming sudo is installed on your system,
run the following command and enter your sudo password:
</p>
<pre class="code">
sudo make install
</pre>
<p>
Otherwise specify the directory prefix as an absolute path, e.g.:
</p>
<pre class="code">
make install PREFIX=/home/myself/lj2
</pre>
<p>
Obviously the prefixes given during build and installation need to be the same.
</p>
<h2 id="windows">Windows Systems</h2>
<h3>Prerequisites</h3>
<p>
Either install one of the open source SDKs
(<a href="http://mingw.org/"><span class="ext">&raquo;</span>&nbsp;MinGW</a> or
<a href="http://www.cygwin.com/"><span class="ext">&raquo;</span>&nbsp;Cygwin</a>), which come with a modified
GCC plus the required development headers.
</p>
<p>
Or install Microsoft's Visual C++ (MSVC). The freely downloadable
<a href="http://www.microsoft.com/Express/VC/"><span class="ext">&raquo;</span>&nbsp;Express Edition</a>
works just fine, but only contains an x86 compiler.
</p>
<p>
The freely downloadable
<a href="http://msdn.microsoft.com/en-us/windowsserver/bb980924.aspx"><span class="ext">&raquo;</span>&nbsp;Windows SDK</a>
only comes with command line tools, but this is all you need to build LuaJIT.
It contains x86 and x64 compilers.
</p>
<p>
Next, download the source package and unpack it using an archive manager
(e.g. the Windows Explorer) to a directory of your choice.
</p>
<h3>Building with MSVC</h3>
<p>
Open a "Visual Studio .NET Command Prompt", <tt>cd</tt> to the
directory where you've unpacked the sources and run these commands:
</p>
<pre class="code">
cd src
msvcbuild
</pre>
<p>
Then follow the installation instructions below.
</p>
<h3>Building with the Windows SDK</h3>
<p>
Open a "Windows SDK Command Shell" and select the x86 compiler:
</p>
<pre class="code">
setenv /release /x86
</pre>
<p>
Or select the x64 compiler:
</p>
<pre class="code">
setenv /release /x64
</pre>
<p>
Then <tt>cd</tt> to the directory where you've unpacked the sources
and run these commands:
</p>
<pre class="code">
cd src
msvcbuild
</pre>
<p>
Then follow the installation instructions below.
</p>
<h3>Building with MinGW or Cygwin</h3>
<p>
Open a command prompt window and make sure the MinGW or Cygwin programs
are in your path. Then <tt>cd</tt> to the directory where
you've unpacked the sources and run this command for MinGW:
</p>
<pre class="code">
mingw32-make
</pre>
<p>
Or this command for Cygwin:
</p>
<pre class="code">
make
</pre>
<p>
Then follow the installation instructions below.
</p>
<h3>Installing LuaJIT</h3>
<p>
Copy <tt>luajit.exe</tt> and <tt>lua51.dll</tt> (built in the <tt>src</tt>
directory) to a newly created directory (any location is ok).
Add <tt>lua</tt> and <tt>lua\jit</tt> directories below it and copy
all Lua files from the <tt>src\jit</tt> directory of the distribution
to the latter directory.
</p>
<p>
There are no hardcoded
absolute path names &mdash; all modules are loaded relative to the
directory where <tt>luajit.exe</tt> is installed
(see <tt>src/luaconf.h</tt>).
</p>
<h2 id="cross">Cross-compiling LuaJIT</h2>
<p>
The GNU Makefile-based build system allows cross-compiling on any host
for any supported target, as long as both architectures have the same
pointer size. If you want to cross-compile to any 32 bit target on an
x64 OS, you need to install the multilib development package (e.g.
<tt>libc6-dev-i386</tt> on Debian/Ubuntu) and build a 32 bit host part
(<tt>HOST_CC="gcc -m32"</tt>).
</p>
<p>
You need to specify <tt>TARGET_SYS</tt> whenever the host OS and the
target OS differ, or you'll get assembler or linker errors. E.g. if
you're compiling on a Windows or OSX host for embedded Linux or Android,
you need to add <tt>TARGET_SYS=Linux</tt> to the examples below. For a
minimal target OS, you may need to disable the built-in allocator in
<tt>src/Makefile</tt> and use <tt>TARGET_SYS=Other</tt>. The examples
below only show some popular targets &mdash; please check the comments
in <tt>src/Makefile</tt> for more details.
</p>
<pre class="code">
# Cross-compile to a 32 bit binary on a multilib x64 OS
make CC="gcc -m32"
# Cross-compile on Debian/Ubuntu for Windows (mingw32 package)
make HOST_CC="gcc -m32" CROSS=i586-mingw32msvc- TARGET_SYS=Windows
</pre>
<p id="cross2">
The <tt>CROSS</tt> prefix allows specifying a standard GNU cross-compile
toolchain (Binutils, GCC and a matching libc). The prefix may vary
depending on the <tt>--target</tt> the toolchain was built for (note the
<tt>CROSS</tt> prefix has a trailing <tt>"-"</tt>). The examples below
use the canonical toolchain triplets for Linux.
</p>
<p>
Since there's often no easy way to detect CPU features at runtime, it's
important to compile with the proper CPU or architecture settings. You
can specify these when building the toolchain yourself. Or add
<tt>-mcpu=...</tt> or <tt>-march=...</tt> to <tt>TARGET_CFLAGS</tt>. For
ARM it's important to have the correct <tt>-mfloat-abi=...</tt> setting,
too. Otherwise LuaJIT may not run at the full performance of your target
CPU.
</p>
<pre class="code">
# ARM soft-float
make HOST_CC="gcc -m32" CROSS=arm-linux-gnueabi- \
TARGET_CFLAGS="-mfloat-abi=soft"
# ARM soft-float ABI with VFP (example for Cortex-A8)
make HOST_CC="gcc -m32" CROSS=arm-linux-gnueabi- \
TARGET_CFLAGS="-mcpu=cortex-a8 -mfloat-abi=softfp"
# ARM hard-float ABI with VFP (armhf, requires recent toolchain)
make HOST_CC="gcc -m32" CROSS=arm-linux-gnueabihf-
# PPC
make HOST_CC="gcc -m32" CROSS=powerpc-linux-gnu-
# PPC/e500v2 (fast interpreter only)
make HOST_CC="gcc -m32" CROSS=powerpc-e500v2-linux-gnuspe-
# MIPS big-endian
make HOST_CC="gcc -m32" CROSS=mips-linux-
# MIPS little-endian
make HOST_CC="gcc -m32" CROSS=mipsel-linux-
</pre>
<p>
You can cross-compile for <b id="android">Android</b> using the <a href="http://developer.android.com/sdk/ndk/index.html"><span class="ext">&raquo;</span>&nbsp;Android NDK</a>.
The environment variables need to match the install locations and the
desired target platform. E.g. Android&nbsp;4.0 corresponds to ABI level&nbsp;14.
For details check the folder <tt>docs</tt> in the NDK directory.
</p>
<p>
Only a few common variations for the different CPUs, ABIs and platforms
are listed. Please use your own judgement for which combination you want
to build/deploy or which lowest common denominator you want to pick:
</p>
<pre class="code">
# Android/ARM, armeabi (ARMv5TE soft-float), Android 2.2+ (Froyo)
NDK=/opt/android/ndk
NDKABI=8
NDKVER=$NDK/toolchains/arm-linux-androideabi-4.6
NDKP=$NDKVER/prebuilt/linux-x86/bin/arm-linux-androideabi-
NDKF="--sysroot $NDK/platforms/android-$NDKABI/arch-arm"
make HOST_CC="gcc -m32" CROSS=$NDKP TARGET_FLAGS="$NDKF"
# Android/ARM, armeabi-v7a (ARMv7 VFP), Android 4.0+ (ICS)
NDK=/opt/android/ndk
NDKABI=14
NDKVER=$NDK/toolchains/arm-linux-androideabi-4.6
NDKP=$NDKVER/prebuilt/linux-x86/bin/arm-linux-androideabi-
NDKF="--sysroot $NDK/platforms/android-$NDKABI/arch-arm"
NDKARCH="-march=armv7-a -mfloat-abi=softfp -Wl,--fix-cortex-a8"
make HOST_CC="gcc -m32" CROSS=$NDKP TARGET_FLAGS="$NDKF $NDKARCH"
# Android/MIPS, mips (MIPS32R1 hard-float), Android 4.0+ (ICS)
NDK=/opt/android/ndk
NDKABI=14
NDKVER=$NDK/toolchains/mipsel-linux-android-4.6
NDKP=$NDKVER/prebuilt/linux-x86/bin/mipsel-linux-android-
NDKF="--sysroot $NDK/platforms/android-$NDKABI/arch-mips"
make HOST_CC="gcc -m32" CROSS=$NDKP TARGET_FLAGS="$NDKF"
# Android/x86, x86 (i686 SSE3), Android 4.0+ (ICS)
NDK=/opt/android/ndk
NDKABI=14
NDKVER=$NDK/toolchains/x86-4.6
NDKP=$NDKVER/prebuilt/linux-x86/bin/i686-linux-android-
NDKF="--sysroot $NDK/platforms/android-$NDKABI/arch-x86"
make HOST_CC="gcc -m32" CROSS=$NDKP TARGET_FLAGS="$NDKF"
</pre>
<p>
You can cross-compile for <b id="ios">iOS 3.0+</b> (iPhone/iPad) using the <a href="http://developer.apple.com/devcenter/ios/index.action"><span class="ext">&raquo;</span>&nbsp;iOS SDK</a>.
The environment variables need to match the iOS SDK version:
</p>
<p style="font-size: 8pt;">
Note: <b>the JIT compiler is disabled for iOS</b>, because regular iOS Apps
are not allowed to generate code at runtime. You'll only get the performance
of the LuaJIT interpreter on iOS. This is still faster than plain Lua, but
much slower than the JIT compiler. Please complain to Apple, not me.
Or use Android. :-p
</p>
<pre class="code">
IXCODE=`xcode-select -print-path`
ISDK=$IXCODE/Platforms/iPhoneOS.platform/Developer
ISDKVER=iPhoneOS6.0.sdk
ISDKP=$ISDK/usr/bin/
ISDKF="-arch armv7 -isysroot $ISDK/SDKs/$ISDKVER"
make HOST_CC="gcc -m32 -arch i386" CROSS=$ISDKP TARGET_FLAGS="$ISDKF" \
TARGET_SYS=iOS
</pre>
<p>
You can cross-compile for <b id="ps3">PS3</b> using the PS3&nbsp;SDK from
a Linux host or a Windows host (requires 32 bit MinGW (GCC) on the host,
too). Due to restrictions on consoles, the JIT compiler is disabled and
only the fast interpreter is built:
</p>
<pre class="code">
make HOST_CC="gcc -m32" CROSS=ppu-lv2-
</pre>
<p>
You can cross-compile for <b id="xbox360">Xbox 360</b> using the
Xbox&nbsp;360 SDK (MSVC + XEDK). Due to restrictions on consoles, the
JIT compiler is disabled and only the fast interpreter is built.
</p>
<p>
Open a "Visual Studio .NET Command Prompt" (32&nbsp;bit host compiler),
<tt>cd</tt> to the directory where you've unpacked the sources and run
the following commands. This builds a static library <tt>luajit20.lib</tt>,
which can be linked against your game, just like the Lua library.
</p>
<pre class="code">
cd src
xedkbuild
</pre>
<h2 id="embed">Embedding LuaJIT</h2>
<p>
LuaJIT is API-compatible with Lua 5.1. If you've already embedded Lua
into your application, you probably don't need to do anything to switch
to LuaJIT, except link with a different library:
</p>
<ul>
<li>It's strongly suggested to build LuaJIT separately using the supplied
build system. Please do <em>not</em> attempt to integrate the individual
source files into your build tree. You'll most likely get the internal build
dependencies wrong or mess up the compiler flags. Treat LuaJIT like any
other external library and link your application with either the dynamic
or static library, depending on your needs.</li>
<li>If you want to load C modules compiled for plain Lua
with <tt>require()</tt>, you need to make sure the public symbols
(e.g. <tt>lua_pushnumber</tt>) are exported, too:
<ul><li>On POSIX systems you can either link to the shared library
or link the static library into your application. In the latter case
you'll need to export all public symbols from your main executable
(e.g. <tt>-Wl,-E</tt> on Linux) and add the external dependencies
(e.g. <tt>-lm -ldl</tt> on Linux).</li>
<li>Since Windows symbols are bound to a specific DLL name, you need to
link to the <tt>lua51.dll</tt> created by the LuaJIT build (do not rename
the DLL). You may link LuaJIT statically on Windows only if you don't
intend to load Lua/C modules at runtime.
</li></ul>
</li>
<li>
If you're building a 64 bit application on OSX which links directly or
indirectly against LuaJIT, you need to link your main executable
with these flags:
<pre class="code">
-pagezero_size 10000 -image_base 100000000
</pre>
Also, it's recommended to <tt>rebase</tt> all (self-compiled) shared libraries
which are loaded at runtime on OSX/x64 (e.g. C extension modules for Lua).
See: <tt>man rebase</tt>
</li>
</ul>
<p>Additional hints for initializing LuaJIT using the C API functions:</p>
<ul>
<li>Here's a
<a href="http://lua-users.org/wiki/SimpleLuaApiExample"><span class="ext">&raquo;</span>&nbsp;simple example</a>
for embedding Lua or LuaJIT into your application.</li>
<li>Make sure you use <tt>luaL_newstate</tt>. Avoid using
<tt>lua_newstate</tt>, since this uses the (slower) default memory
allocator from your system (no support for this on x64).</li>
<li>Make sure you use <tt>luaL_openlibs</tt> and not the old Lua 5.0 style
of calling <tt>luaopen_base</tt> etc. directly.</li>
<li>To change or extend the list of standard libraries to load, copy
<tt>src/lib_init.c</tt> to your project and modify it accordingly.
Make sure the <tt>jit</tt> library is loaded or the JIT compiler
will not be activated.</li>
<li>The <tt>bit.*</tt> module for bitwise operations
is already built-in. There's no need to statically link
<a href="http://bitop.luajit.org/"><span class="ext">&raquo;</span>&nbsp;Lua BitOp</a> to your application.</li>
</ul>
<h2 id="distro">Hints for Distribution Maintainers</h2>
<p>
The LuaJIT build system has extra provisions for the needs of most
POSIX-based distributions. If you're a package maintainer for
a distribution, <em>please</em> make use of these features and
avoid patching, subverting, autotoolizing or messing up the build system
in unspeakable ways.
</p>
<p>
There should be absolutely no need to patch <tt>luaconf.h</tt> or any
of the Makefiles. And please do not hand-pick files for your packages &mdash;
simply use whatever <tt>make install</tt> creates. There's a reason
for all of the files <em>and</em> directories it creates.
</p>
<p>
The build system uses GNU make and auto-detects most settings based on
the host you're building it on. This should work fine for native builds,
even when sandboxed. You may need to pass some of the following flags to
<em>both</em> the <tt>make</tt> and the <tt>make install</tt> command lines
for a regular distribution build:
</p>
<ul>
<li><tt>PREFIX</tt> overrides the installation path and should usually
be set to <tt>/usr</tt>. Setting this also changes the module paths and
the <tt>-rpath</tt> of the shared library.</li>
<li><tt>DESTDIR</tt> is an absolute path which allows you to install
to a shadow tree instead of the root tree of the build system.</li>
<li>Have a look at the top-level <tt>Makefile</tt> and <tt>src/Makefile</tt>
for additional variables to tweak. The following variables <em>may</em> be
overridden, but it's <em>not</em> recommended, except for special needs
like cross-builds:
<tt>BUILDMODE, CC, HOST_CC, STATIC_CC, DYNAMIC_CC, CFLAGS, HOST_CFLAGS,
TARGET_CFLAGS, LDFLAGS, HOST_LDFLAGS, TARGET_LDFLAGS, TARGET_SHLDFLAGS,
TARGET_FLAGS, LIBS, HOST_LIBS, TARGET_LIBS, CROSS, HOST_SYS, TARGET_SYS
</tt></li>
</ul>
<p>
The build system has a special target for an amalgamated build, i.e.
<tt>make amalg</tt>. This compiles the LuaJIT core as one huge C file
and allows GCC to generate faster and shorter code. Alas, this requires
lots of memory during the build. This may be a problem for some users,
that's why it's not enabled by default. But it shouldn't be a problem for
most build farms. It's recommended that binary distributions use this
target for their LuaJIT builds.
</p>
<p>
The tl;dr version of the above:
</p>
<pre class="code">
make amalg PREFIX=/usr && \
make install PREFIX=/usr DESTDIR=/tmp/buildroot
</pre>
<p>
Finally, if you encounter any difficulties, please
<a href="contact.html">contact me</a> first, instead of releasing a broken
package onto unsuspecting users. Because they'll usually gonna complain
to me (the upstream) and not you (the package maintainer), anyway.
</p>
<br class="flush">
</div>
<div id="foot">
<hr class="hide">
Copyright &copy; 2005-2013 Mike Pall
<span class="noprint">
&middot;
<a href="contact.html">Contact</a>
</span>
</div>
</body>
</html>
-228
View File
@@ -1,228 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>LuaJIT</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Author" content="Mike Pall">
<meta name="Copyright" content="Copyright (C) 2005-2013, Mike Pall">
<meta name="Language" content="en">
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
<meta name="description" content="LuaJIT is a Just-In-Time (JIT) compiler for the Lua language.">
<style type="text/css">
table.feature {
width: inherit;
line-height: 1.2;
margin: 0;
}
table.feature td {
width: 80px;
height: 40px;
vertical-align: middle;
text-align: center;
font-weight: bold;
border: 4px solid #e6ecff;
border-radius: 12px;
}
table.os td {
background: #7080d0;
background-image: linear-gradient(#4060c0 10%, #b0b0ff 95%);
background-image: -moz-linear-gradient(#4060c0 10%, #b0b0ff 95%);
background-image: -webkit-linear-gradient(#4060c0 10%, #b0b0ff 95%);
background-image: -o-linear-gradient(#4060c0 10%, #b0b0ff 95%);
background-image: -ms-linear-gradient(#4060c0 10%, #b0b0ff 95%);
}
table.os1 td {
color: #ffff80;
}
table.os2 td {
color: #ffa040;
}
table.compiler td {
color: #2080ff;
background: #62bf41;
background-image: linear-gradient(#62bf41 10%, #b0ffb0 95%);
background-image: -moz-linear-gradient(#62bf41 10%, #b0ffb0 95%);
background-image: -webkit-linear-gradient(#62bf41 10%, #b0ffb0 95%);
background-image: -o-linear-gradient(#62bf41 10%, #b0ffb0 95%);
background-image: -ms-linear-gradient(#62bf41 10%, #b0ffb0 95%);
}
table.cpu td {
color: #ffff00;
background: #cf7251;
background-image: linear-gradient(#bf6241 10%, #ffb0b0 95%);
background-image: -moz-linear-gradient(#bf6241 10%, #ffb0b0 95%);
background-image: -webkit-linear-gradient(#bf6241 10%, #ffb0b0 95%);
background-image: -o-linear-gradient(#bf6241 10%, #ffb0b0 95%);
background-image: -ms-linear-gradient(#bf6241 10%, #ffb0b0 95%);
}
table.fcompat td {
color: #2060e0;
background: #61cfcf;
background-image: linear-gradient(#41bfbf 10%, #b0ffff 95%);
background-image: -moz-linear-gradient(#41bfbf 10%, #b0ffff 95%);
background-image: -webkit-linear-gradient(#41bfbf 10%, #b0ffff 95%);
background-image: -o-linear-gradient(#41bfbf 10%, #b0ffff 95%);
background-image: -ms-linear-gradient(#41bfbf 10%, #b0ffff 95%);
}
table.stats td {
color: #ffffff;
background: #a0a0a0;
background-image: linear-gradient(#808080 10%, #d0d0d0 95%);
background-image: -moz-linear-gradient(#808080 10%, #d0d0d0 95%);
background-image: -webkit-linear-gradient(#808080 10%, #d0d0d0 95%);
background-image: -o-linear-gradient(#808080 10%, #d0d0d0 95%);
background-image: -ms-linear-gradient(#808080 10%, #d0d0d0 95%);
}
table.stats td.speed {
color: #ff4020;
}
table.stats td.kb {
color: #ffff80;
background: #808080;
background-image: linear-gradient(#606060 10%, #c0c0c0 95%);
background-image: -moz-linear-gradient(#606060 10%, #c0c0c0 95%);
background-image: -webkit-linear-gradient(#606060 10%, #c0c0c0 95%);
background-image: -o-linear-gradient(#606060 10%, #c0c0c0 95%);
background-image: -ms-linear-gradient(#606060 10%, #c0c0c0 95%);
}
table.feature small {
font-size: 50%;
}
</style>
</head>
<body>
<div id="site">
<a href="http://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
</div>
<div id="head">
<h1>LuaJIT</h1>
</div>
<div id="nav">
<ul><li>
<a class="current" href="luajit.html">LuaJIT</a>
<ul><li>
<a href="http://luajit.org/download.html">Download <span class="ext">&raquo;</span></a>
</li><li>
<a href="install.html">Installation</a>
</li><li>
<a href="running.html">Running</a>
</li></ul>
</li><li>
<a href="extensions.html">Extensions</a>
<ul><li>
<a href="ext_ffi.html">FFI Library</a>
<ul><li>
<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
</li><li>
<a href="ext_ffi_api.html">ffi.* API</a>
</li><li>
<a href="ext_ffi_semantics.html">FFI Semantics</a>
</li></ul>
</li><li>
<a href="ext_jit.html">jit.* Library</a>
</li><li>
<a href="ext_c_api.html">Lua/C API</a>
</li></ul>
</li><li>
<a href="status.html">Status</a>
<ul><li>
<a href="changes.html">Changes</a>
</li></ul>
</li><li>
<a href="faq.html">FAQ</a>
</li><li>
<a href="http://luajit.org/performance.html">Performance <span class="ext">&raquo;</span></a>
</li><li>
<a href="http://wiki.luajit.org/">Wiki <span class="ext">&raquo;</span></a>
</li><li>
<a href="http://luajit.org/list.html">Mailing List <span class="ext">&raquo;</span></a>
</li></ul>
</div>
<div id="main">
<p>
LuaJIT is a <b>Just-In-Time Compiler</b> (JIT) for the
<a href="http://www.lua.org/"><span class="ext">&raquo;</span>&nbsp;Lua</a> programming language.
Lua is a powerful, dynamic and light-weight programming language.
It may be embedded or used as a general-purpose, stand-alone language.
</p>
<p>
LuaJIT is Copyright &copy; 2005-2013 Mike Pall, released under the
<a href="http://www.opensource.org/licenses/mit-license.php"><span class="ext">&raquo;</span>&nbsp;MIT open source license</a>.
</p>
<p>
</p>
<h2>Compatibility</h2>
<table class="feature os os1">
<tr><td>Windows</td><td>Linux</td><td>BSD</td><td>OSX</td><td>POSIX</td></tr>
</table>
<table class="feature os os2">
<tr><td><span style="font-size:90%;">Embedded</span></td><td>Android</td><td>iOS</td><td>PS3</td><td>Xbox 360</td></tr>
</table>
<table class="feature compiler">
<tr><td>GCC</td><td>CLANG<br>LLVM</td><td>MSVC</td></tr>
</table>
<table class="feature cpu">
<tr><td>x86</td><td>x64</td><td>ARM</td><td>PPC</td><td>e500</td><td>MIPS</td></tr>
</table>
<table class="feature fcompat">
<tr><td>Lua&nbsp;5.1<br>API+ABI</td><td>+&nbsp;JIT</td><td>+&nbsp;BitOp</td><td>+&nbsp;FFI</td><td>Drop-in<br>DLL/.so</td></tr>
</table>
<h2>Overview</h2>
<table class="feature stats">
<tr>
<td class="speed">3x<br>-&nbsp;&nbsp;100x</td>
<td class="kb">115&nbsp;<small>KB</small><br>VM</td>
<td class="kb">90&nbsp;<small>KB</small><br>JIT</td>
<td class="kloc">63&nbsp;<small>KLOC</small><br>C</td>
<td class="kloc">24&nbsp;<small>KLOC</small><br>ASM</td>
<td class="kloc">11&nbsp;<small>KLOC</small><br>Lua</td>
</tr>
</table>
<p style="margin-top: 1em;">
LuaJIT has been successfully used as a <b>scripting middleware</b> in
games, appliances, network and graphics apps, numerical simulations,
trading platforms and many other specialty applications. It scales from
embedded devices, smartphones, desktops up to server farms. It combines
high flexibility with <a href="http://luajit.org/performance.html"><span class="ext">&raquo;</span>&nbsp;high performance</a>
and an unmatched <b>low memory footprint</b>.
</p>
<p>
LuaJIT has been in continuous development since 2005. It's widely
considered to be <b>one of the fastest dynamic language
implementations</b>. It has outperformed other dynamic languages on many
cross-language benchmarks since its first release &mdash; often by a
substantial margin.
</p>
<p>
For <b>LuaJIT 2.0</b>, the whole VM has been rewritten from the ground up
and relentlessly optimized for performance. It combines a <b>high-speed
interpreter</b>, written in assembler, with a <b>state-of-the-art JIT
compiler</b>.
</p>
<p>
An innovative <b>trace compiler</b> is integrated with advanced,
SSA-based optimizations and highly tuned code generation backends.
A substantial reduction of the overhead associated with dynamic languages
allows it to break into the performance range traditionally reserved for
offline, static language compilers.
</p>
<h2>More ...</h2>
<p>
Please select a sub-topic in the navigation bar to learn more about LuaJIT.
</p>
<br class="flush">
</div>
<div id="foot">
<hr class="hide">
Copyright &copy; 2005-2013 Mike Pall
<span class="noprint">
&middot;
<a href="contact.html">Contact</a>
</span>
</div>
</body>
</html>
-125
View File
@@ -1,125 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Status &amp; Roadmap</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Author" content="Mike Pall">
<meta name="Copyright" content="Copyright (C) 2005-2013, Mike Pall">
<meta name="Language" content="en">
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
<style type="text/css">
ul li { padding-bottom: 0.3em; }
</style>
</head>
<body>
<div id="site">
<a href="http://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
</div>
<div id="head">
<h1>Status &amp; Roadmap</h1>
</div>
<div id="nav">
<ul><li>
<a href="luajit.html">LuaJIT</a>
<ul><li>
<a href="http://luajit.org/download.html">Download <span class="ext">&raquo;</span></a>
</li><li>
<a href="install.html">Installation</a>
</li><li>
<a href="running.html">Running</a>
</li></ul>
</li><li>
<a href="extensions.html">Extensions</a>
<ul><li>
<a href="ext_ffi.html">FFI Library</a>
<ul><li>
<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
</li><li>
<a href="ext_ffi_api.html">ffi.* API</a>
</li><li>
<a href="ext_ffi_semantics.html">FFI Semantics</a>
</li></ul>
</li><li>
<a href="ext_jit.html">jit.* Library</a>
</li><li>
<a href="ext_c_api.html">Lua/C API</a>
</li></ul>
</li><li>
<a class="current" href="status.html">Status</a>
<ul><li>
<a href="changes.html">Changes</a>
</li></ul>
</li><li>
<a href="faq.html">FAQ</a>
</li><li>
<a href="http://luajit.org/performance.html">Performance <span class="ext">&raquo;</span></a>
</li><li>
<a href="http://wiki.luajit.org/">Wiki <span class="ext">&raquo;</span></a>
</li><li>
<a href="http://luajit.org/list.html">Mailing List <span class="ext">&raquo;</span></a>
</li></ul>
</div>
<div id="main">
<p>
<span style="color: #0000c0;">LuaJIT&nbsp;2.0</span> is the current
<span style="color: #0000c0;">stable branch</span>. This branch is in
feature-freeze &mdash; new features will only be added to LuaJIT&nbsp;2.1.
</p>
<h2>Current Status</h2>
<p>
LuaJIT ought to run all Lua&nbsp;5.1-compatible source code just fine.
It's considered a serious bug if the VM crashes or produces unexpected
results &mdash; please report this.
</p>
<p>
Known incompatibilities and issues in LuaJIT&nbsp;2.0:
</p>
<ul>
<li>
There are some differences in <b>implementation-defined</b> behavior.
These either have a good reason, are arbitrary design choices
or are due to quirks in the VM. The latter cases may get fixed if a
demonstrable need is shown.
</li>
<li>
The Lua <b>debug API</b> is missing a couple of features (return
hooks for non-Lua functions) and shows slightly different behavior
in LuaJIT (no per-coroutine hooks, no tail call counting).
</li>
<li>
Some checks are missing in the JIT-compiled code for obscure situations
with <b>open upvalues aliasing</b> one of the SSA slots later on (or
vice versa). Bonus points, if you can find a real world test case for
this.
</li>
<li>
Currently some <b>out-of-memory</b> errors from <b>on-trace code</b> are not
handled correctly. The error may fall through an on-trace
<tt>pcall</tt> or it may be passed on to the function set with
<tt>lua_atpanic</tt> on x64. This issue will be fixed with the new
garbage collector.
</li>
</ul>
<h2>Roadmap</h2>
<p>
Please refer to the
<a href="http://www.freelists.org/post/luajit/LuaJIT-Roadmap-20122013"><span class="ext">&raquo;</span>&nbsp;LuaJIT Roadmap 2012/2013</a> and an
<a href="http://www.freelists.org/post/luajit/LuaJIT-Roadmap-20122013-UPDATE"><span class="ext">&raquo;</span>&nbsp;update on release planning</a> for details.
</p>
<p>
</p>
<br class="flush">
</div>
<div id="foot">
<hr class="hide">
Copyright &copy; 2005-2013 Mike Pall
<span class="noprint">
&middot;
<a href="contact.html">Contact</a>
</span>
</div>
</body>
</html>
-953
View File
@@ -1,953 +0,0 @@
------------------------------------------------------------------------------
-- DynASM MIPS module.
--
-- Copyright (C) 2005-2013 Mike Pall. All rights reserved.
-- See dynasm.lua for full copyright notice.
------------------------------------------------------------------------------
-- Module information:
local _info = {
arch = "mips",
description = "DynASM MIPS module",
version = "1.3.0",
vernum = 10300,
release = "2012-01-23",
author = "Mike Pall",
license = "MIT",
}
-- Exported glue functions for the arch-specific module.
local _M = { _info = _info }
-- Cache library functions.
local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
local assert, setmetatable = assert, setmetatable
local _s = string
local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
local match, gmatch = _s.match, _s.gmatch
local concat, sort = table.concat, table.sort
local bit = bit or require("bit")
local band, shl, sar, tohex = bit.band, bit.lshift, bit.arshift, bit.tohex
-- Inherited tables and callbacks.
local g_opt, g_arch
local wline, werror, wfatal, wwarn
-- Action name list.
-- CHECK: Keep this in sync with the C code!
local action_names = {
"STOP", "SECTION", "ESC", "REL_EXT",
"ALIGN", "REL_LG", "LABEL_LG",
"REL_PC", "LABEL_PC", "IMM",
}
-- Maximum number of section buffer positions for dasm_put().
-- CHECK: Keep this in sync with the C code!
local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
-- Action name -> action number.
local map_action = {}
for n,name in ipairs(action_names) do
map_action[name] = n-1
end
-- Action list buffer.
local actlist = {}
-- Argument list for next dasm_put(). Start with offset 0 into action list.
local actargs = { 0 }
-- Current number of section buffer positions for dasm_put().
local secpos = 1
------------------------------------------------------------------------------
-- Dump action names and numbers.
local function dumpactions(out)
out:write("DynASM encoding engine action codes:\n")
for n,name in ipairs(action_names) do
local num = map_action[name]
out:write(format(" %-10s %02X %d\n", name, num, num))
end
out:write("\n")
end
-- Write action list buffer as a huge static C array.
local function writeactions(out, name)
local nn = #actlist
if nn == 0 then nn = 1; actlist[0] = map_action.STOP end
out:write("static const unsigned int ", name, "[", nn, "] = {\n")
for i = 1,nn-1 do
assert(out:write("0x", tohex(actlist[i]), ",\n"))
end
assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n"))
end
------------------------------------------------------------------------------
-- Add word to action list.
local function wputxw(n)
assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
actlist[#actlist+1] = n
end
-- Add action to list with optional arg. Advance buffer pos, too.
local function waction(action, val, a, num)
local w = assert(map_action[action], "bad action name `"..action.."'")
wputxw(0xff000000 + w * 0x10000 + (val or 0))
if a then actargs[#actargs+1] = a end
if a or num then secpos = secpos + (num or 1) end
end
-- Flush action list (intervening C code or buffer pos overflow).
local function wflush(term)
if #actlist == actargs[1] then return end -- Nothing to flush.
if not term then waction("STOP") end -- Terminate action list.
wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true)
actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
secpos = 1 -- The actionlist offset occupies a buffer position, too.
end
-- Put escaped word.
local function wputw(n)
if n >= 0xff000000 then waction("ESC") end
wputxw(n)
end
-- Reserve position for word.
local function wpos()
local pos = #actlist+1
actlist[pos] = ""
return pos
end
-- Store word to reserved position.
local function wputpos(pos, n)
assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
actlist[pos] = n
end
------------------------------------------------------------------------------
-- Global label name -> global label number. With auto assignment on 1st use.
local next_global = 20
local map_global = setmetatable({}, { __index = function(t, name)
if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end
local n = next_global
if n > 2047 then werror("too many global labels") end
next_global = n + 1
t[name] = n
return n
end})
-- Dump global labels.
local function dumpglobals(out, lvl)
local t = {}
for name, n in pairs(map_global) do t[n] = name end
out:write("Global labels:\n")
for i=20,next_global-1 do
out:write(format(" %s\n", t[i]))
end
out:write("\n")
end
-- Write global label enum.
local function writeglobals(out, prefix)
local t = {}
for name, n in pairs(map_global) do t[n] = name end
out:write("enum {\n")
for i=20,next_global-1 do
out:write(" ", prefix, t[i], ",\n")
end
out:write(" ", prefix, "_MAX\n};\n")
end
-- Write global label names.
local function writeglobalnames(out, name)
local t = {}
for name, n in pairs(map_global) do t[n] = name end
out:write("static const char *const ", name, "[] = {\n")
for i=20,next_global-1 do
out:write(" \"", t[i], "\",\n")
end
out:write(" (const char *)0\n};\n")
end
------------------------------------------------------------------------------
-- Extern label name -> extern label number. With auto assignment on 1st use.
local next_extern = 0
local map_extern_ = {}
local map_extern = setmetatable({}, { __index = function(t, name)
-- No restrictions on the name for now.
local n = next_extern
if n > 2047 then werror("too many extern labels") end
next_extern = n + 1
t[name] = n
map_extern_[n] = name
return n
end})
-- Dump extern labels.
local function dumpexterns(out, lvl)
out:write("Extern labels:\n")
for i=0,next_extern-1 do
out:write(format(" %s\n", map_extern_[i]))
end
out:write("\n")
end
-- Write extern label names.
local function writeexternnames(out, name)
out:write("static const char *const ", name, "[] = {\n")
for i=0,next_extern-1 do
out:write(" \"", map_extern_[i], "\",\n")
end
out:write(" (const char *)0\n};\n")
end
------------------------------------------------------------------------------
-- Arch-specific maps.
local map_archdef = { sp="r29", ra="r31" } -- Ext. register name -> int. name.
local map_type = {} -- Type name -> { ctype, reg }
local ctypenum = 0 -- Type number (for Dt... macros).
-- Reverse defines for registers.
function _M.revdef(s)
if s == "r29" then return "sp"
elseif s == "r31" then return "ra" end
return s
end
------------------------------------------------------------------------------
-- Template strings for MIPS instructions.
local map_op = {
-- First-level opcodes.
j_1 = "08000000J",
jal_1 = "0c000000J",
b_1 = "10000000B",
beqz_2 = "10000000SB",
beq_3 = "10000000STB",
bnez_2 = "14000000SB",
bne_3 = "14000000STB",
blez_2 = "18000000SB",
bgtz_2 = "1c000000SB",
addi_3 = "20000000TSI",
li_2 = "24000000TI",
addiu_3 = "24000000TSI",
slti_3 = "28000000TSI",
sltiu_3 = "2c000000TSI",
andi_3 = "30000000TSU",
lu_2 = "34000000TU",
ori_3 = "34000000TSU",
xori_3 = "38000000TSU",
lui_2 = "3c000000TU",
beqzl_2 = "50000000SB",
beql_3 = "50000000STB",
bnezl_2 = "54000000SB",
bnel_3 = "54000000STB",
blezl_2 = "58000000SB",
bgtzl_2 = "5c000000SB",
lb_2 = "80000000TO",
lh_2 = "84000000TO",
lwl_2 = "88000000TO",
lw_2 = "8c000000TO",
lbu_2 = "90000000TO",
lhu_2 = "94000000TO",
lwr_2 = "98000000TO",
sb_2 = "a0000000TO",
sh_2 = "a4000000TO",
swl_2 = "a8000000TO",
sw_2 = "ac000000TO",
swr_2 = "b8000000TO",
cache_2 = "bc000000NO",
ll_2 = "c0000000TO",
lwc1_2 = "c4000000HO",
pref_2 = "cc000000NO",
ldc1_2 = "d4000000HO",
sc_2 = "e0000000TO",
swc1_2 = "e4000000HO",
sdc1_2 = "f4000000HO",
-- Opcode SPECIAL.
nop_0 = "00000000",
sll_3 = "00000000DTA",
movf_2 = "00000001DS",
movf_3 = "00000001DSC",
movt_2 = "00010001DS",
movt_3 = "00010001DSC",
srl_3 = "00000002DTA",
rotr_3 = "00200002DTA",
sra_3 = "00000003DTA",
sllv_3 = "00000004DTS",
srlv_3 = "00000006DTS",
rotrv_3 = "00000046DTS",
srav_3 = "00000007DTS",
jr_1 = "00000008S",
jalr_1 = "0000f809S",
jalr_2 = "00000009DS",
movz_3 = "0000000aDST",
movn_3 = "0000000bDST",
syscall_0 = "0000000c",
syscall_1 = "0000000cY",
break_0 = "0000000d",
break_1 = "0000000dY",
sync_0 = "0000000f",
mfhi_1 = "00000010D",
mthi_1 = "00000011S",
mflo_1 = "00000012D",
mtlo_1 = "00000013S",
mult_2 = "00000018ST",
multu_2 = "00000019ST",
div_2 = "0000001aST",
divu_2 = "0000001bST",
add_3 = "00000020DST",
move_2 = "00000021DS",
addu_3 = "00000021DST",
sub_3 = "00000022DST",
negu_2 = "00000023DT",
subu_3 = "00000023DST",
and_3 = "00000024DST",
or_3 = "00000025DST",
xor_3 = "00000026DST",
not_2 = "00000027DS",
nor_3 = "00000027DST",
slt_3 = "0000002aDST",
sltu_3 = "0000002bDST",
tge_2 = "00000030ST",
tge_3 = "00000030STZ",
tgeu_2 = "00000031ST",
tgeu_3 = "00000031STZ",
tlt_2 = "00000032ST",
tlt_3 = "00000032STZ",
tltu_2 = "00000033ST",
tltu_3 = "00000033STZ",
teq_2 = "00000034ST",
teq_3 = "00000034STZ",
tne_2 = "00000036ST",
tne_3 = "00000036STZ",
-- Opcode REGIMM.
bltz_2 = "04000000SB",
bgez_2 = "04010000SB",
bltzl_2 = "04020000SB",
bgezl_2 = "04030000SB",
tgei_2 = "04080000SI",
tgeiu_2 = "04090000SI",
tlti_2 = "040a0000SI",
tltiu_2 = "040b0000SI",
teqi_2 = "040c0000SI",
tnei_2 = "040e0000SI",
bltzal_2 = "04100000SB",
bal_1 = "04110000B",
bgezal_2 = "04110000SB",
bltzall_2 = "04120000SB",
bgezall_2 = "04130000SB",
synci_1 = "041f0000O",
-- Opcode SPECIAL2.
madd_2 = "70000000ST",
maddu_2 = "70000001ST",
mul_3 = "70000002DST",
msub_2 = "70000004ST",
msubu_2 = "70000005ST",
clz_2 = "70000020DS=",
clo_2 = "70000021DS=",
sdbbp_0 = "7000003f",
sdbbp_1 = "7000003fY",
-- Opcode SPECIAL3.
ext_4 = "7c000000TSAM", -- Note: last arg is msbd = size-1
ins_4 = "7c000004TSAM", -- Note: last arg is msb = pos+size-1
wsbh_2 = "7c0000a0DT",
seb_2 = "7c000420DT",
seh_2 = "7c000620DT",
rdhwr_2 = "7c00003bTD",
-- Opcode COP0.
mfc0_2 = "40000000TD",
mfc0_3 = "40000000TDW",
mtc0_2 = "40800000TD",
mtc0_3 = "40800000TDW",
rdpgpr_2 = "41400000DT",
di_0 = "41606000",
di_1 = "41606000T",
ei_0 = "41606020",
ei_1 = "41606020T",
wrpgpr_2 = "41c00000DT",
tlbr_0 = "42000001",
tlbwi_0 = "42000002",
tlbwr_0 = "42000006",
tlbp_0 = "42000008",
eret_0 = "42000018",
deret_0 = "4200001f",
wait_0 = "42000020",
-- Opcode COP1.
mfc1_2 = "44000000TG",
cfc1_2 = "44400000TG",
mfhc1_2 = "44600000TG",
mtc1_2 = "44800000TG",
ctc1_2 = "44c00000TG",
mthc1_2 = "44e00000TG",
bc1f_1 = "45000000B",
bc1f_2 = "45000000CB",
bc1t_1 = "45010000B",
bc1t_2 = "45010000CB",
bc1fl_1 = "45020000B",
bc1fl_2 = "45020000CB",
bc1tl_1 = "45030000B",
bc1tl_2 = "45030000CB",
["add.s_3"] = "46000000FGH",
["sub.s_3"] = "46000001FGH",
["mul.s_3"] = "46000002FGH",
["div.s_3"] = "46000003FGH",
["sqrt.s_2"] = "46000004FG",
["abs.s_2"] = "46000005FG",
["mov.s_2"] = "46000006FG",
["neg.s_2"] = "46000007FG",
["round.l.s_2"] = "46000008FG",
["trunc.l.s_2"] = "46000009FG",
["ceil.l.s_2"] = "4600000aFG",
["floor.l.s_2"] = "4600000bFG",
["round.w.s_2"] = "4600000cFG",
["trunc.w.s_2"] = "4600000dFG",
["ceil.w.s_2"] = "4600000eFG",
["floor.w.s_2"] = "4600000fFG",
["movf.s_2"] = "46000011FG",
["movf.s_3"] = "46000011FGC",
["movt.s_2"] = "46010011FG",
["movt.s_3"] = "46010011FGC",
["movz.s_3"] = "46000012FGT",
["movn.s_3"] = "46000013FGT",
["recip.s_2"] = "46000015FG",
["rsqrt.s_2"] = "46000016FG",
["cvt.d.s_2"] = "46000021FG",
["cvt.w.s_2"] = "46000024FG",
["cvt.l.s_2"] = "46000025FG",
["cvt.ps.s_3"] = "46000026FGH",
["c.f.s_2"] = "46000030GH",
["c.f.s_3"] = "46000030VGH",
["c.un.s_2"] = "46000031GH",
["c.un.s_3"] = "46000031VGH",
["c.eq.s_2"] = "46000032GH",
["c.eq.s_3"] = "46000032VGH",
["c.ueq.s_2"] = "46000033GH",
["c.ueq.s_3"] = "46000033VGH",
["c.olt.s_2"] = "46000034GH",
["c.olt.s_3"] = "46000034VGH",
["c.ult.s_2"] = "46000035GH",
["c.ult.s_3"] = "46000035VGH",
["c.ole.s_2"] = "46000036GH",
["c.ole.s_3"] = "46000036VGH",
["c.ule.s_2"] = "46000037GH",
["c.ule.s_3"] = "46000037VGH",
["c.sf.s_2"] = "46000038GH",
["c.sf.s_3"] = "46000038VGH",
["c.ngle.s_2"] = "46000039GH",
["c.ngle.s_3"] = "46000039VGH",
["c.seq.s_2"] = "4600003aGH",
["c.seq.s_3"] = "4600003aVGH",
["c.ngl.s_2"] = "4600003bGH",
["c.ngl.s_3"] = "4600003bVGH",
["c.lt.s_2"] = "4600003cGH",
["c.lt.s_3"] = "4600003cVGH",
["c.nge.s_2"] = "4600003dGH",
["c.nge.s_3"] = "4600003dVGH",
["c.le.s_2"] = "4600003eGH",
["c.le.s_3"] = "4600003eVGH",
["c.ngt.s_2"] = "4600003fGH",
["c.ngt.s_3"] = "4600003fVGH",
["add.d_3"] = "46200000FGH",
["sub.d_3"] = "46200001FGH",
["mul.d_3"] = "46200002FGH",
["div.d_3"] = "46200003FGH",
["sqrt.d_2"] = "46200004FG",
["abs.d_2"] = "46200005FG",
["mov.d_2"] = "46200006FG",
["neg.d_2"] = "46200007FG",
["round.l.d_2"] = "46200008FG",
["trunc.l.d_2"] = "46200009FG",
["ceil.l.d_2"] = "4620000aFG",
["floor.l.d_2"] = "4620000bFG",
["round.w.d_2"] = "4620000cFG",
["trunc.w.d_2"] = "4620000dFG",
["ceil.w.d_2"] = "4620000eFG",
["floor.w.d_2"] = "4620000fFG",
["movf.d_2"] = "46200011FG",
["movf.d_3"] = "46200011FGC",
["movt.d_2"] = "46210011FG",
["movt.d_3"] = "46210011FGC",
["movz.d_3"] = "46200012FGT",
["movn.d_3"] = "46200013FGT",
["recip.d_2"] = "46200015FG",
["rsqrt.d_2"] = "46200016FG",
["cvt.s.d_2"] = "46200020FG",
["cvt.w.d_2"] = "46200024FG",
["cvt.l.d_2"] = "46200025FG",
["c.f.d_2"] = "46200030GH",
["c.f.d_3"] = "46200030VGH",
["c.un.d_2"] = "46200031GH",
["c.un.d_3"] = "46200031VGH",
["c.eq.d_2"] = "46200032GH",
["c.eq.d_3"] = "46200032VGH",
["c.ueq.d_2"] = "46200033GH",
["c.ueq.d_3"] = "46200033VGH",
["c.olt.d_2"] = "46200034GH",
["c.olt.d_3"] = "46200034VGH",
["c.ult.d_2"] = "46200035GH",
["c.ult.d_3"] = "46200035VGH",
["c.ole.d_2"] = "46200036GH",
["c.ole.d_3"] = "46200036VGH",
["c.ule.d_2"] = "46200037GH",
["c.ule.d_3"] = "46200037VGH",
["c.sf.d_2"] = "46200038GH",
["c.sf.d_3"] = "46200038VGH",
["c.ngle.d_2"] = "46200039GH",
["c.ngle.d_3"] = "46200039VGH",
["c.seq.d_2"] = "4620003aGH",
["c.seq.d_3"] = "4620003aVGH",
["c.ngl.d_2"] = "4620003bGH",
["c.ngl.d_3"] = "4620003bVGH",
["c.lt.d_2"] = "4620003cGH",
["c.lt.d_3"] = "4620003cVGH",
["c.nge.d_2"] = "4620003dGH",
["c.nge.d_3"] = "4620003dVGH",
["c.le.d_2"] = "4620003eGH",
["c.le.d_3"] = "4620003eVGH",
["c.ngt.d_2"] = "4620003fGH",
["c.ngt.d_3"] = "4620003fVGH",
["add.ps_3"] = "46c00000FGH",
["sub.ps_3"] = "46c00001FGH",
["mul.ps_3"] = "46c00002FGH",
["abs.ps_2"] = "46c00005FG",
["mov.ps_2"] = "46c00006FG",
["neg.ps_2"] = "46c00007FG",
["movf.ps_2"] = "46c00011FG",
["movf.ps_3"] = "46c00011FGC",
["movt.ps_2"] = "46c10011FG",
["movt.ps_3"] = "46c10011FGC",
["movz.ps_3"] = "46c00012FGT",
["movn.ps_3"] = "46c00013FGT",
["cvt.s.pu_2"] = "46c00020FG",
["cvt.s.pl_2"] = "46c00028FG",
["pll.ps_3"] = "46c0002cFGH",
["plu.ps_3"] = "46c0002dFGH",
["pul.ps_3"] = "46c0002eFGH",
["puu.ps_3"] = "46c0002fFGH",
["c.f.ps_2"] = "46c00030GH",
["c.f.ps_3"] = "46c00030VGH",
["c.un.ps_2"] = "46c00031GH",
["c.un.ps_3"] = "46c00031VGH",
["c.eq.ps_2"] = "46c00032GH",
["c.eq.ps_3"] = "46c00032VGH",
["c.ueq.ps_2"] = "46c00033GH",
["c.ueq.ps_3"] = "46c00033VGH",
["c.olt.ps_2"] = "46c00034GH",
["c.olt.ps_3"] = "46c00034VGH",
["c.ult.ps_2"] = "46c00035GH",
["c.ult.ps_3"] = "46c00035VGH",
["c.ole.ps_2"] = "46c00036GH",
["c.ole.ps_3"] = "46c00036VGH",
["c.ule.ps_2"] = "46c00037GH",
["c.ule.ps_3"] = "46c00037VGH",
["c.sf.ps_2"] = "46c00038GH",
["c.sf.ps_3"] = "46c00038VGH",
["c.ngle.ps_2"] = "46c00039GH",
["c.ngle.ps_3"] = "46c00039VGH",
["c.seq.ps_2"] = "46c0003aGH",
["c.seq.ps_3"] = "46c0003aVGH",
["c.ngl.ps_2"] = "46c0003bGH",
["c.ngl.ps_3"] = "46c0003bVGH",
["c.lt.ps_2"] = "46c0003cGH",
["c.lt.ps_3"] = "46c0003cVGH",
["c.nge.ps_2"] = "46c0003dGH",
["c.nge.ps_3"] = "46c0003dVGH",
["c.le.ps_2"] = "46c0003eGH",
["c.le.ps_3"] = "46c0003eVGH",
["c.ngt.ps_2"] = "46c0003fGH",
["c.ngt.ps_3"] = "46c0003fVGH",
["cvt.s.w_2"] = "46800020FG",
["cvt.d.w_2"] = "46800021FG",
["cvt.s.l_2"] = "46a00020FG",
["cvt.d.l_2"] = "46a00021FG",
-- Opcode COP1X.
lwxc1_2 = "4c000000FX",
ldxc1_2 = "4c000001FX",
luxc1_2 = "4c000005FX",
swxc1_2 = "4c000008FX",
sdxc1_2 = "4c000009FX",
suxc1_2 = "4c00000dFX",
prefx_2 = "4c00000fMX",
["alnv.ps_4"] = "4c00001eFGHS",
["madd.s_4"] = "4c000020FRGH",
["madd.d_4"] = "4c000021FRGH",
["madd.ps_4"] = "4c000026FRGH",
["msub.s_4"] = "4c000028FRGH",
["msub.d_4"] = "4c000029FRGH",
["msub.ps_4"] = "4c00002eFRGH",
["nmadd.s_4"] = "4c000030FRGH",
["nmadd.d_4"] = "4c000031FRGH",
["nmadd.ps_4"] = "4c000036FRGH",
["nmsub.s_4"] = "4c000038FRGH",
["nmsub.d_4"] = "4c000039FRGH",
["nmsub.ps_4"] = "4c00003eFRGH",
}
------------------------------------------------------------------------------
local function parse_gpr(expr)
local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$")
local tp = map_type[tname or expr]
if tp then
local reg = ovreg or tp.reg
if not reg then
werror("type `"..(tname or expr).."' needs a register override")
end
expr = reg
end
local r = match(expr, "^r([1-3]?[0-9])$")
if r then
r = tonumber(r)
if r <= 31 then return r, tp end
end
werror("bad register name `"..expr.."'")
end
local function parse_fpr(expr)
local r = match(expr, "^f([1-3]?[0-9])$")
if r then
r = tonumber(r)
if r <= 31 then return r end
end
werror("bad register name `"..expr.."'")
end
local function parse_imm(imm, bits, shift, scale, signed)
local n = tonumber(imm)
if n then
local m = sar(n, scale)
if shl(m, scale) == n then
if signed then
local s = sar(m, bits-1)
if s == 0 then return shl(m, shift)
elseif s == -1 then return shl(m + shl(1, bits), shift) end
else
if sar(m, bits) == 0 then return shl(m, shift) end
end
end
werror("out of range immediate `"..imm.."'")
elseif match(imm, "^[rf]([1-3]?[0-9])$") or
match(imm, "^([%w_]+):([rf][1-3]?[0-9])$") then
werror("expected immediate operand, got register")
else
waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm)
return 0
end
end
local function parse_disp(disp)
local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$")
if imm then
local r = shl(parse_gpr(reg), 21)
local extname = match(imm, "^extern%s+(%S+)$")
if extname then
waction("REL_EXT", map_extern[extname], nil, 1)
return r
else
return r + parse_imm(imm, 16, 0, 0, true)
end
end
local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$")
if reg and tailr ~= "" then
local r, tp = parse_gpr(reg)
if tp then
waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr))
return shl(r, 21)
end
end
werror("bad displacement `"..disp.."'")
end
local function parse_index(idx)
local rt, rs = match(idx, "^(.*)%(([%w_:]+)%)$")
if rt then
rt = parse_gpr(rt)
rs = parse_gpr(rs)
return shl(rt, 16) + shl(rs, 21)
end
werror("bad index `"..idx.."'")
end
local function parse_label(label, def)
local prefix = sub(label, 1, 2)
-- =>label (pc label reference)
if prefix == "=>" then
return "PC", 0, sub(label, 3)
end
-- ->name (global label reference)
if prefix == "->" then
return "LG", map_global[sub(label, 3)]
end
if def then
-- [1-9] (local label definition)
if match(label, "^[1-9]$") then
return "LG", 10+tonumber(label)
end
else
-- [<>][1-9] (local label reference)
local dir, lnum = match(label, "^([<>])([1-9])$")
if dir then -- Fwd: 1-9, Bkwd: 11-19.
return "LG", lnum + (dir == ">" and 0 or 10)
end
-- extern label (extern label reference)
local extname = match(label, "^extern%s+(%S+)$")
if extname then
return "EXT", map_extern[extname]
end
end
werror("bad label `"..label.."'")
end
------------------------------------------------------------------------------
-- Handle opcodes defined with template strings.
map_op[".template__"] = function(params, template, nparams)
if not params then return sub(template, 9) end
local op = tonumber(sub(template, 1, 8), 16)
local n = 1
-- Limit number of section buffer positions used by a single dasm_put().
-- A single opcode needs a maximum of 2 positions (ins/ext).
if secpos+2 > maxsecpos then wflush() end
local pos = wpos()
-- Process each character.
for p in gmatch(sub(template, 9), ".") do
if p == "D" then
op = op + shl(parse_gpr(params[n]), 11); n = n + 1
elseif p == "T" then
op = op + shl(parse_gpr(params[n]), 16); n = n + 1
elseif p == "S" then
op = op + shl(parse_gpr(params[n]), 21); n = n + 1
elseif p == "F" then
op = op + shl(parse_fpr(params[n]), 6); n = n + 1
elseif p == "G" then
op = op + shl(parse_fpr(params[n]), 11); n = n + 1
elseif p == "H" then
op = op + shl(parse_fpr(params[n]), 16); n = n + 1
elseif p == "R" then
op = op + shl(parse_fpr(params[n]), 21); n = n + 1
elseif p == "I" then
op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1
elseif p == "U" then
op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1
elseif p == "O" then
op = op + parse_disp(params[n]); n = n + 1
elseif p == "X" then
op = op + parse_index(params[n]); n = n + 1
elseif p == "B" or p == "J" then
local mode, n, s = parse_label(params[n], false)
if p == "B" then n = n + 2048 end
waction("REL_"..mode, n, s, 1)
n = n + 1
elseif p == "A" then
op = op + parse_imm(params[n], 5, 6, 0, false); n = n + 1
elseif p == "M" then
op = op + parse_imm(params[n], 5, 11, 0, false); n = n + 1
elseif p == "N" then
op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1
elseif p == "C" then
op = op + parse_imm(params[n], 3, 18, 0, false); n = n + 1
elseif p == "V" then
op = op + parse_imm(params[n], 3, 8, 0, false); n = n + 1
elseif p == "W" then
op = op + parse_imm(params[n], 3, 0, 0, false); n = n + 1
elseif p == "Y" then
op = op + parse_imm(params[n], 20, 6, 0, false); n = n + 1
elseif p == "Z" then
op = op + parse_imm(params[n], 10, 6, 0, false); n = n + 1
elseif p == "=" then
op = op + shl(band(op, 0xf800), 5) -- Copy D to T for clz, clo.
else
assert(false)
end
end
wputpos(pos, op)
end
------------------------------------------------------------------------------
-- Pseudo-opcode to mark the position where the action list is to be emitted.
map_op[".actionlist_1"] = function(params)
if not params then return "cvar" end
local name = params[1] -- No syntax check. You get to keep the pieces.
wline(function(out) writeactions(out, name) end)
end
-- Pseudo-opcode to mark the position where the global enum is to be emitted.
map_op[".globals_1"] = function(params)
if not params then return "prefix" end
local prefix = params[1] -- No syntax check. You get to keep the pieces.
wline(function(out) writeglobals(out, prefix) end)
end
-- Pseudo-opcode to mark the position where the global names are to be emitted.
map_op[".globalnames_1"] = function(params)
if not params then return "cvar" end
local name = params[1] -- No syntax check. You get to keep the pieces.
wline(function(out) writeglobalnames(out, name) end)
end
-- Pseudo-opcode to mark the position where the extern names are to be emitted.
map_op[".externnames_1"] = function(params)
if not params then return "cvar" end
local name = params[1] -- No syntax check. You get to keep the pieces.
wline(function(out) writeexternnames(out, name) end)
end
------------------------------------------------------------------------------
-- Label pseudo-opcode (converted from trailing colon form).
map_op[".label_1"] = function(params)
if not params then return "[1-9] | ->global | =>pcexpr" end
if secpos+1 > maxsecpos then wflush() end
local mode, n, s = parse_label(params[1], true)
if mode == "EXT" then werror("bad label definition") end
waction("LABEL_"..mode, n, s, 1)
end
------------------------------------------------------------------------------
-- Pseudo-opcodes for data storage.
map_op[".long_*"] = function(params)
if not params then return "imm..." end
for _,p in ipairs(params) do
local n = tonumber(p)
if not n then werror("bad immediate `"..p.."'") end
if n < 0 then n = n + 2^32 end
wputw(n)
if secpos+2 > maxsecpos then wflush() end
end
end
-- Alignment pseudo-opcode.
map_op[".align_1"] = function(params)
if not params then return "numpow2" end
if secpos+1 > maxsecpos then wflush() end
local align = tonumber(params[1])
if align then
local x = align
-- Must be a power of 2 in the range (2 ... 256).
for i=1,8 do
x = x / 2
if x == 1 then
waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1.
return
end
end
end
werror("bad alignment")
end
------------------------------------------------------------------------------
-- Pseudo-opcode for (primitive) type definitions (map to C types).
map_op[".type_3"] = function(params, nparams)
if not params then
return nparams == 2 and "name, ctype" or "name, ctype, reg"
end
local name, ctype, reg = params[1], params[2], params[3]
if not match(name, "^[%a_][%w_]*$") then
werror("bad type name `"..name.."'")
end
local tp = map_type[name]
if tp then
werror("duplicate type `"..name.."'")
end
-- Add #type to defines. A bit unclean to put it in map_archdef.
map_archdef["#"..name] = "sizeof("..ctype..")"
-- Add new type and emit shortcut define.
local num = ctypenum + 1
map_type[name] = {
ctype = ctype,
ctypefmt = format("Dt%X(%%s)", num),
reg = reg,
}
wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
ctypenum = num
end
map_op[".type_2"] = map_op[".type_3"]
-- Dump type definitions.
local function dumptypes(out, lvl)
local t = {}
for name in pairs(map_type) do t[#t+1] = name end
sort(t)
out:write("Type definitions:\n")
for _,name in ipairs(t) do
local tp = map_type[name]
local reg = tp.reg or ""
out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg))
end
out:write("\n")
end
------------------------------------------------------------------------------
-- Set the current section.
function _M.section(num)
waction("SECTION", num)
wflush(true) -- SECTION is a terminal action.
end
------------------------------------------------------------------------------
-- Dump architecture description.
function _M.dumparch(out)
out:write(format("DynASM %s version %s, released %s\n\n",
_info.arch, _info.version, _info.release))
dumpactions(out)
end
-- Dump all user defined elements.
function _M.dumpdef(out, lvl)
dumptypes(out, lvl)
dumpglobals(out, lvl)
dumpexterns(out, lvl)
end
------------------------------------------------------------------------------
-- Pass callbacks from/to the DynASM core.
function _M.passcb(wl, we, wf, ww)
wline, werror, wfatal, wwarn = wl, we, wf, ww
return wflush
end
-- Setup the arch-specific module.
function _M.setup(arch, opt)
g_arch, g_opt = arch, opt
end
-- Merge the core maps and the arch-specific maps.
function _M.mergemaps(map_coreop, map_def)
setmetatable(map_op, { __index = map_coreop })
setmetatable(map_def, { __index = map_archdef })
return map_op, map_def
end
return _M
------------------------------------------------------------------------------
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-676
View File
@@ -1,676 +0,0 @@
##############################################################################
# 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-2012 Mike Pall. See Copyright Notice in luajit.h
##############################################################################
MAJVER= 2
MINVER= 0
RELVER= 0
ABIVER= 5.1
NODOTABIVER= 51
##############################################################################
############################# COMPILER OPTIONS #############################
##############################################################################
# These options mainly affect the speed of the JIT compiler itself, not the
# speed of the JIT-compiled code. Turn any of the optional settings on by
# removing the '#' in front of them. Make sure you force a full recompile
# with "make clean", followed by "make" if you change any options.
#
# LuaJIT builds as a native 32 or 64 bit binary by default.
CC= gcc
#
# Use this if you want to force a 32 bit build on a 64 bit multilib OS.
#CC= gcc -m32
#
# Since the assembler part does NOT maintain a frame pointer, it's pointless
# to slow down the C part by not omitting it. Debugging, tracebacks and
# unwinding are not affected -- the assembler part has frame unwind
# information and GCC emits it where needed (x64) or with -g (see CCDEBUG).
CCOPT= -O2 -fomit-frame-pointer
# Use this if you want to generate a smaller binary (but it's slower):
#CCOPT= -Os -fomit-frame-pointer
# Note: it's no longer recommended to use -O3 with GCC 4.x.
# The I-Cache bloat usually outweighs the benefits from aggressive inlining.
#
# Target-specific compiler options:
#
# x86 only: it's recommended to compile at least for i686. Better yet,
# compile for an architecture that has SSE2, too (-msse -msse2).
#
# x86/x64 only: For GCC 4.2 or higher and if you don't intend to distribute
# the binaries to a different machine you could also use: -march=native
#
CCOPT_x86= -march=i686
CCOPT_x64=
CCOPT_arm=
CCOPT_ppc=
CCOPT_ppcspe=
CCOPT_mips=
#
CCDEBUG=
# Uncomment the next line to generate debug information:
#CCDEBUG= -g
#
CCWARN= -Wall
# Uncomment the next line to enable more warnings:
#CCWARN+= -Wextra -Wdeclaration-after-statement -Wredundant-decls -Wshadow -Wpointer-arith
#
##############################################################################
##############################################################################
################################ BUILD MODE ################################
##############################################################################
# The default build mode is mixed mode on POSIX. On Windows this is the same
# as dynamic mode.
#
# Mixed mode creates a static + dynamic library and a statically linked luajit.
BUILDMODE= mixed
#
# Static mode creates a static library and a statically linked luajit.
#BUILDMODE= static
#
# Dynamic mode creates a dynamic library and a dynamically linked luajit.
# Note: this executable will only run when the library is installed!
#BUILDMODE= dynamic
#
##############################################################################
##############################################################################
################################# FEATURES #################################
##############################################################################
# Enable/disable these features as needed, but make sure you force a full
# recompile with "make clean", followed by "make".
XCFLAGS=
#
# Permanently disable the FFI extension to reduce the size of the LuaJIT
# executable. But please consider that the FFI library is compiled-in,
# but NOT loaded by default. It only allocates any memory, if you actually
# make use of it.
#XCFLAGS+= -DLUAJIT_DISABLE_FFI
#
# Features from Lua 5.2 that are unlikely to break existing code are
# enabled by default. Some other features that *might* break some existing
# code (e.g. __pairs or os.execute() return values) can be enabled here.
# Note: this does not provide full compatibility with Lua 5.2 at this time.
#XCFLAGS+= -DLUAJIT_ENABLE_LUA52COMPAT
#
# Disable the JIT compiler, i.e. turn LuaJIT into a pure interpreter.
#XCFLAGS+= -DLUAJIT_DISABLE_JIT
#
# Some architectures (e.g. PPC) can use either single-number (1) or
# dual-number (2) mode. Uncomment one of these lines to override the
# default mode. Please see LJ_ARCH_NUMMODE in lj_arch.h for details.
#XCFLAGS+= -DLUAJIT_NUMMODE=1
#XCFLAGS+= -DLUAJIT_NUMMODE=2
#
##############################################################################
##############################################################################
############################ DEBUGGING SUPPORT #############################
##############################################################################
# Enable these options as needed, but make sure you force a full recompile
# with "make clean", followed by "make".
# Note that most of these are NOT suitable for benchmarking or release mode!
#
# Use the system provided memory allocator (realloc) instead of the
# bundled memory allocator. This is slower, but sometimes helpful for
# debugging. It's helpful for Valgrind's memcheck tool, too. This option
# cannot be enabled on x64, since the built-in allocator is mandatory.
#XCFLAGS+= -DLUAJIT_USE_SYSMALLOC
#
# This define is required to run LuaJIT under Valgrind. The Valgrind
# header files must be installed. You should enable debug information, too.
# Use --suppressions=lj.supp to avoid some false positives.
#XCFLAGS+= -DLUAJIT_USE_VALGRIND
#
# This is the client for the GDB JIT API. GDB 7.0 or higher is required
# to make use of it. See lj_gdbjit.c for details. Enabling this causes
# a non-negligible overhead, even when not running under GDB.
#XCFLAGS+= -DLUAJIT_USE_GDBJIT
#
# Turn on assertions for the Lua/C API to debug problems with lua_* calls.
# This is rather slow -- use only while developing C libraries/embeddings.
#XCFLAGS+= -DLUA_USE_APICHECK
#
# Turn on assertions for the whole LuaJIT VM. This significantly slows down
# everything. Use only if you suspect a problem with LuaJIT itself.
#XCFLAGS+= -DLUA_USE_ASSERT
#
##############################################################################
# You probably don't need to change anything below this line!
##############################################################################
##############################################################################
# Flags and options for host and target.
##############################################################################
# You can override the following variables at the make command line:
# CC HOST_CC STATIC_CC DYNAMIC_CC
# CFLAGS HOST_CFLAGS TARGET_CFLAGS
# LDFLAGS HOST_LDFLAGS TARGET_LDFLAGS TARGET_SHLDFLAGS
# LIBS HOST_LIBS TARGET_LIBS
# CROSS HOST_SYS TARGET_SYS TARGET_FLAGS
#
# Cross-compilation examples:
# make HOST_CC="gcc -m32" CROSS=i586-mingw32msvc- TARGET_SYS=Windows
# make HOST_CC="gcc -m32" CROSS=powerpc-linux-gnu-
CCOPTIONS= $(CCDEBUG) $(CCOPT) $(CCWARN) $(XCFLAGS) $(CFLAGS)
LDOPTIONS= $(CCDEBUG) $(LDFLAGS)
HOST_CC= $(CC)
HOST_RM= rm -f
# If left blank, minilua is built and used. You can supply an installed
# copy of (plain) Lua 5.1 or 5.2, plus Lua BitOp. E.g. with: HOST_LUA=lua
HOST_LUA=
HOST_XCFLAGS= -I.
HOST_XLDFLAGS=
HOST_XLIBS=
HOST_ACFLAGS= $(CCOPTIONS) $(HOST_XCFLAGS) $(TARGET_ARCH) $(HOST_CFLAGS)
HOST_ALDFLAGS= $(LDOPTIONS) $(HOST_XLDFLAGS) $(HOST_LDFLAGS)
HOST_ALIBS= $(HOST_XLIBS) $(LIBS) $(HOST_LIBS)
STATIC_CC = $(CROSS)$(CC)
DYNAMIC_CC = $(CROSS)$(CC) -fPIC
TARGET_CC= $(STATIC_CC)
TARGET_STCC= $(STATIC_CC)
TARGET_DYNCC= $(DYNAMIC_CC)
TARGET_LD= $(CROSS)$(CC)
TARGET_AR= $(CROSS)ar rcus
TARGET_STRIP= $(CROSS)strip
TARGET_SONAME= libluajit.so
TARGET_DYLIBNAME= libluajit-$(ABIVER).$(MAJVER).dylib
TARGET_DYLIBPATH= $(or $(PREFIX),/usr/local)/lib/$(TARGET_DYLIBNAME)
TARGET_DLLNAME= lua$(NODOTABIVER).dll
TARGET_XSHLDFLAGS= -shared -fPIC -Wl,-soname,$(TARGET_SONAME)
TARGET_DYNXLDOPTS=
TARGET_LFSFLAGS= -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
TARGET_XCFLAGS= $(TARGET_LFSFLAGS) -U_FORTIFY_SOURCE
TARGET_XLDFLAGS=
TARGET_XLIBS= -lm
TARGET_TCFLAGS= $(CCOPTIONS) $(TARGET_XCFLAGS) $(TARGET_FLAGS) $(TARGET_CFLAGS)
TARGET_ACFLAGS= $(CCOPTIONS) $(TARGET_XCFLAGS) $(TARGET_FLAGS) $(TARGET_CFLAGS)
TARGET_ALDFLAGS= $(LDOPTIONS) $(TARGET_XLDFLAGS) $(TARGET_FLAGS) $(TARGET_LDFLAGS)
TARGET_ASHLDFLAGS= $(LDOPTIONS) $(TARGET_XSHLDFLAGS) $(TARGET_FLAGS) $(TARGET_SHLDFLAGS)
TARGET_ALIBS= $(TARGET_XLIBS) $(LIBS) $(TARGET_LIBS)
TARGET_TESTARCH=$(shell $(TARGET_CC) $(TARGET_TCFLAGS) -E 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_PPC ,$(TARGET_TESTARCH)))
TARGET_LJARCH= ppc
else
ifneq (,$(findstring LJ_TARGET_PPCSPE ,$(TARGET_TESTARCH)))
TARGET_LJARCH= ppcspe
else
ifneq (,$(findstring LJ_TARGET_MIPS ,$(TARGET_TESTARCH)))
ifneq (,$(findstring MIPSEL ,$(TARGET_TESTARCH)))
TARGET_ARCH= -D__MIPSEL__=1
endif
TARGET_LJARCH= mips
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
endif
ifneq (,$(findstring LJ_NO_UNWIND 1,$(TARGET_TESTARCH)))
TARGET_ARCH+= -DLUAJIT_NO_UNWIND
endif
TARGET_XCFLAGS+= $(CCOPT_$(TARGET_LJARCH))
TARGET_ARCH+= $(patsubst %,-DLUAJIT_TARGET=LUAJIT_ARCH_%,$(TARGET_LJARCH))
ifneq (,$(PREFIX))
ifneq (/usr/local,$(PREFIX))
TARGET_XCFLAGS+= -DLUA_XROOT=\"$(PREFIX)/\"
ifneq (/usr,$(PREFIX))
TARGET_DYNXLDOPTS= -Wl,-rpath,$(PREFIX)/lib
endif
endif
endif
##############################################################################
# System detection.
##############################################################################
ifeq (Windows,$(findstring Windows,$(OS))$(MSYSTEM)$(TERM))
HOST_SYS= Windows
HOST_RM= del
else
HOST_SYS:= $(shell uname -s)
ifneq (,$(findstring MINGW,$(HOST_SYS)))
HOST_SYS= Windows
HOST_MSYS= mingw
endif
ifneq (,$(findstring CYGWIN,$(HOST_SYS)))
HOST_SYS= Windows
HOST_MSYS= cygwin
endif
endif
TARGET_SYS?= $(HOST_SYS)
ifeq (Windows,$(TARGET_SYS))
TARGET_STRIP+= --strip-unneeded
TARGET_XSHLDFLAGS= -shared
TARGET_DYNXLDOPTS=
else
ifeq (Darwin,$(TARGET_SYS))
ifeq (,$(MACOSX_DEPLOYMENT_TARGET))
export MACOSX_DEPLOYMENT_TARGET=10.4
endif
TARGET_STRIP+= -x
TARGET_AR+= 2>/dev/null
TARGET_XCFLAGS+= -fno-stack-protector
TARGET_XSHLDFLAGS= -dynamiclib -single_module -undefined dynamic_lookup -fPIC
TARGET_DYNXLDOPTS=
TARGET_XSHLDFLAGS+= -install_name $(TARGET_DYLIBPATH) -compatibility_version $(MAJVER).$(MINVER) -current_version $(MAJVER).$(MINVER).$(RELVER)
ifeq (x64,$(TARGET_LJARCH))
TARGET_XLDFLAGS+= -pagezero_size 10000 -image_base 100000000
TARGET_XSHLDFLAGS+= -image_base 7fff04c4a000
endif
else
ifeq (iOS,$(TARGET_SYS))
TARGET_STRIP+= -x
TARGET_AR+= 2>/dev/null
TARGET_XCFLAGS+= -fno-stack-protector
TARGET_XSHLDFLAGS= -dynamiclib -single_module -undefined dynamic_lookup -fPIC
TARGET_DYNXLDOPTS=
TARGET_XSHLDFLAGS+= -install_name $(TARGET_DYLIBPATH) -compatibility_version $(MAJVER).$(MINVER) -current_version $(MAJVER).$(MINVER).$(RELVER)
else
ifneq (,$(findstring stack-protector,$(shell $(TARGET_CC) -dumpspecs)))
TARGET_XCFLAGS+= -fno-stack-protector
endif
ifneq (SunOS,$(TARGET_SYS))
ifneq (PS3,$(TARGET_SYS))
TARGET_XLDFLAGS+= -Wl,-E
endif
endif
ifeq (Linux,$(TARGET_SYS))
TARGET_XLIBS+= -ldl
endif
ifeq (GNU/kFreeBSD,$(TARGET_SYS))
TARGET_XLIBS+= -ldl
endif
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
else
HOST_XCFLAGS+= -DLUAJIT_OS=LUAJIT_OS_OTHER
endif
endif
endif
endif
endif
ifneq (,$(CCDEBUG))
TARGET_STRIP= @:
endif
##############################################################################
# Files and pathnames.
##############################################################################
MINILUA_O= host/minilua.o
MINILUA_LIBS= -lm
MINILUA_T= host/minilua
MINILUA_X= $(MINILUA_T)
ifeq (,$(HOST_LUA))
HOST_LUA= $(MINILUA_X)
DASM_DEP= $(MINILUA_T)
endif
DASM_DIR= ../dynasm
DASM= $(HOST_LUA) $(DASM_DIR)/dynasm.lua
DASM_XFLAGS=
DASM_AFLAGS=
DASM_ARCH= $(TARGET_LJARCH)
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_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
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 (x86,$(TARGET_LJARCH))
ifneq (,$(findstring __SSE2__ 1,$(TARGET_TESTARCH)))
DASM_AFLAGS+= -D SSE
endif
else
ifeq (x64,$(TARGET_LJARCH))
DASM_ARCH= x86
else
ifeq (arm,$(TARGET_LJARCH))
ifeq (iOS,$(TARGET_SYS))
DASM_AFLAGS+= -D IOS
endif
else
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_PPC64 1,$(TARGET_TESTARCH)))
DASM_AFLAGS+= -D GPR64
endif
ifeq (PS3,$(TARGET_SYS))
DASM_AFLAGS+= -D PPE -D TOC
endif
endif
endif
endif
endif
DASM_FLAGS= $(DASM_XFLAGS) $(DASM_AFLAGS)
DASM_DASC= vm_$(DASM_ARCH).dasc
BUILDVM_O= host/buildvm.o host/buildvm_asm.o host/buildvm_peobj.o \
host/buildvm_lib.o host/buildvm_fold.o
BUILDVM_T= host/buildvm
BUILDVM_X= $(BUILDVM_T)
HOST_O= $(MINILUA_O) $(BUILDVM_O)
HOST_T= $(MINILUA_T) $(BUILDVM_T)
LJVM_S= lj_vm.s
LJVM_O= lj_vm.o
LJVM_BOUT= $(LJVM_S)
LJVM_MODE= elfasm
LJLIB_O= lib_base.o lib_math.o lib_bit.o lib_string.o lib_table.o \
lib_io.o lib_os.o lib_package.o lib_debug.o lib_jit.o lib_ffi.o
LJLIB_C= $(LJLIB_O:.o=.c)
LJCORE_O= lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o \
lj_str.o lj_tab.o lj_func.o lj_udata.o lj_meta.o lj_debug.o \
lj_state.o lj_dispatch.o lj_vmevent.o lj_vmmath.o lj_strscan.o \
lj_api.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
LJVMCORE_O= $(LJVM_O) $(LJCORE_O)
LJVMCORE_DYNO= $(LJVMCORE_O:.o=_dyn.o)
LIB_VMDEF= jit/vmdef.lua
LIB_VMDEFP= $(LIB_VMDEF)
LUAJIT_O= luajit.o
LUAJIT_A= libluajit.a
LUAJIT_SO= libluajit.so
LUAJIT_T= luajit
ALL_T= $(LUAJIT_T) $(LUAJIT_A) $(LUAJIT_SO) $(HOST_T)
ALL_HDRGEN= lj_bcdef.h lj_ffdef.h lj_libdef.h lj_recdef.h lj_folddef.h \
host/buildvm_arch.h
ALL_GEN= $(LJVM_S) $(ALL_HDRGEN) $(LIB_VMDEFP)
WIN_RM= *.obj *.lib *.exp *.dll *.exe *.manifest *.pdb *.ilk
ALL_RM= $(ALL_T) $(ALL_GEN) *.o host/*.o $(WIN_RM)
##############################################################################
# Build mode handling.
##############################################################################
# Mixed mode defaults.
TARGET_O= $(LUAJIT_A)
TARGET_T= $(LUAJIT_T) $(LUAJIT_SO)
TARGET_DEP= $(LIB_VMDEF) $(LUAJIT_SO)
ifeq (Windows,$(TARGET_SYS))
TARGET_DYNCC= $(STATIC_CC)
LJVM_MODE= coffasm
LUAJIT_T= luajit.exe
ifeq (cygwin,$(HOST_MSYS))
LUAJIT_SO= cyg$(TARGET_DLLNAME)
else
LUAJIT_SO= $(TARGET_DLLNAME)
endif
# Mixed mode is not supported on Windows. And static mode doesn't work well.
# C modules cannot be loaded, because they bind to lua51.dll.
ifneq (static,$(BUILDMODE))
BUILDMODE= dynamic
TARGET_XCFLAGS+= -DLUA_BUILD_AS_DLL
endif
endif
ifeq (Darwin,$(TARGET_SYS))
LJVM_MODE= machasm
endif
ifeq (iOS,$(TARGET_SYS))
LJVM_MODE= machasm
endif
ifeq (SunOS,$(TARGET_SYS))
BUILDMODE= static
endif
ifeq (PS3,$(TARGET_SYS))
BUILDMODE= static
endif
ifeq (Windows,$(HOST_SYS))
MINILUA_T= host/minilua.exe
BUILDVM_T= host/buildvm.exe
ifeq (,$(HOST_MSYS))
MINILUA_X= host\minilua
BUILDVM_X= host\buildvm
ALL_RM:= $(subst /,\,$(ALL_RM))
endif
endif
ifeq (static,$(BUILDMODE))
TARGET_DYNCC= @:
TARGET_T= $(LUAJIT_T)
TARGET_DEP= $(LIB_VMDEF)
else
ifeq (dynamic,$(BUILDMODE))
ifneq (Windows,$(TARGET_SYS))
TARGET_CC= $(DYNAMIC_CC)
endif
TARGET_DYNCC= @:
LJVMCORE_DYNO= $(LJVMCORE_O)
TARGET_O= $(LUAJIT_SO)
TARGET_XLDFLAGS+= $(TARGET_DYNXLDOPTS)
else
ifeq (Darwin,$(TARGET_SYS))
TARGET_DYNCC= @:
LJVMCORE_DYNO= $(LJVMCORE_O)
endif
ifeq (iOS,$(TARGET_SYS))
TARGET_DYNCC= @:
LJVMCORE_DYNO= $(LJVMCORE_O)
endif
endif
endif
Q= @
E= @echo
#Q=
#E= @:
##############################################################################
# Make targets.
##############################################################################
default all: $(TARGET_T)
amalg:
@grep "^[+|]" ljamalg.c
$(MAKE) all "LJCORE_O=ljamalg.o"
clean:
$(HOST_RM) $(ALL_RM)
depend:
@for file in $(ALL_HDRGEN); do \
test -f $$file || touch $$file; \
done
@$(HOST_CC) $(HOST_ACFLAGS) -MM *.c host/*.c | \
sed -e "s| [^ ]*/dasm_\S*\.h||g" \
-e "s|^\([^l ]\)|host/\1|" \
-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" >Makefile.dep
@for file in $(ALL_HDRGEN); do \
test -s $$file || $(HOST_RM) $$file; \
done
.PHONY: default all amalg clean depend
##############################################################################
# Rules for generated files.
##############################################################################
$(MINILUA_T): $(MINILUA_O)
$(E) "HOSTLINK $@"
$(Q)$(HOST_CC) $(HOST_ALDFLAGS) -o $@ $(MINILUA_O) $(MINILUA_LIBS) $(HOST_ALIBS)
host/buildvm_arch.h: $(DASM_DASC) $(DASM_DEP)
$(E) "DYNASM $@"
$(Q)$(DASM) $(DASM_FLAGS) -o $@ $(DASM_DASC)
host/buildvm.o: $(DASM_DIR)/dasm_*.h
$(BUILDVM_T): $(BUILDVM_O)
$(E) "HOSTLINK $@"
$(Q)$(HOST_CC) $(HOST_ALDFLAGS) -o $@ $(BUILDVM_O) $(HOST_ALIBS)
$(LJVM_BOUT): $(BUILDVM_T)
$(E) "BUILDVM $@"
$(Q)$(BUILDVM_X) -m $(LJVM_MODE) -o $@
lj_bcdef.h: $(BUILDVM_T) $(LJLIB_C)
$(E) "BUILDVM $@"
$(Q)$(BUILDVM_X) -m bcdef -o $@ $(LJLIB_C)
lj_ffdef.h: $(BUILDVM_T) $(LJLIB_C)
$(E) "BUILDVM $@"
$(Q)$(BUILDVM_X) -m ffdef -o $@ $(LJLIB_C)
lj_libdef.h: $(BUILDVM_T) $(LJLIB_C)
$(E) "BUILDVM $@"
$(Q)$(BUILDVM_X) -m libdef -o $@ $(LJLIB_C)
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)
lj_folddef.h: $(BUILDVM_T) lj_opt_fold.c
$(E) "BUILDVM $@"
$(Q)$(BUILDVM_X) -m folddef -o $@ lj_opt_fold.c
##############################################################################
# Object file rules.
##############################################################################
%.o: %.c
$(E) "CC $@"
$(Q)$(TARGET_DYNCC) $(TARGET_ACFLAGS) -c -o $(@:.o=_dyn.o) $<
$(Q)$(TARGET_CC) $(TARGET_ACFLAGS) -c -o $@ $<
%.o: %.s
$(E) "ASM $@"
$(Q)$(TARGET_DYNCC) $(TARGET_ACFLAGS) -c -o $(@:.o=_dyn.o) $<
$(Q)$(TARGET_CC) $(TARGET_ACFLAGS) -c -o $@ $<
$(LUAJIT_O):
$(E) "CC $@"
$(Q)$(TARGET_STCC) $(TARGET_ACFLAGS) -c -o $@ $<
$(HOST_O): %.o: %.c
$(E) "HOSTCC $@"
$(Q)$(HOST_CC) $(HOST_ACFLAGS) -c -o $@ $<
include Makefile.dep
##############################################################################
# Target file rules.
##############################################################################
$(LUAJIT_A): $(LJVMCORE_O)
$(E) "AR $@"
$(Q)$(TARGET_AR) $@ $(LJVMCORE_O)
# The dependency on _O, but linking with _DYNO is intentional.
$(LUAJIT_SO): $(LJVMCORE_O)
$(E) "DYNLINK $@"
$(Q)$(TARGET_LD) $(TARGET_ASHLDFLAGS) -o $@ $(LJVMCORE_DYNO) $(TARGET_ALIBS)
$(Q)$(TARGET_STRIP) $@
$(LUAJIT_T): $(TARGET_O) $(LUAJIT_O) $(TARGET_DEP)
$(E) "LINK $@"
$(Q)$(TARGET_LD) $(TARGET_ALDFLAGS) -o $@ $(LUAJIT_O) $(TARGET_O) $(TARGET_ALIBS)
$(Q)$(TARGET_STRIP) $@
$(E) "OK Successfully built LuaJIT"
##############################################################################
-226
View File
@@ -1,226 +0,0 @@
lib_aux.o: lib_aux.c lua.h luaconf.h lauxlib.h lj_obj.h lj_def.h \
lj_arch.h lj_err.h lj_errmsg.h lj_state.h lj_trace.h lj_jit.h lj_ir.h \
lj_dispatch.h lj_bc.h lj_traceerr.h lj_lib.h lj_alloc.h
lib_base.o: lib_base.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_str.h \
lj_tab.h lj_meta.h lj_state.h lj_ctype.h lj_cconv.h lj_bc.h lj_ff.h \
lj_ffdef.h lj_dispatch.h lj_jit.h lj_ir.h lj_char.h lj_strscan.h \
lj_lib.h lj_libdef.h
lib_bit.o: lib_bit.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
lj_arch.h lj_err.h lj_errmsg.h lj_str.h lj_lib.h lj_libdef.h
lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_lib.h \
lj_libdef.h
lib_ffi.o: lib_ffi.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h \
lj_ctype.h lj_cparse.h lj_cdata.h lj_cconv.h lj_carith.h lj_ccall.h \
lj_ccallback.h lj_clib.h lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h
lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h
lib_io.o: lib_io.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
lj_arch.h lj_err.h lj_errmsg.h lj_str.h lj_state.h lj_ff.h lj_ffdef.h \
lj_lib.h lj_libdef.h
lib_jit.o: lib_jit.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h \
lj_obj.h lj_def.h lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_tab.h \
lj_bc.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h lj_target.h \
lj_target_*.h lj_dispatch.h lj_vm.h lj_vmevent.h lj_lib.h luajit.h \
lj_libdef.h
lib_math.o: lib_math.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
lj_def.h lj_arch.h lj_lib.h lj_vm.h lj_libdef.h
lib_os.o: lib_os.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
lj_arch.h lj_err.h lj_errmsg.h lj_lib.h lj_libdef.h
lib_package.o: lib_package.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h
lib_string.o: lib_string.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h \
lj_meta.h lj_state.h lj_ff.h lj_ffdef.h lj_bcdump.h lj_lex.h lj_char.h \
lj_lib.h lj_libdef.h
lib_table.o: lib_table.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_lib.h \
lj_libdef.h
lj_alloc.o: lj_alloc.c lj_def.h lua.h luaconf.h lj_arch.h lj_alloc.h
lj_api.o: lj_api.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_tab.h lj_func.h lj_udata.h \
lj_meta.h lj_state.h lj_bc.h lj_frame.h lj_trace.h lj_jit.h lj_ir.h \
lj_dispatch.h lj_traceerr.h lj_vm.h lj_strscan.h
lj_asm.o: lj_asm.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h lj_ir.h lj_jit.h \
lj_ircall.h lj_iropt.h lj_mcode.h lj_trace.h lj_dispatch.h lj_traceerr.h \
lj_snap.h lj_asm.h lj_vm.h lj_target.h lj_target_*.h lj_emit_*.h \
lj_asm_*.h
lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \
lj_bcdef.h
lj_bcread.o: lj_bcread.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_bc.h lj_ctype.h \
lj_cdata.h lualib.h lj_lex.h lj_bcdump.h lj_state.h
lj_bcwrite.o: lj_bcwrite.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_str.h lj_bc.h lj_ctype.h lj_dispatch.h lj_jit.h lj_ir.h \
lj_bcdump.h lj_lex.h lj_err.h lj_errmsg.h lj_vm.h
lj_carith.o: lj_carith.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_meta.h lj_ctype.h lj_cconv.h \
lj_cdata.h lj_carith.h
lj_ccall.o: lj_ccall.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_ctype.h lj_cconv.h \
lj_cdata.h lj_ccall.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_bc.h \
lj_traceerr.h
lj_ccallback.o: lj_ccallback.c lj_obj.h lua.h luaconf.h lj_def.h \
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_state.h lj_frame.h \
lj_bc.h lj_ctype.h lj_cconv.h lj_ccall.h lj_ccallback.h lj_target.h \
lj_target_*.h lj_mcode.h lj_jit.h lj_ir.h lj_trace.h lj_dispatch.h \
lj_traceerr.h lj_vm.h
lj_cconv.o: lj_cconv.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_err.h lj_errmsg.h lj_tab.h lj_ctype.h lj_gc.h lj_cdata.h lj_cconv.h \
lj_ccallback.h
lj_cdata.o: lj_cdata.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_ctype.h lj_cconv.h \
lj_cdata.h
lj_char.o: lj_char.c lj_char.h lj_def.h lua.h luaconf.h
lj_clib.o: lj_clib.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_err.h lj_errmsg.h lj_tab.h lj_str.h lj_udata.h lj_ctype.h lj_cconv.h \
lj_cdata.h lj_clib.h
lj_cparse.o: lj_cparse.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ctype.h lj_cparse.h lj_frame.h \
lj_bc.h lj_vm.h lj_char.h lj_strscan.h
lj_crecord.o: lj_crecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h \
lj_gc.h lj_cdata.h lj_cparse.h lj_cconv.h lj_clib.h lj_ccall.h lj_ff.h \
lj_ffdef.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h lj_trace.h \
lj_dispatch.h lj_traceerr.h lj_record.h lj_ffrecord.h lj_snap.h \
lj_crecord.h
lj_ctype.o: lj_ctype.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_ctype.h lj_ccallback.h
lj_debug.o: lj_debug.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_tab.h lj_state.h lj_frame.h \
lj_bc.h lj_jit.h lj_ir.h
lj_dispatch.o: lj_dispatch.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_err.h lj_errmsg.h lj_func.h lj_str.h lj_tab.h lj_meta.h lj_debug.h \
lj_state.h lj_frame.h lj_bc.h lj_ff.h lj_ffdef.h lj_jit.h lj_ir.h \
lj_ccallback.h lj_ctype.h lj_gc.h lj_trace.h lj_dispatch.h lj_traceerr.h \
lj_vm.h luajit.h
lj_err.o: lj_err.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_err.h \
lj_errmsg.h lj_debug.h lj_str.h lj_func.h lj_state.h lj_frame.h lj_bc.h \
lj_ff.h lj_ffdef.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h \
lj_traceerr.h lj_vm.h
lj_ffrecord.o: lj_ffrecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ff.h \
lj_ffdef.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h lj_trace.h \
lj_dispatch.h lj_traceerr.h lj_record.h lj_ffrecord.h lj_crecord.h \
lj_vm.h lj_strscan.h lj_recdef.h
lj_func.o: lj_func.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_func.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_bc.h \
lj_traceerr.h lj_vm.h
lj_gc.o: lj_gc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h lj_udata.h lj_meta.h \
lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_cdata.h lj_trace.h lj_jit.h \
lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h
lj_gdbjit.o: lj_gdbjit.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_frame.h lj_bc.h lj_jit.h \
lj_ir.h lj_dispatch.h
lj_ir.o: lj_ir.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_str.h lj_tab.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h lj_trace.h \
lj_dispatch.h lj_bc.h lj_traceerr.h lj_ctype.h lj_cdata.h lj_carith.h \
lj_vm.h lj_strscan.h lj_lib.h
lj_lex.o: lj_lex.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_ctype.h lj_cdata.h lualib.h \
lj_state.h lj_lex.h lj_parse.h lj_char.h lj_strscan.h
lj_lib.o: lj_lib.c lauxlib.h lua.h luaconf.h lj_obj.h lj_def.h lj_arch.h \
lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h lj_bc.h \
lj_dispatch.h lj_jit.h lj_ir.h lj_vm.h lj_strscan.h lj_lib.h
lj_load.o: lj_load.c lua.h luaconf.h lauxlib.h lj_obj.h lj_def.h \
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_func.h lj_frame.h \
lj_bc.h lj_vm.h lj_lex.h lj_bcdump.h lj_parse.h
lj_mcode.o: lj_mcode.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_jit.h lj_ir.h lj_mcode.h lj_trace.h lj_dispatch.h lj_bc.h \
lj_traceerr.h lj_vm.h
lj_meta.o: lj_meta.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h lj_frame.h lj_bc.h \
lj_vm.h lj_strscan.h
lj_obj.o: lj_obj.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h
lj_opt_dce.o: lj_opt_dce.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_ir.h lj_jit.h lj_iropt.h
lj_opt_fold.o: lj_opt_fold.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_str.h lj_tab.h lj_ir.h lj_jit.h lj_iropt.h lj_trace.h lj_dispatch.h \
lj_bc.h lj_traceerr.h lj_ctype.h lj_gc.h lj_carith.h lj_vm.h \
lj_strscan.h lj_folddef.h
lj_opt_loop.o: lj_opt_loop.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_err.h lj_errmsg.h lj_str.h lj_ir.h lj_jit.h lj_iropt.h lj_trace.h \
lj_dispatch.h lj_bc.h lj_traceerr.h lj_snap.h lj_vm.h
lj_opt_mem.o: lj_opt_mem.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_tab.h lj_ir.h lj_jit.h lj_iropt.h
lj_opt_narrow.o: lj_opt_narrow.c lj_obj.h lua.h luaconf.h lj_def.h \
lj_arch.h lj_bc.h lj_ir.h lj_jit.h lj_iropt.h lj_trace.h lj_dispatch.h \
lj_traceerr.h lj_vm.h lj_strscan.h
lj_opt_sink.o: lj_opt_sink.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_ir.h lj_jit.h lj_iropt.h lj_target.h lj_target_*.h
lj_opt_split.o: lj_opt_split.c lj_obj.h lua.h luaconf.h lj_def.h \
lj_arch.h lj_err.h lj_errmsg.h lj_str.h lj_ir.h lj_jit.h lj_ircall.h \
lj_iropt.h lj_vm.h
lj_parse.o: lj_parse.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_tab.h lj_func.h \
lj_state.h lj_bc.h lj_ctype.h lj_lex.h lj_parse.h lj_vm.h lj_vmevent.h
lj_record.o: lj_record.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h lj_frame.h lj_bc.h \
lj_ctype.h lj_gc.h lj_ff.h lj_ffdef.h lj_ir.h lj_jit.h lj_ircall.h \
lj_iropt.h lj_trace.h lj_dispatch.h lj_traceerr.h lj_record.h \
lj_ffrecord.h lj_snap.h lj_vm.h
lj_snap.o: lj_snap.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_tab.h lj_state.h lj_frame.h lj_bc.h lj_ir.h lj_jit.h lj_iropt.h \
lj_trace.h lj_dispatch.h lj_traceerr.h lj_snap.h lj_target.h \
lj_target_*.h lj_ctype.h lj_cdata.h
lj_state.o: lj_state.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h lj_meta.h \
lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_trace.h lj_jit.h lj_ir.h \
lj_dispatch.h lj_traceerr.h lj_vm.h lj_lex.h lj_alloc.h
lj_str.o: lj_str.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_err.h lj_errmsg.h lj_str.h lj_state.h lj_char.h
lj_strscan.o: lj_strscan.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_char.h lj_strscan.h
lj_tab.o: lj_tab.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_err.h lj_errmsg.h lj_tab.h
lj_trace.o: lj_trace.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_frame.h lj_bc.h \
lj_state.h lj_ir.h lj_jit.h lj_iropt.h lj_mcode.h lj_trace.h \
lj_dispatch.h lj_traceerr.h lj_snap.h lj_gdbjit.h lj_record.h lj_asm.h \
lj_vm.h lj_vmevent.h lj_target.h lj_target_*.h
lj_udata.o: lj_udata.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_udata.h
lj_vmevent.o: lj_vmevent.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_str.h lj_tab.h lj_state.h lj_dispatch.h lj_bc.h lj_jit.h lj_ir.h \
lj_vm.h lj_vmevent.h
lj_vmmath.o: lj_vmmath.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_ir.h lj_vm.h
ljamalg.o: ljamalg.c lua.h luaconf.h lauxlib.h lj_gc.c lj_obj.h lj_def.h \
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h \
lj_udata.h lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_cdata.h \
lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h lj_err.c \
lj_debug.h lj_ff.h lj_ffdef.h lj_char.c lj_char.h lj_bc.c lj_bcdef.h \
lj_obj.c lj_str.c lj_tab.c lj_func.c lj_udata.c lj_meta.c lj_strscan.h \
lj_debug.c lj_state.c lj_lex.h lj_alloc.h lj_dispatch.c lj_ccallback.h \
luajit.h lj_vmevent.c lj_vmevent.h lj_vmmath.c lj_strscan.c lj_api.c \
lj_lex.c lualib.h lj_parse.h lj_parse.c lj_bcread.c lj_bcdump.h \
lj_bcwrite.c lj_load.c lj_ctype.c lj_cdata.c lj_cconv.h lj_cconv.c \
lj_ccall.c lj_ccall.h lj_ccallback.c lj_target.h lj_target_*.h \
lj_mcode.h lj_carith.c lj_carith.h lj_clib.c lj_clib.h lj_cparse.c \
lj_cparse.h lj_lib.c lj_lib.h lj_ir.c lj_ircall.h lj_iropt.h \
lj_opt_mem.c lj_opt_fold.c lj_folddef.h lj_opt_narrow.c lj_opt_dce.c \
lj_opt_loop.c lj_snap.h lj_opt_split.c lj_opt_sink.c lj_mcode.c \
lj_snap.c lj_record.c lj_record.h lj_ffrecord.h lj_crecord.c \
lj_crecord.h lj_ffrecord.c lj_recdef.h lj_asm.c lj_asm.h lj_emit_*.h \
lj_asm_*.h lj_trace.c lj_gdbjit.h lj_gdbjit.c lj_alloc.c lib_aux.c \
lib_base.c lj_libdef.h lib_math.c lib_string.c lib_table.c lib_io.c \
lib_os.c lib_package.c lib_debug.c lib_bit.c lib_jit.c lib_ffi.c \
lib_init.c
luajit.o: luajit.c lua.h luaconf.h lauxlib.h lualib.h luajit.h lj_arch.h
host/buildvm.o: host/buildvm.c host/buildvm.h lj_def.h lua.h luaconf.h \
lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_gc.h lj_obj.h lj_bc.h lj_ir.h \
lj_ircall.h lj_ir.h lj_jit.h lj_frame.h lj_bc.h lj_dispatch.h lj_ctype.h \
lj_gc.h lj_ccall.h lj_ctype.h luajit.h \
host/buildvm_arch.h lj_traceerr.h
host/buildvm_asm.o: host/buildvm_asm.c host/buildvm.h lj_def.h lua.h luaconf.h \
lj_arch.h lj_bc.h lj_def.h lj_arch.h
host/buildvm_fold.o: host/buildvm_fold.c host/buildvm.h lj_def.h lua.h \
luaconf.h lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_ir.h lj_obj.h
host/buildvm_lib.o: host/buildvm_lib.c host/buildvm.h lj_def.h lua.h luaconf.h \
lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_lib.h lj_obj.h
host/buildvm_peobj.o: host/buildvm_peobj.c host/buildvm.h lj_def.h lua.h \
luaconf.h lj_arch.h lj_bc.h lj_def.h lj_arch.h
host/minilua.o: host/minilua.c
-368
View File
@@ -1,368 +0,0 @@
/*
** LuaJIT VM builder: PE object emitter.
** Copyright (C) 2005-2013 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_X86ORX64 || LJ_TARGET_PPC
/* 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. */
#elif LJ_TARGET_PPC
#define PEOBJ_ARCH_TARGET 0x01f2
#define PEOBJ_RELOC_REL32 0x06
#define PEOBJ_RELOC_DIR32 0x02
#define PEOBJ_RELOC_OFS (-4)
#define PEOBJ_TEXT_FLAGS 0x60400020 /* 60=r+x, 40=align8, 20=code. */
#endif
/* Section numbers (0-based). */
enum {
PEOBJ_SECT_ABS = -2,
PEOBJ_SECT_UNDEF = -1,
PEOBJ_SECT_TEXT,
#if LJ_TARGET_X64
PEOBJ_SECT_PDATA,
PEOBJ_SECT_XDATA,
#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;
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;
#if LJ_TARGET_X64
memcpy(pesect[PEOBJ_SECT_PDATA].name, ".pdata", sizeof(".pdata")-1);
pesect[PEOBJ_SECT_PDATA].ofs = sofs;
sofs += (pesect[PEOBJ_SECT_PDATA].size = 6*4);
pesect[PEOBJ_SECT_PDATA].relocofs = sofs;
sofs += (pesect[PEOBJ_SECT_PDATA].nreloc = 6) * 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 = 8*2+4+6*2); /* 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;
#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;
#if LJ_TARGET_X64
pehdr.nsyms += 1; /* Symbol for lj_err_unwind_win64. */
#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)) {
#if LJ_TARGET_PPC
uint32_t *p = (uint32_t *)ctx->code;
int n = (int)(ctx->codesz >> 2);
for (i = 0; i < n; i++, p++)
*p = lj_bswap(*p); /* Byteswap .text section. */
#else
fprintf(stderr, "Error: different byte order for host and target\n");
exit(1);
#endif
}
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 fcofs = (uint32_t)ctx->sym[ctx->nsym-1].ofs;
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);
}
#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);
#if LJ_TARGET_X64
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_win64", 0,
PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
#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
-191
View File
@@ -1,191 +0,0 @@
----------------------------------------------------------------------------
-- LuaJIT bytecode listing module.
--
-- Copyright (C) 2005-2013 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")
assert(jit.version_num == 20001, "LuaJIT core/library version mismatch")
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.
module(...)
line = bcline
dump = bcdump
targets = bctargets
on = bcliston
off = bclistoff
start = bcliston -- For -j command line option.
-659
View File
@@ -1,659 +0,0 @@
----------------------------------------------------------------------------
-- LuaJIT module to save/list bytecode.
--
-- Copyright (C) 2005-2013 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 == 20001, "LuaJIT core/library version mismatch")
local bit = require("bit")
-- Symbol name prefix for LuaJIT bytecode.
local LJBC_PREFIX = "luaJIT_BC_"
------------------------------------------------------------------------------
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.
-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).
-e chunk Use chunk string as input.
-- Stop handling options.
- Use stdin as input and/or stdout as output.
File types: c 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(input)
if type(input) == "function" then return input end
if input == "-" then input = nil end
return check(loadfile(input))
end
local function savefile(name, mode)
if name == "-" then return io.stdout end
return check(io.open(name, mode))
end
------------------------------------------------------------------------------
local map_type = {
raw = "raw", c = "c", h = "h", o = "obj", obj = "obj",
}
local map_arch = {
x86 = true, x64 = true, arm = true, ppc = true, ppcspe = true,
mips = true, mipsel = true,
}
local map_os = {
linux = true, windows = true, osx = true, freebsd = true, netbsd = true,
openbsd = true, solaris = true,
}
local function checkarg(str, map, err)
str = string.lower(str)
local s = check(map[str], "unknown ", err)
return s == true and str or s
end
local function detecttype(str)
local ext = string.match(string.lower(str), "%.(%a+)$")
return map_type[ext] or "raw"
end
local function checkmodname(str)
check(string.match(str, "^[%w_.%-]+$"), "bad module name")
return string.gsub(str, "[%.%-]", "_")
end
local function detectmodname(str)
if type(str) == "string" then
local tail = string.match(str, "[^/\\]+$")
if tail then str = tail end
local head = string.match(str, "^(.*)%.[^.]*$")
if head then str = head end
str = string.match(str, "^[%w_.%-]+")
else
str = nil
end
check(str, "cannot derive module name, use -n name")
return string.gsub(str, "[%.%-]", "_")
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)
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(string.format([[
#ifdef _cplusplus
extern "C"
#endif
#ifdef _WIN32
__declspec(dllexport)
#endif
const char %s%s[] = {
]], LJBC_PREFIX, ctx.modname))
else
fp:write(string.format([[
#define %s%s_SIZE %d
static const 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(table.concat(t, ",", 1, n), ",\n")
n, m = 0, #b + 1
end
n = n + 1
t[n] = b
end
bcsave_tail(fp, output, table.concat(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 is64, isbe = false, false
if ctx.arch == "x64" then
is64 = true
elseif ctx.arch == "ppc" or ctx.arch == "ppcspe" or ctx.arch == "mips" then
isbe = true
end
-- 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(({ x86=3, x64=62, arm=40, ppc=20, ppcspe=20, mips=8, mipsel=8 })[ctx.arch])
if ctx.arch == "mips" or ctx.arch == "mipsel" then
hdr.flags = 0x50001006
end
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+1)
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 is64 = false
if ctx.arch == "x86" then
symname = "_"..symname
elseif ctx.arch == "x64" then
is64 = true
end
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(({ x86=0x14c, x64=0x8664, arm=0x1c0, ppc=0x1f2, mips=0x366, mipsel=0x366 })[ctx.arch])
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];
uint32_t vmaddr, vmsize, fileoff, filesize;
uint32_t maxprot, initprot, nsects, flags;
} mach_segment_command;
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];
uint32_t addr, size;
uint32_t offset, align, reloff, nreloc, flags;
uint32_t reserved1, reserved2;
} mach_section;
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;
int16_t desc;
uint32_t value;
} mach_nlist;
typedef struct {
uint32_t strx;
uint8_t type, sect;
uint16_t desc;
uint64_t value;
} mach_nlist_64;
typedef struct
{
uint32_t magic, nfat_arch;
} mach_fat_header;
typedef struct
{
uint32_t cputype, cpusubtype, offset, size, align;
} mach_fat_arch;
typedef struct {
struct {
mach_header hdr;
mach_segment_command seg;
mach_section sec;
mach_symtab_command sym;
} arch[1];
mach_nlist sym_entry;
uint8_t space[4096];
} mach_obj;
typedef struct {
struct {
mach_header_64 hdr;
mach_segment_command_64 seg;
mach_section_64 sec;
mach_symtab_command sym;
} arch[1];
mach_nlist_64 sym_entry;
uint8_t space[4096];
} mach_obj_64;
typedef struct {
mach_fat_header fat;
mach_fat_arch fat_arch[4];
struct {
mach_header hdr;
mach_segment_command seg;
mach_section sec;
mach_symtab_command sym;
} arch[4];
mach_nlist sym_entry;
uint8_t space[4096];
} mach_fat_obj;
]]
local symname = '_'..LJBC_PREFIX..ctx.modname
local isfat, is64, align, mobj = false, false, 4, "mach_obj"
if ctx.arch == "x64" then
is64, align, mobj = true, 8, "mach_obj_64"
elseif ctx.arch == "arm" then
isfat, mobj = true, "mach_fat_obj"
else
check(ctx.arch == "x86", "unsupported architecture for OSX")
end
local function aligned(v, a) return bit.band(v+a-1, -a) end
local be32 = bit.bswap -- Mach-O FAT is BE, supported archs are LE.
-- Create Mach-O object and fill in header.
local o = ffi.new(mobj)
local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, align)
local cputype = ({ x86={7}, x64={0x01000007}, arm={7,12,12,12} })[ctx.arch]
local cpusubtype = ({ x86={3}, x64={3}, arm={3,6,9,11} })[ctx.arch]
if isfat then
o.fat.magic = be32(0xcafebabe)
o.fat.nfat_arch = be32(#cpusubtype)
end
-- Fill in sections and symbols.
for i=0,#cpusubtype-1 do
local ofs = 0
if isfat then
local a = o.fat_arch[i]
a.cputype = be32(cputype[i+1])
a.cpusubtype = be32(cpusubtype[i+1])
-- Subsequent slices overlap each other to share data.
ofs = ffi.offsetof(o, "arch") + i*ffi.sizeof(o.arch[0])
a.offset = be32(ofs)
a.size = be32(mach_size-ofs+#s)
end
local a = o.arch[i]
a.hdr.magic = is64 and 0xfeedfacf or 0xfeedface
a.hdr.cputype = cputype[i+1]
a.hdr.cpusubtype = cpusubtype[i+1]
a.hdr.filetype = 1
a.hdr.ncmds = 2
a.hdr.sizeofcmds = ffi.sizeof(a.seg)+ffi.sizeof(a.sec)+ffi.sizeof(a.sym)
a.seg.cmd = is64 and 0x19 or 0x1
a.seg.cmdsize = ffi.sizeof(a.seg)+ffi.sizeof(a.sec)
a.seg.vmsize = #s
a.seg.fileoff = mach_size-ofs
a.seg.filesize = #s
a.seg.maxprot = 1
a.seg.initprot = 1
a.seg.nsects = 1
ffi.copy(a.sec.sectname, "__data")
ffi.copy(a.sec.segname, "__DATA")
a.sec.size = #s
a.sec.offset = mach_size-ofs
a.sym.cmd = 2
a.sym.cmdsize = ffi.sizeof(a.sym)
a.sym.symoff = ffi.offsetof(o, "sym_entry")-ofs
a.sym.nsyms = 1
a.sym.stroff = ffi.offsetof(o, "sym_entry")+ffi.sizeof(o.sym_entry)-ofs
a.sym.strsize = aligned(#symname+2, align)
end
o.sym_entry.type = 0xf
o.sym_entry.sect = 1
o.sym_entry.strx = 1
ffi.copy(o.space+1, symname)
-- Write Macho-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 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(input, output)
local f = readfile(input)
require("jit.bc").dump(f, savefile(output, "w"), true)
end
local function bcsave(ctx, input, output)
local f = readfile(input)
local s = string.dump(f, ctx.strip)
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 = {
strip = true, arch = jit.arch, os = string.lower(jit.os),
type = false, modname = false,
}
while n <= #arg do
local a = arg[n]
if type(a) == "string" and string.sub(a, 1, 1) == "-" and a ~= "-" then
table.remove(arg, n)
if a == "--" then break end
for m=2,#a do
local opt = string.sub(a, m, m)
if opt == "l" then
list = true
elseif opt == "s" then
ctx.strip = true
elseif opt == "g" then
ctx.strip = false
else
if arg[n] == nil or m ~= #a then usage() end
if opt == "e" then
if n ~= 1 then usage() end
arg[1] = check(loadstring(arg[1]))
elseif opt == "n" then
ctx.modname = checkmodname(table.remove(arg, n))
elseif opt == "t" then
ctx.type = checkarg(table.remove(arg, n), map_type, "file type")
elseif opt == "a" then
ctx.arch = checkarg(table.remove(arg, n), map_arch, "architecture")
elseif opt == "o" then
ctx.os = checkarg(table.remove(arg, n), map_os, "OS name")
else
usage()
end
end
end
else
n = n + 1
end
end
if list then
if #arg == 0 or #arg > 2 then usage() end
bclist(arg[1], arg[2] or "-")
else
if #arg ~= 2 then usage() end
bcsave(ctx, arg[1], arg[2])
end
end
------------------------------------------------------------------------------
-- Public module functions.
module(...)
start = docmd -- Process -b command line option.
-689
View File
@@ -1,689 +0,0 @@
----------------------------------------------------------------------------
-- LuaJIT ARM disassembler module.
--
-- Copyright (C) 2005-2013 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, gsub = string.match, string.gmatch, string.gsub
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.
module(...)
create = create_
disass = disass_
regname = regname_
-428
View File
@@ -1,428 +0,0 @@
----------------------------------------------------------------------------
-- LuaJIT MIPS disassembler module.
--
-- Copyright (C) 2005-2013 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 sub, byte, format = string.sub, 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_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", }
local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", }
local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", }
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",
false, false, false, false,
"multST", "multuST", "divST", "divuST",
false, false, false, false,
"addDST", "addu|moveDST0", "subDST", "subu|neguDS0T",
"andDST", "orDST", "xorDST", "nor|notDST0",
false, false, "sltDST", "sltuDST",
false, false, false, false,
"tgeSTZ", "tgeuSTZ", "tltSTZ", "tltuSTZ",
"teqSTZ", false, "tneSTZ",
}
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_special3 = {
shift = 0, mask = 63,
[0] = "extTSAK", [4] = "insTSAL",
[32] = map_bshfl,
[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_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",
},
}
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", false, "cfc1TG", "mfhc1TG",
"mtc1TG", false, "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",
false, false, false, false,
map_special2, false, 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", false,
"scTSO", "swc1HSO", "swc2TSO", false,
false, "sdc1HSO", "sdc2TSO", false,
}
------------------------------------------------------------------------------
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 = map_pri[rshift(op, 26)]
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
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 == "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 == "L" then
x = band(rshift(op, 11), 31) - last + 1
elseif p == "I" then
x = arshift(lshift(op, 16), 16)
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), 16)*4 + 4
ctx.rel = x
x = "0x"..tohex(x)
elseif p == "J" then
x = band(ctx.addr + ctx.pos, 0xf0000000) + band(op, 0x03ffffff)*4
ctx.rel = x
x = "0x"..tohex(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
return ctx
end
local function create_el_(code, addr, out)
local ctx = create_(code, addr, out)
ctx.get = get_le
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
-- 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.
module(...)
create = create_
create_el = create_el_
disass = disass_
disass_el = disass_el_
regname = regname_
-20
View File
@@ -1,20 +0,0 @@
----------------------------------------------------------------------------
-- LuaJIT MIPSEL disassembler wrapper module.
--
-- Copyright (C) 2005-2013 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 require = require
module(...)
local dis_mips = require(_PACKAGE.."dis_mips")
create = dis_mips.create_el
disass = dis_mips.disass_el
regname = dis_mips.regname
-591
View File
@@ -1,591 +0,0 @@
----------------------------------------------------------------------------
-- LuaJIT PPC disassembler module.
--
-- Copyright (C) 2005-2013 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 sub, byte, format = string.sub, 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.
module(...)
create = create_
disass = disass_
regname = regname_
-20
View File
@@ -1,20 +0,0 @@
----------------------------------------------------------------------------
-- LuaJIT x64 disassembler wrapper module.
--
-- Copyright (C) 2005-2013 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 require = require
module(...)
local dis_x86 = require(_PACKAGE.."dis_x86")
create = dis_x86.create64
disass = dis_x86.disass64
regname = dis_x86.regname64
-836
View File
@@ -1,836 +0,0 @@
----------------------------------------------------------------------------
-- LuaJIT x86/x64 disassembler module.
--
-- Copyright (C) 2005-2013 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 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.
-- * The public API may change when more architectures are added.
------------------------------------------------------------------------------
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
-- 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","$lesVrm","$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]=false, [0xc5]=false, [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|movssXrm|movupdXrm|movsdXrm",
"movupsXmr|movssXmr|movupdXmr|movsdXmr",
"movhlpsXrm$movlpsXrm|movsldupXrm|movlpdXrm|movddupXrm",
"movlpsXmr||movlpdXmr",
"unpcklpsXrm||unpcklpdXrm",
"unpckhpsXrm||unpckhpdXrm",
"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|cvtsi2ssXrVmt|cvtpi2pdXrMm|cvtsi2sdXrVmt",
"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|rsqrtssXrm","rcppsXrm|rcpssXrm",
"andpsXrm||andpdXrm","andnpsXrm||andnpdXrm",
"orpsXrm||orpdXrm","xorpsXrm||xorpdXrm",
"addpsXrm|addssXrm|addpdXrm|addsdXrm","mulpsXrm|mulssXrm|mulpdXrm|mulsdXrm",
"cvtps2pdXrm|cvtss2sdXrm|cvtpd2psXrm|cvtsd2ssXrm",
"cvtdq2psXrm|cvttps2dqXrm|cvtps2dqXrm",
"subpsXrm|subssXrm|subpdXrm|subsdXrm","minpsXrm|minssXrm|minpdXrm|minsdXrm",
"divpsXrm|divssXrm|divpdXrm|divsdXrm","maxpsXrm|maxssXrm|maxpdXrm|maxsdXrm",
--6x
"punpcklbwPrm","punpcklwdPrm","punpckldqPrm","packsswbPrm",
"pcmpgtbPrm","pcmpgtwPrm","pcmpgtdPrm","packuswbPrm",
"punpckhbwPrm","punpckhwdPrm","punpckhdqPrm","packssdwPrm",
"||punpcklqdqXrm","||punpckhqdqXrm",
"movPrVSm","movqMrm|movdquXrm|movdqaXrm",
--7x
"pshufwMrmu|pshufhwXrmu|pshufdXrmu|pshuflwXrmu","pshiftw!Pmu",
"pshiftd!Pmu","pshiftq!Mmu||pshiftdq!Xmu",
"pcmpeqbPrm","pcmpeqwPrm","pcmpeqdPrm","emms|",
"vmreadUmr||extrqXmuu$|insertqXrmuu$","vmwriteUrm||extrqXrm$|insertqXrm$",
nil,nil,
"||haddpdXrm|haddpsXrm","||hsubpdXrm|hsubpsXrm",
"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",
"cmppsXrmu|cmpssXrmu|cmppdXrmu|cmpsdXrmu","$movntiVmr|",
"pinsrwPrWmu","pextrwDrPmu",
"shufpsXrmu||shufpdXrmu","$cmpxchg!Qmp",
"bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR",
--Dx
"||addsubpdXrm|addsubpsXrm","psrlwPrm","psrldPrm","psrlqPrm",
"paddqPrm","pmullwPrm",
"|movq2dqXrMm|movqXmr|movdq2qMrXm$","pmovmskbVrMm||pmovmskbVrXm",
"psubusbPrm","psubuswPrm","pminubPrm","pandPrm",
"paddusbPrm","padduswPrm","pmaxubPrm","pandnPrm",
--Ex
"pavgbPrm","psrawPrm","psradPrm","pavgwPrm",
"pmulhuwPrm","pmulhwPrm",
"|cvtdq2pdXrm|cvttpd2dqXrm|cvtpd2dqXrm","$movntqMmr||$movntdqXmr",
"psubsbPrm","psubswPrm","pminswPrm","porPrm",
"paddsbPrm","paddswPrm","pmaxswPrm","pxorPrm",
--Fx
"|||lddquXrm","psllwPrm","pslldPrm","psllqPrm",
"pmuludqPrm","pmaddwdPrm","psadbwPrm","maskmovqMrm||maskmovdquXrm$",
"psubbPrm","psubwPrm","psubdPrm","psubqPrm",
"paddbPrm","paddwPrm","padddPrm","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]="pshufbPrm","phaddwPrm","phadddPrm","phaddswPrm",
"pmaddubswPrm","phsubwPrm","phsubdPrm","phsubswPrm",
"psignbPrm","psignwPrm","psigndPrm","pmulhrswPrm",
nil,nil,nil,nil,
--1x
"||pblendvbXrma",nil,nil,nil,
"||blendvpsXrma","||blendvpdXrma",nil,"||ptestXrm",
nil,nil,nil,nil,
"pabsbPrm","pabswPrm","pabsdPrm",nil,
--2x
"||pmovsxbwXrm","||pmovsxbdXrm","||pmovsxbqXrm","||pmovsxwdXrm",
"||pmovsxwqXrm","||pmovsxdqXrm",nil,nil,
"||pmuldqXrm","||pcmpeqqXrm","||$movntdqaXrm","||packusdwXrm",
nil,nil,nil,nil,
--3x
"||pmovzxbwXrm","||pmovzxbdXrm","||pmovzxbqXrm","||pmovzxwdXrm",
"||pmovzxwqXrm","||pmovzxdqXrm",nil,"||pcmpgtqXrm",
"||pminsbXrm","||pminsdXrm","||pminuwXrm","||pminudXrm",
"||pmaxsbXrm","||pmaxsdXrm","||pmaxuwXrm","||pmaxudXrm",
--4x
"||pmulddXrm","||phminposuwXrm",
--Fx
[0xf0] = "|||crc32TrBmt",[0xf1] = "|||crc32TrVmt",
},
["3a"] = { -- [66] 0f 3a xx
--0x
[0x00]=nil,nil,nil,nil,nil,nil,nil,nil,
"||roundpsXrmu","||roundpdXrmu","||roundssXrmu","||roundsdXrmu",
"||blendpsXrmu","||blendpdXrmu","||pblendwXrmu","palignrPrmu",
--1x
nil,nil,nil,nil,
"||pextrbVmXru","||pextrwVmXru","||pextrVmSXru","||extractpsVmXru",
nil,nil,nil,nil,nil,nil,nil,nil,
--2x
"||pinsrbXrVmu","||insertpsXrmu","||pinsrXrVmuS",nil,
--4x
[0x40] = "||dppsXrmu",
[0x41] = "||dppdXrmu",
[0x42] = "||mpsadbwXrmu",
--6x
[0x60] = "||pcmpestrmXrmu",[0x61] = "||pcmpestriXrmu",
[0x62] = "||pcmpistrmXrmu",[0x63] = "||pcmpistriXrmu",
},
}
-- 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" },
}
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,
}
local map_sz2prefix = {
B = "byte", W = "word", D = "dword",
Q = "qword",
M = "qword", X = "xword",
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 "")
if t ~= "" then text = "rex."..t.." "..text end
ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false
ctx.rex = 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.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
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 = ctx.code, ctx.pos, ctx.stop
-- Chars used: 1DFGIMPQRSTUVWXacdfgijmoprstuwxyz
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, "[WDQMXFG]") then
sz = p
regs = map_regs[sz]
elseif p == "P" then
sz = ctx.o16 and "X" or "M"; ctx.o16 = false
regs = map_regs[sz]
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 == "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 = format("0x%08x", 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 == "y" then x = "DR"..sp
elseif p == "z" then x = "TR"..sp
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,
-- 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 prefix allowed.
for p in gmatch(pat, ".") do ctx["rex"..p] = true end
ctx.rex = true
end,
-- Special case for nop with REX prefix.
nop = function(ctx, name, pat)
return dispatch(ctx, ctx.rex and pat or "nop")
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.
module(...)
create = create_
create64 = create64_
disass = disass_
disass64 = disass64_
regname = regname_
regname64 = regname64_
-700
View File
@@ -1,700 +0,0 @@
----------------------------------------------------------------------------
-- LuaJIT compiler dump module.
--
-- Copyright (C) 2005-2013 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.
--
-- 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")
assert(jit.version_num == 20001, "LuaJIT core/library version mismatch")
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, shl, shr = bit.band, bit.lshift, bit.rshift
local sub, gsub, format = string.sub, string.gsub, string.format
local byte, char, rep = string.byte, string.char, 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 == "mips" or jit.arch == "mipsel" then
t[traceexitstub(tr, 0)] = "exit"
return
end
for i=0,nexit-1 do
local addr = traceexitstub(tr, i)
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 ircall = vmdef.ircall
for i=0,#ircall do
local addr = ircalladdr(i)
if addr ~= 0 then 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
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
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, t)
return s
end
local function colorize_ansi(s, t)
return format(colortype_ansi[t], s)
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)
s = gsub(s, "[<>&]", html_escape)
return format('<span class="irt_%s">%s</span>', irtype_text[t], 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; }
</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
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, 0x400) ~= 0 then s = s.." trunc"
elseif band(mode, 0x800) ~= 0 then s = s.." sext" end
local c = shr(mode, 14)
if 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,
}
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)
local k, t, slot = tracek(tr, idx)
local tn = type(k)
local s
if tn == "number" then
if k == 2^52+2^51 then
s = "bias"
else
s = format("%+.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 == "[0x00000000]" 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
else
s = tostring(k) -- For primitives.
end
s = colorize(format("%-4s", s), t)
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))
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)))
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
err = format(vmdef.traceerr[err], 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) end
out:write(" ", fmtfunc(func, pc), "\n")
recprefix = ""
elseif what == "stop" or what == "abort" then
out:write("---- TRACE ", tr, " ", what)
recprefix = nil
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
out:write("---- TRACE ", what, "\n\n")
end
out:flush()
end
-- Dump recorded bytecode.
local function dump_record(tr, func, pc, depth, callee)
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"
callee = func
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
------------------------------------------------------------------------------
-- 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 jit.arch == "x64" 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(format(" %08x", regs[i]))
if i % 8 == 0 then out:write("\n") end
end
end
if jit.arch == "mips" or jit.arch == "mipsel" 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 colormode = 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.
module(...)
on = dumpon
off = dumpoff
start = dumpon -- For -j command line option.
-167
View File
@@ -1,167 +0,0 @@
----------------------------------------------------------------------------
-- Verbose mode of the LuaJIT compiler.
--
-- Copyright (C) 2005-2013 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")
assert(jit.version_num == 20001, "LuaJIT core/library version mismatch")
local jutil = require("jit.util")
local vmdef = require("jit.vmdef")
local funcinfo, traceinfo = jutil.funcinfo, jutil.traceinfo
local type, format = type, 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
err = format(vmdef.traceerr[err], 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..") " 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 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.
module(...)
on = dumpon
off = dumpoff
start = dumpon -- For -j command line option.
-74
View File
@@ -1,74 +0,0 @@
/*
** Bit manipulation library.
** Copyright (C) 2005-2013 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_str.h"
#include "lj_lib.h"
/* ------------------------------------------------------------------------ */
#define LJLIB_MODULE_bit
LJLIB_ASM(bit_tobit) LJLIB_REC(bit_unary IR_TOBIT)
{
lj_lib_checknumber(L, 1);
return FFH_RETRY;
}
LJLIB_ASM_(bit_bnot) LJLIB_REC(bit_unary IR_BNOT)
LJLIB_ASM_(bit_bswap) LJLIB_REC(bit_unary IR_BSWAP)
LJLIB_ASM(bit_lshift) LJLIB_REC(bit_shift IR_BSHL)
{
lj_lib_checknumber(L, 1);
lj_lib_checkbit(L, 2);
return FFH_RETRY;
}
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)
{
int i = 0;
do { lj_lib_checknumber(L, ++i); } while (L->base+i < L->top);
return FFH_RETRY;
}
LJLIB_ASM_(bit_bor) LJLIB_REC(bit_nary IR_BOR)
LJLIB_ASM_(bit_bxor) LJLIB_REC(bit_nary IR_BXOR)
/* ------------------------------------------------------------------------ */
LJLIB_CF(bit_tohex)
{
uint32_t b = (uint32_t)lj_lib_checkbit(L, 1);
int32_t i, n = L->base+1 >= L->top ? 8 : lj_lib_checkbit(L, 2);
const char *hexdigits = "0123456789abcdef";
char buf[8];
if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; }
if (n > 8) n = 8;
for (i = n; --i >= 0; ) { buf[i] = hexdigits[b & 15]; b >>= 4; }
lua_pushlstring(L, buf, (size_t)n);
return 1;
}
/* ------------------------------------------------------------------------ */
#include "lj_libdef.h"
LUALIB_API int luaopen_bit(lua_State *L)
{
LJ_LIB_REG(L, LUA_BITLIBNAME, bit);
return 1;
}
-233
View File
@@ -1,233 +0,0 @@
/*
** Math library.
** Copyright (C) 2005-2013 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_lib.h"
#include "lj_vm.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_unary IRFPM_LOG10)
LJLIB_ASM_(math_exp) LJLIB_REC(math_unary IRFPM_EXP)
LJLIB_ASM_(math_sin) LJLIB_REC(math_unary IRFPM_SIN)
LJLIB_ASM_(math_cos) LJLIB_REC(math_unary IRFPM_COS)
LJLIB_ASM_(math_tan) LJLIB_REC(math_unary IRFPM_TAN)
LJLIB_ASM_(math_asin) LJLIB_REC(math_atrig FF_math_asin)
LJLIB_ASM_(math_acos) LJLIB_REC(math_atrig FF_math_acos)
LJLIB_ASM_(math_atan) LJLIB_REC(math_atrig FF_math_atan)
LJLIB_ASM_(math_sinh) LJLIB_REC(math_htrig IRCALL_sinh)
LJLIB_ASM_(math_cosh) LJLIB_REC(math_htrig IRCALL_cosh)
LJLIB_ASM_(math_tanh) LJLIB_REC(math_htrig IRCALL_tanh)
LJLIB_ASM_(math_frexp)
LJLIB_ASM_(math_modf) LJLIB_REC(.)
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, x*y); /* Do NOT join the expression to x / y. */
return FFH_RES(1);
}
return FFH_RETRY;
}
LJLIB_PUSH(57.29577951308232)
LJLIB_ASM_(math_deg) LJLIB_REC(math_degrad)
LJLIB_PUSH(0.017453292519943295)
LJLIB_ASM_(math_rad) LJLIB_REC(math_degrad)
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.
*/
/* PRNG state. */
struct RandomState {
uint64_t gen[4]; /* State of the 4 LFSR generators. */
int valid; /* State is valid. */
};
/* Union needed for bit-pattern conversion between uint64_t and double. */
typedef union { uint64_t u64; double d; } U64double;
/* Update generator i and compute a running xor of all states. */
#define TW223_GEN(i, k, q, s) \
z = rs->gen[i]; \
z = (((z<<q)^z) >> (k-s)) ^ ((z&((uint64_t)(int64_t)-1 << (64-k)))<<s); \
r ^= z; rs->gen[i] = z;
/* PRNG step function. Returns a double in the range 1.0 <= d < 2.0. */
LJ_NOINLINE uint64_t LJ_FASTCALL lj_math_random_step(RandomState *rs)
{
uint64_t z, r = 0;
TW223_GEN(0, 63, 31, 18)
TW223_GEN(1, 58, 19, 28)
TW223_GEN(2, 55, 24, 7)
TW223_GEN(3, 47, 21, 8)
return (r & U64x(000fffff,ffffffff)) | U64x(3ff00000,00000000);
}
/* PRNG initialization function. */
static void random_init(RandomState *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 gen[i] are non-zero. */
rs->gen[i] = u.u64;
}
rs->valid = 1;
for (i = 0; i < 10; i++)
lj_math_random_step(rs);
}
/* PRNG extract function. */
LJLIB_PUSH(top-2) /* Upvalue holds userdata with RandomState. */
LJLIB_CF(math_random) LJLIB_REC(.)
{
int n = (int)(L->top - L->base);
RandomState *rs = (RandomState *)(uddata(udataV(lj_lib_upvalue(L, 1))));
U64double u;
double d;
if (LJ_UNLIKELY(!rs->valid)) random_init(rs, 0.0);
u.u64 = lj_math_random_step(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 RandomState. */
LJLIB_CF(math_randomseed)
{
RandomState *rs = (RandomState *)(uddata(udataV(lj_lib_upvalue(L, 1))));
random_init(rs, lj_lib_checknum(L, 1));
return 0;
}
/* ------------------------------------------------------------------------ */
#include "lj_libdef.h"
LUALIB_API int luaopen_math(lua_State *L)
{
RandomState *rs;
rs = (RandomState *)lua_newuserdata(L, sizeof(RandomState));
rs->valid = 0; /* Use lazy initialization to save some time on startup. */
LJ_LIB_REG(L, LUA_MATHLIBNAME, math);
#if defined(LUA_COMPAT_MOD) && !LJ_52
lua_getfield(L, -1, "fmod");
lua_setfield(L, -2, "mod");
#endif
return 1;
}
-940
View File
@@ -1,940 +0,0 @@
/*
** String library.
** Copyright (C) 2005-2013 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 <stdio.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_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_lib.h"
/* ------------------------------------------------------------------------ */
#define LJLIB_MODULE_string
LJLIB_ASM(string_len) LJLIB_REC(.)
{
lj_lib_checkstr(L, 1);
return FFH_RETRY;
}
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, p[i]);
return FFH_RES(n);
}
LJLIB_ASM(string_char)
{
int i, nargs = (int)(L->top - L->base);
char *buf = lj_str_needbuf(L, &G(L)->tmpbuf, (size_t)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_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_ASM(string_rep)
{
GCstr *s = lj_lib_checkstr(L, 1);
int32_t k = lj_lib_checkint(L, 2);
GCstr *sep = lj_lib_optstr(L, 3);
int32_t len = (int32_t)s->len;
global_State *g = G(L);
int64_t tlen;
const char *src;
char *buf;
if (k <= 0) {
empty:
setstrV(L, L->base-1, &g->strempty);
return FFH_RES(1);
}
if (sep) {
tlen = (int64_t)len + sep->len;
if (tlen > LJ_MAX_STR)
lj_err_caller(L, LJ_ERR_STROV);
tlen *= k;
if (tlen > LJ_MAX_STR)
lj_err_caller(L, LJ_ERR_STROV);
} else {
tlen = (int64_t)k * len;
if (tlen > LJ_MAX_STR)
lj_err_caller(L, LJ_ERR_STROV);
}
if (tlen == 0) goto empty;
buf = lj_str_needbuf(L, &g->tmpbuf, (MSize)tlen);
src = strdata(s);
if (sep) {
tlen -= sep->len; /* Ignore trailing separator. */
if (k > 1) { /* Paste one string and one separator. */
int32_t i;
i = 0; while (i < len) *buf++ = src[i++];
src = strdata(sep); len = sep->len;
i = 0; while (i < len) *buf++ = src[i++];
src = g->tmpbuf.buf; len += s->len; k--; /* Now copy that k-1 times. */
}
}
do {
int32_t i = 0;
do { *buf++ = src[i++]; } while (i < len);
} while (--k > 0);
setstrV(L, L->base-1, lj_str_new(L, g->tmpbuf.buf, (size_t)tlen));
return FFH_RES(1);
}
LJLIB_ASM(string_reverse)
{
GCstr *s = lj_lib_checkstr(L, 1);
lj_str_needbuf(L, &G(L)->tmpbuf, s->len);
return FFH_RETRY;
}
LJLIB_ASM_(string_lower)
LJLIB_ASM_(string_upper)
/* ------------------------------------------------------------------------ */
static int writer_buf(lua_State *L, const void *p, size_t size, void *b)
{
luaL_addlstring((luaL_Buffer *)b, (const char *)p, size);
UNUSED(L);
return 0;
}
LJLIB_CF(string_dump)
{
GCfunc *fn = lj_lib_checkfunc(L, 1);
int strip = L->base+1 < L->top && tvistruecond(L->base+1);
luaL_Buffer b;
L->top = L->base+1;
luaL_buffinit(L, &b);
if (!isluafunc(fn) || lj_bcwrite(L, funcproto(fn), writer_buf, &b, strip))
lj_err_caller(L, LJ_ERR_STRDUMP);
luaL_pushresult(&b);
return 1;
}
/* ------------------------------------------------------------------------ */
/* 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 '%'
#define SPECIALS "^$*+?.([%-"
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 const char *lmemfind(const char *s1, size_t l1,
const char *s2, size_t l2)
{
if (l2 == 0) {
return s1; /* empty strings are everywhere */
} else if (l2 > l1) {
return NULL; /* avoids a negative `l1' */
} else {
const char *init; /* to search for a `*s2' inside `s1' */
l2--; /* 1st char will be checked by `memchr' */
l1 = l1-l2; /* `s2' cannot be found after that */
while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
init++; /* 1st char is already checked */
if (memcmp(init, s2+1, l2) == 0) {
return init-1;
} else { /* correct `l1' and `s1' to try again */
l1 -= (size_t)(init-s1);
s1 = init;
}
}
return NULL; /* not found */
}
}
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 ptrdiff_t posrelat(ptrdiff_t pos, size_t len)
{
/* relative string position: negative means back from end */
if (pos < 0) pos += (ptrdiff_t)len + 1;
return (pos >= 0) ? pos : 0;
}
static int str_find_aux(lua_State *L, int find)
{
size_t l1, l2;
const char *s = luaL_checklstring(L, 1, &l1);
const char *p = luaL_checklstring(L, 2, &l2);
ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1;
if (init < 0) {
init = 0;
} else if ((size_t)(init) > l1) {
#if LJ_52
setnilV(L->top-1);
return 1;
#else
init = (ptrdiff_t)l1;
#endif
}
if (find && (lua_toboolean(L, 4) || /* explicit request? */
strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */
/* do a plain search */
const char *s2 = lmemfind(s+init, l1-(size_t)init, p, l2);
if (s2) {
lua_pushinteger(L, s2-s+1);
lua_pushinteger(L, s2-s+(ptrdiff_t)l2);
return 2;
}
} else {
MatchState ms;
int anchor = (*p == '^') ? (p++, 1) : 0;
const char *s1=s+init;
ms.L = L;
ms.src_init = s;
ms.src_end = s+l1;
do {
const char *res;
ms.level = ms.depth = 0;
if ((res=match(&ms, s1, p)) != NULL) {
if (find) {
lua_pushinteger(L, s1-s+1); /* start */
lua_pushinteger(L, res-s); /* end */
return push_captures(&ms, NULL, 0) + 2;
} else {
return push_captures(&ms, s1, res);
}
}
} while (s1++ < ms.src_end && !anchor);
}
lua_pushnil(L); /* not found */
return 1;
}
LJLIB_CF(string_find)
{
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;
}
/* ------------------------------------------------------------------------ */
/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
#define MAX_FMTITEM 512
/* valid flags in a format specification */
#define FMT_FLAGS "-+ #0"
/*
** maximum size of each format specification (such as '%-099.99d')
** (+10 accounts for %99.99x plus margin of error)
*/
#define MAX_FMTSPEC (sizeof(FMT_FLAGS) + sizeof(LUA_INTFRMLEN) + 10)
static void addquoted(lua_State *L, luaL_Buffer *b, int arg)
{
GCstr *str = lj_lib_checkstr(L, arg);
int32_t len = (int32_t)str->len;
const char *s = strdata(str);
luaL_addchar(b, '"');
while (len--) {
uint32_t c = uchar(*s);
if (c == '"' || c == '\\' || c == '\n') {
luaL_addchar(b, '\\');
} else if (lj_char_iscntrl(c)) { /* This can only be 0-31 or 127. */
uint32_t d;
luaL_addchar(b, '\\');
if (c >= 100 || lj_char_isdigit(uchar(s[1]))) {
luaL_addchar(b, '0'+(c >= 100)); if (c >= 100) c -= 100;
goto tens;
} else if (c >= 10) {
tens:
d = (c * 205) >> 11; c -= d * 10; luaL_addchar(b, '0'+d);
}
c += '0';
}
luaL_addchar(b, c);
s++;
}
luaL_addchar(b, '"');
}
static const char *scanformat(lua_State *L, const char *strfrmt, char *form)
{
const char *p = strfrmt;
while (*p != '\0' && strchr(FMT_FLAGS, *p) != NULL) p++; /* skip flags */
if ((size_t)(p - strfrmt) >= sizeof(FMT_FLAGS))
lj_err_caller(L, LJ_ERR_STRFMTR);
if (lj_char_isdigit(uchar(*p))) p++; /* skip width */
if (lj_char_isdigit(uchar(*p))) p++; /* (2 digits at most) */
if (*p == '.') {
p++;
if (lj_char_isdigit(uchar(*p))) p++; /* skip precision */
if (lj_char_isdigit(uchar(*p))) p++; /* (2 digits at most) */
}
if (lj_char_isdigit(uchar(*p)))
lj_err_caller(L, LJ_ERR_STRFMTW);
*(form++) = '%';
strncpy(form, strfrmt, (size_t)(p - strfrmt + 1));
form += p - strfrmt + 1;
*form = '\0';
return p;
}
static void addintlen(char *form)
{
size_t l = strlen(form);
char spec = form[l - 1];
strcpy(form + l - 1, LUA_INTFRMLEN);
form[l + sizeof(LUA_INTFRMLEN) - 2] = spec;
form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0';
}
static unsigned LUA_INTFRM_T num2intfrm(lua_State *L, int arg)
{
if (sizeof(LUA_INTFRM_T) == 4) {
return (LUA_INTFRM_T)lj_lib_checkbit(L, arg);
} else {
cTValue *o;
lj_lib_checknumber(L, arg);
o = L->base+arg-1;
if (tvisint(o))
return (LUA_INTFRM_T)intV(o);
else
return (LUA_INTFRM_T)numV(o);
}
}
static unsigned LUA_INTFRM_T num2uintfrm(lua_State *L, int arg)
{
if (sizeof(LUA_INTFRM_T) == 4) {
return (unsigned LUA_INTFRM_T)lj_lib_checkbit(L, arg);
} else {
cTValue *o;
lj_lib_checknumber(L, arg);
o = L->base+arg-1;
if (tvisint(o))
return (unsigned LUA_INTFRM_T)intV(o);
else if ((int32_t)o->u32.hi < 0)
return (unsigned LUA_INTFRM_T)(LUA_INTFRM_T)numV(o);
else
return (unsigned LUA_INTFRM_T)numV(o);
}
}
static GCstr *meta_tostring(lua_State *L, int arg)
{
TValue *o = L->base+arg-1;
cTValue *mo;
lua_assert(o < L->top); /* Caller already checks for existence. */
if (LJ_LIKELY(tvisstr(o)))
return strV(o);
if (!tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) {
copyTV(L, L->top++, mo);
copyTV(L, L->top++, o);
lua_call(L, 1, 1);
L->top--;
if (tvisstr(L->top))
return strV(L->top);
o = L->base+arg-1;
copyTV(L, o, L->top);
}
if (tvisnumber(o)) {
return lj_str_fromnumber(L, o);
} else if (tvisnil(o)) {
return lj_str_newlit(L, "nil");
} else if (tvisfalse(o)) {
return lj_str_newlit(L, "false");
} else if (tvistrue(o)) {
return lj_str_newlit(L, "true");
} else {
if (tvisfunc(o) && isffunc(funcV(o)))
lj_str_pushf(L, "function: builtin#%d", funcV(o)->c.ffid);
else
lj_str_pushf(L, "%s: %p", lj_typename(o), lua_topointer(L, arg));
L->top--;
return strV(L->top);
}
}
LJLIB_CF(string_format)
{
int arg = 1, top = (int)(L->top - L->base);
GCstr *fmt = lj_lib_checkstr(L, arg);
const char *strfrmt = strdata(fmt);
const char *strfrmt_end = strfrmt + fmt->len;
luaL_Buffer b;
luaL_buffinit(L, &b);
while (strfrmt < strfrmt_end) {
if (*strfrmt != L_ESC) {
luaL_addchar(&b, *strfrmt++);
} else if (*++strfrmt == L_ESC) {
luaL_addchar(&b, *strfrmt++); /* %% */
} else { /* format item */
char form[MAX_FMTSPEC]; /* to store the format (`%...') */
char buff[MAX_FMTITEM]; /* to store the formatted item */
if (++arg > top)
luaL_argerror(L, arg, lj_obj_typename[0]);
strfrmt = scanformat(L, strfrmt, form);
switch (*strfrmt++) {
case 'c':
sprintf(buff, form, lj_lib_checkint(L, arg));
break;
case 'd': case 'i':
addintlen(form);
sprintf(buff, form, num2intfrm(L, arg));
break;
case 'o': case 'u': case 'x': case 'X':
addintlen(form);
sprintf(buff, form, num2uintfrm(L, arg));
break;
case 'e': case 'E': case 'f': case 'g': case 'G': case 'a': case 'A': {
TValue tv;
tv.n = lj_lib_checknum(L, arg);
if (LJ_UNLIKELY((tv.u32.hi << 1) >= 0xffe00000)) {
/* Canonicalize output of non-finite values. */
char *p, nbuf[LJ_STR_NUMBUF];
size_t len = lj_str_bufnum(nbuf, &tv);
if (strfrmt[-1] < 'a') {
nbuf[len-3] = nbuf[len-3] - 0x20;
nbuf[len-2] = nbuf[len-2] - 0x20;
nbuf[len-1] = nbuf[len-1] - 0x20;
}
nbuf[len] = '\0';
for (p = form; *p < 'A' && *p != '.'; p++) ;
*p++ = 's'; *p = '\0';
sprintf(buff, form, nbuf);
break;
}
sprintf(buff, form, (double)tv.n);
break;
}
case 'q':
addquoted(L, &b, arg);
continue;
case 'p':
lj_str_pushf(L, "%p", lua_topointer(L, arg));
luaL_addvalue(&b);
continue;
case 's': {
GCstr *str = meta_tostring(L, arg);
if (!strchr(form, '.') && str->len >= 100) {
/* no precision and string is too long to be formatted;
keep original string */
setstrV(L, L->top++, str);
luaL_addvalue(&b);
continue;
}
sprintf(buff, form, strdata(str));
break;
}
default:
lj_err_callerv(L, LJ_ERR_STRFMTO, *(strfrmt -1));
break;
}
luaL_addlstring(&b, buff, strlen(buff));
}
}
luaL_pushresult(&b);
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);
#if defined(LUA_COMPAT_GFIND) && !LJ_52
lua_getfield(L, -1, "gmatch");
lua_setfield(L, -2, "gfind");
#endif
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));
return 1;
}
-300
View File
@@ -1,300 +0,0 @@
/*
** Table library.
** Copyright (C) 2005-2013 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_tab.h"
#include "lj_lib.h"
/* ------------------------------------------------------------------------ */
#define LJLIB_MODULE_table
LJLIB_CF(table_foreachi)
{
GCtab *t = lj_lib_checktab(L, 1);
GCfunc *func = lj_lib_checkfunc(L, 2);
MSize i, n = lj_tab_len(t);
for (i = 1; i <= n; i++) {
cTValue *val;
setfuncV(L, L->top, func);
setintV(L->top+1, i);
val = lj_tab_getint(t, (int32_t)i);
if (val) { copyTV(L, L->top+2, val); } else { setnilV(L->top+2); }
L->top += 3;
lua_call(L, 2, 1);
if (!tvisnil(L->top-1))
return 1;
L->top--;
}
return 0;
}
LJLIB_CF(table_foreach)
{
GCtab *t = lj_lib_checktab(L, 1);
GCfunc *func = lj_lib_checkfunc(L, 2);
L->top = L->base+3;
setnilV(L->top-1);
while (lj_tab_next(L, t, L->top-1)) {
copyTV(L, L->top+2, L->top);
copyTV(L, L->top+1, L->top-1);
setfuncV(L, L->top, func);
L->top += 3;
lua_call(L, 2, 1);
if (!tvisnil(L->top-1))
return 1;
L->top--;
}
return 0;
}
LJLIB_ASM(table_getn) LJLIB_REC(.)
{
lj_lib_checktab(L, 1);
return FFH_UNREACHABLE;
}
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;
}
setnumV(L->top-1, m);
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_CF(table_remove) LJLIB_REC(.)
{
GCtab *t = lj_lib_checktab(L, 1);
int32_t e = (int32_t)lj_tab_len(t);
int32_t pos = lj_lib_optint(L, 2, e);
if (!(1 <= pos && pos <= e)) /* Nothing to remove? */
return 0;
lua_rawgeti(L, 1, pos); /* Get previous value. */
/* NOBARRIER: This just moves existing elements around. */
for (; pos < e; pos++) {
cTValue *src = lj_tab_getint(t, pos+1);
TValue *dst = lj_tab_setint(L, t, pos);
if (src) {
copyTV(L, dst, src);
} else {
setnilV(dst);
}
}
setnilV(lj_tab_setint(L, t, e)); /* Remove (last) value. */
return 1; /* Return previous value. */
}
LJLIB_CF(table_concat)
{
luaL_Buffer b;
GCtab *t = lj_lib_checktab(L, 1);
GCstr *sep = lj_lib_optstr(L, 2);
MSize seplen = sep ? sep->len : 0;
int32_t i = lj_lib_optint(L, 3, 1);
int32_t e = L->base+3 < L->top ? lj_lib_checkint(L, 4) :
(int32_t)lj_tab_len(t);
luaL_buffinit(L, &b);
if (i <= e) {
for (;;) {
cTValue *o;
lua_rawgeti(L, 1, i);
o = L->top-1;
if (!(tvisstr(o) || tvisnumber(o)))
lj_err_callerv(L, LJ_ERR_TABCAT, lj_typename(o), i);
luaL_addvalue(&b);
if (i++ == e) break;
if (seplen)
luaL_addlstring(&b, strdata(sep), seplen);
}
}
luaL_pushresult(&b);
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
/* ------------------------------------------------------------------------ */
#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
return 1;
}
-26
View File
@@ -1,26 +0,0 @@
# Valgrind suppression file for LuaJIT 2.0.
{
Optimized string compare
Memcheck:Addr4
fun:lj_str_cmp
}
{
Optimized string compare
Memcheck:Addr1
fun:lj_str_cmp
}
{
Optimized string compare
Memcheck:Addr4
fun:lj_str_new
}
{
Optimized string compare
Memcheck:Addr1
fun:lj_str_new
}
{
Optimized string compare
Memcheck:Cond
fun:lj_str_new
}
-17
View File
@@ -1,17 +0,0 @@
/*
** 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(void);
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
File diff suppressed because it is too large Load Diff
-419
View File
@@ -1,419 +0,0 @@
/*
** Target architecture selection.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_ARCH_H
#define _LJ_ARCH_H
#include "lua.h"
/* 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_PPC 4
#define LUAJIT_ARCH_ppc 4
#define LUAJIT_ARCH_PPCSPE 5
#define LUAJIT_ARCH_ppcspe 5
#define LUAJIT_ARCH_MIPS 6
#define LUAJIT_ARCH_mips 6
/* 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
/* 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(__ppc__) || defined(__ppc) || defined(__PPC__) || defined(__PPC) || defined(__powerpc__) || defined(__powerpc) || defined(__POWERPC__) || defined(__POWERPC) || defined(_M_PPC)
#ifdef __NO_FPRS__
#define LUAJIT_TARGET LUAJIT_ARCH_PPCSPE
#else
#define LUAJIT_TARGET LUAJIT_ARCH_PPC
#endif
#elif defined(__mips__) || defined(__mips) || defined(__MIPS__) || defined(__MIPS)
#define LUAJIT_TARGET LUAJIT_ARCH_MIPS
#else
#error "No support for this architecture (yet)"
#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__)
#define LUAJIT_OS LUAJIT_OS_OSX
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
defined(__NetBSD__) || defined(__OpenBSD__)
#define LUAJIT_OS LUAJIT_OS_BSD
#elif (defined(__sun__) && defined(__svr4__)) || defined(__CYGWIN__)
#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_IOS (LJ_TARGET_OSX && LUAJIT_TARGET == LUAJIT_ARCH_ARM)
#define LJ_TARGET_POSIX (LUAJIT_OS > LUAJIT_OS_WINDOWS)
#define LJ_TARGET_DLOPEN LJ_TARGET_POSIX
#ifdef __CELLOS_LV2__
#define LJ_TARGET_PS3 1
#define LJ_TARGET_CONSOLE 1
#endif
#if _XBOX_VER >= 200
#define LJ_TARGET_XBOX360 1
#define LJ_TARGET_CONSOLE 1
#endif
#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. */
/* 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
#if LJ_TARGET_WINDOWS || __CYGWIN__
#define LJ_ABI_WIN 1
#else
#define LJ_ABI_WIN 0
#endif
#define LJ_TARGET_X86 1
#define LJ_TARGET_X86ORX64 1
#define LJ_TARGET_EHRETREG 0
#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_ABI_WIN LJ_TARGET_WINDOWS
#define LJ_TARGET_X64 1
#define LJ_TARGET_X86ORX64 1
#define LJ_TARGET_EHRETREG 0
#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
#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_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_7__ || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH_7S__
#define LJ_ARCH_VERSION 70
#elif __ARM_ARCH_6T2__
#define LJ_ARCH_VERSION 61
#elif __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_PPC
#define LJ_ARCH_NAME "ppc"
#if _LP64
#define LJ_ARCH_BITS 64
#else
#define LJ_ARCH_BITS 32
#endif
#define LJ_ARCH_ENDIAN LUAJIT_BE
#define LJ_TARGET_PPC 1
#define LJ_TARGET_EHRETREG 3
#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. */
#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL_SINGLE
#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 __PPC64__ || __powerpc64__ || LJ_TARGET_CONSOLE
#define LJ_ARCH_PPC64 1
#define LJ_ARCH_NOFFI 1
#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_PPCSPE
#define LJ_ARCH_NAME "ppcspe"
#define LJ_ARCH_BITS 32
#define LJ_ARCH_ENDIAN LUAJIT_BE
#ifndef LJ_ABI_SOFTFP
#define LJ_ABI_SOFTFP 1
#endif
#define LJ_ABI_EABI 1
#define LJ_TARGET_PPCSPE 1
#define LJ_TARGET_EHRETREG 3
#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. */
#define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE
#define LJ_ARCH_NOFFI 1 /* NYI: comparisons, calls. */
#define LJ_ARCH_NOJIT 1
#elif LUAJIT_TARGET == LUAJIT_ARCH_MIPS
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL)
#define LJ_ARCH_NAME "mipsel"
#define LJ_ARCH_ENDIAN LUAJIT_LE
#else
#define LJ_ARCH_NAME "mips"
#define LJ_ARCH_ENDIAN LUAJIT_BE
#endif
#define LJ_ARCH_BITS 32
#define LJ_TARGET_MIPS 1
#define LJ_TARGET_EHRETREG 4
#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_SINGLE
#if _MIPS_ARCH_MIPS32R2
#define LJ_ARCH_VERSION 20
#else
#define LJ_ARCH_VERSION 10
#endif
#else
#error "No target architecture defined"
#endif
#ifndef LJ_PAGESIZE
#define LJ_PAGESIZE 4096
#endif
/* 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_PS3
#if (__GNUC__ < 4) || ((__GNUC__ == 4) && __GNUC_MINOR__ < 3)
#error "Need at least GCC 4.3 or newer"
#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"
#endif
#if __ARM_ARCH_6M__ || __ARM_ARCH_7M__ || __ARM_ARCH_7EM__
#error "No support for Cortex-M CPUs"
#endif
#if !(__ARM_EABI__ || LJ_TARGET_IOS)
#error "Only ARM EABI or iOS 3.0+ ABI is supported"
#endif
#elif LJ_TARGET_PPC || LJ_TARGET_PPCSPE
#if defined(_SOFT_FLOAT) || defined(_SOFT_DOUBLE)
#error "No support for PowerPC CPUs without double-precision FPU"
#endif
#if defined(_LITTLE_ENDIAN)
#error "No support for little-endian PowerPC"
#endif
#if defined(_LP64)
#error "No support for PowerPC 64 bit mode"
#endif
#elif LJ_TARGET_MIPS
#if defined(__mips_soft_float)
#error "No support for MIPS CPUs without FPU"
#endif
#endif
#endif
/* 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 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
/* 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
#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)
#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
/* Various workarounds for embedded operating systems. */
#if (defined(__ANDROID__) && !defined(LJ_TARGET_X86ORX64)) || defined(__symbian__) || LJ_TARGET_XBOX360
#define LUAJIT_NO_LOG2
#endif
#if defined(__symbian__)
#define LUAJIT_NO_EXP2
#endif
#if defined(LUAJIT_NO_UNWIND) || defined(__symbian__) || LJ_TARGET_IOS || LJ_TARGET_PS3
#define LJ_NO_UNWIND 1
#endif
/* Compatibility with Lua 5.1 vs. 5.2. */
#ifdef LUAJIT_ENABLE_LUA52COMPAT
#define LJ_52 1
#else
#define LJ_52 0
#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
-396
View File
@@ -1,396 +0,0 @@
/*
** Bytecode writer.
** Copyright (C) 2005-2013 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_str.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_bcdump.h"
#include "lj_vm.h"
/* Context for bytecode writer. */
typedef struct BCWriteCtx {
SBuf sb; /* Output buffer. */
lua_State *L; /* Lua state. */
GCproto *pt; /* Root prototype. */
lua_Writer wfunc; /* Writer callback. */
void *wdata; /* Writer callback data. */
int strip; /* Strip debug info. */
int status; /* Status from writer callback. */
} BCWriteCtx;
/* -- Output buffer handling ---------------------------------------------- */
/* Resize buffer if needed. */
static LJ_NOINLINE void bcwrite_resize(BCWriteCtx *ctx, MSize len)
{
MSize sz = ctx->sb.sz * 2;
while (ctx->sb.n + len > sz) sz = sz * 2;
lj_str_resizebuf(ctx->L, &ctx->sb, sz);
}
/* Need a certain amount of buffer space. */
static LJ_AINLINE void bcwrite_need(BCWriteCtx *ctx, MSize len)
{
if (LJ_UNLIKELY(ctx->sb.n + len > ctx->sb.sz))
bcwrite_resize(ctx, len);
}
/* Add memory block to buffer. */
static void bcwrite_block(BCWriteCtx *ctx, const void *p, MSize len)
{
uint8_t *q = (uint8_t *)(ctx->sb.buf + ctx->sb.n);
MSize i;
ctx->sb.n += len;
for (i = 0; i < len; i++) q[i] = ((uint8_t *)p)[i];
}
/* Add byte to buffer. */
static LJ_AINLINE void bcwrite_byte(BCWriteCtx *ctx, uint8_t b)
{
ctx->sb.buf[ctx->sb.n++] = b;
}
/* Add ULEB128 value to buffer. */
static void bcwrite_uleb128(BCWriteCtx *ctx, uint32_t v)
{
MSize n = ctx->sb.n;
uint8_t *p = (uint8_t *)ctx->sb.buf;
for (; v >= 0x80; v >>= 7)
p[n++] = (uint8_t)((v & 0x7f) | 0x80);
p[n++] = (uint8_t)v;
ctx->sb.n = n;
}
/* -- Bytecode writer ----------------------------------------------------- */
/* Write a single constant key/value of a template table. */
static void bcwrite_ktabk(BCWriteCtx *ctx, cTValue *o, int narrow)
{
bcwrite_need(ctx, 1+10);
if (tvisstr(o)) {
const GCstr *str = strV(o);
MSize len = str->len;
bcwrite_need(ctx, 5+len);
bcwrite_uleb128(ctx, BCDUMP_KTAB_STR+len);
bcwrite_block(ctx, strdata(str), len);
} else if (tvisint(o)) {
bcwrite_byte(ctx, BCDUMP_KTAB_INT);
bcwrite_uleb128(ctx, 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. */
bcwrite_byte(ctx, BCDUMP_KTAB_INT);
bcwrite_uleb128(ctx, k);
return;
}
}
bcwrite_byte(ctx, BCDUMP_KTAB_NUM);
bcwrite_uleb128(ctx, o->u32.lo);
bcwrite_uleb128(ctx, o->u32.hi);
} else {
lua_assert(tvispri(o));
bcwrite_byte(ctx, BCDUMP_KTAB_NIL+~itype(o));
}
}
/* Write a template table. */
static void bcwrite_ktab(BCWriteCtx *ctx, 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].val);
}
/* Write number of array slots and hash slots. */
bcwrite_uleb128(ctx, narray);
bcwrite_uleb128(ctx, nhash);
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. */
MSize i = nhash;
Node *node = noderef(t->node) + t->hmask;
for (;; node--)
if (!tvisnil(&node->val)) {
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;
/* 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) {
lua_assert((pt->flags & PROTO_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 {
lua_assert(id == CTID_COMPLEX_DOUBLE);
tp = BCDUMP_KGC_COMPLEX;
}
#endif
} else {
lua_assert(o->gch.gct == ~LJ_TTAB);
tp = BCDUMP_KGC_TAB;
need = 1+2*5;
}
/* Write constant type. */
bcwrite_need(ctx, need);
bcwrite_uleb128(ctx, tp);
/* Write constant data (if any). */
if (tp >= BCDUMP_KGC_STR) {
bcwrite_block(ctx, strdata(gco2str(o)), gco2str(o)->len);
} else if (tp == BCDUMP_KGC_TAB) {
bcwrite_ktab(ctx, gco2tab(o));
#if LJ_HASFFI
} else if (tp != BCDUMP_KGC_CHILD) {
cTValue *p = (TValue *)cdataptr(gco2cd(o));
bcwrite_uleb128(ctx, p[0].u32.lo);
bcwrite_uleb128(ctx, p[0].u32.hi);
if (tp == BCDUMP_KGC_COMPLEX) {
bcwrite_uleb128(ctx, p[1].u32.lo);
bcwrite_uleb128(ctx, p[1].u32.hi);
}
#endif
}
}
}
/* 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);
bcwrite_need(ctx, 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) { /* 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:
bcwrite_uleb128(ctx, 2*(uint32_t)k | ((uint32_t)k & 0x80000000u));
if (k < 0) {
char *p = &ctx->sb.buf[ctx->sb.n-1];
*p = (*p & 7) | ((k>>27) & 0x18);
}
continue;
}
}
bcwrite_uleb128(ctx, 1+(2*o->u32.lo | (o->u32.lo & 0x80000000u)));
if (o->u32.lo >= 0x80000000u) {
char *p = &ctx->sb.buf[ctx->sb.n-1];
*p = (*p & 7) | ((o->u32.lo>>27) & 0x18);
}
bcwrite_uleb128(ctx, o->u32.hi);
}
}
}
/* Write bytecode instructions. */
static void bcwrite_bytecode(BCWriteCtx *ctx, GCproto *pt)
{
MSize nbc = pt->sizebc-1; /* Omit the [JI]FUNC* header. */
#if LJ_HASJIT
uint8_t *p = (uint8_t *)&ctx->sb.buf[ctx->sb.n];
#endif
bcwrite_block(ctx, proto_bc(pt)+1, nbc*(MSize)sizeof(BCIns));
#if LJ_HASJIT
/* Unpatch modified bytecode containing ILOOP/JLOOP etc. */
if ((pt->flags & PROTO_ILOOP) || pt->trace) {
jit_State *J = L2J(ctx->L);
MSize i;
for (i = 0; i < nbc; i++, p += sizeof(BCIns)) {
BCOp op = (BCOp)p[LJ_ENDIAN_SELECT(0, 3)];
if (op == BC_IFORL || op == BC_IITERL || op == BC_ILOOP ||
op == BC_JFORI) {
p[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 = p[LJ_ENDIAN_SELECT(2, 1)] + (p[LJ_ENDIAN_SELECT(3, 0)] << 8);
BCIns ins = traceref(J, rd)->startins;
p[LJ_ENDIAN_SELECT(0, 3)] = (uint8_t)(op-BC_JFORL+BC_FORL);
p[LJ_ENDIAN_SELECT(2, 1)] = bc_c(ins);
p[LJ_ENDIAN_SELECT(3, 0)] = bc_b(ins);
}
}
}
#endif
}
/* Write prototype. */
static void bcwrite_proto(BCWriteCtx *ctx, GCproto *pt)
{
MSize sizedbg = 0;
/* 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. */
lj_str_resetbuf(&ctx->sb);
ctx->sb.n = 5; /* Leave room for final size. */
bcwrite_need(ctx, 4+6*5+(pt->sizebc-1)*(MSize)sizeof(BCIns)+pt->sizeuv*2);
/* Write prototype header. */
bcwrite_byte(ctx, (pt->flags & (PROTO_CHILD|PROTO_VARARG|PROTO_FFI)));
bcwrite_byte(ctx, pt->numparams);
bcwrite_byte(ctx, pt->framesize);
bcwrite_byte(ctx, pt->sizeuv);
bcwrite_uleb128(ctx, pt->sizekgc);
bcwrite_uleb128(ctx, pt->sizekn);
bcwrite_uleb128(ctx, pt->sizebc-1);
if (!ctx->strip) {
if (proto_lineinfo(pt))
sizedbg = pt->sizept - (MSize)((char *)proto_lineinfo(pt) - (char *)pt);
bcwrite_uleb128(ctx, sizedbg);
if (sizedbg) {
bcwrite_uleb128(ctx, pt->firstline);
bcwrite_uleb128(ctx, pt->numline);
}
}
/* Write bytecode instructions and upvalue refs. */
bcwrite_bytecode(ctx, pt);
bcwrite_block(ctx, proto_uv(pt), pt->sizeuv*2);
/* Write constants. */
bcwrite_kgc(ctx, pt);
bcwrite_knum(ctx, pt);
/* Write debug info, if not stripped. */
if (sizedbg) {
bcwrite_need(ctx, sizedbg);
bcwrite_block(ctx, proto_lineinfo(pt), sizedbg);
}
/* Pass buffer to writer function. */
if (ctx->status == 0) {
MSize n = ctx->sb.n - 5;
MSize nn = (lj_fls(n)+8)*9 >> 6;
ctx->sb.n = 5 - nn;
bcwrite_uleb128(ctx, n); /* Fill in final size. */
lua_assert(ctx->sb.n == 5);
ctx->status = ctx->wfunc(ctx->L, ctx->sb.buf+5-nn, 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;
lj_str_resetbuf(&ctx->sb);
bcwrite_need(ctx, 5+5+len);
bcwrite_byte(ctx, BCDUMP_HEAD1);
bcwrite_byte(ctx, BCDUMP_HEAD2);
bcwrite_byte(ctx, BCDUMP_HEAD3);
bcwrite_byte(ctx, BCDUMP_VERSION);
bcwrite_byte(ctx, (ctx->strip ? BCDUMP_F_STRIP : 0) +
(LJ_BE ? BCDUMP_F_BE : 0) +
((ctx->pt->flags & PROTO_FFI) ? BCDUMP_F_FFI : 0));
if (!ctx->strip) {
bcwrite_uleb128(ctx, len);
bcwrite_block(ctx, name, len);
}
ctx->status = ctx->wfunc(ctx->L, ctx->sb.buf, ctx->sb.n, 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(ctx->L, &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(dummy);
lj_str_resizebuf(L, &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,
int strip)
{
BCWriteCtx ctx;
int status;
ctx.L = L;
ctx.pt = pt;
ctx.wfunc = writer;
ctx.wdata = data;
ctx.strip = strip;
ctx.status = 0;
lj_str_initbuf(&ctx.sb);
status = lj_vm_cpcall(L, NULL, &ctx, cpwriter);
if (status == 0) status = ctx.status;
lj_str_freebuf(G(ctx.L), &ctx.sb);
return status;
}
-27
View File
@@ -1,27 +0,0 @@
/*
** C data arithmetic.
** Copyright (C) 2005-2013 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_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
-837
View File
@@ -1,837 +0,0 @@
/*
** FFI C call handling.
** Copyright (C) 2005-2013 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_str.h"
#include "lj_tab.h"
#include "lj_ctype.h"
#include "lj_cconv.h"
#include "lj_cdata.h"
#include "lj_ccall.h"
#include "lj_trace.h"
/* Target-specific handling of register arguments. */
#if LJ_TARGET_X86
/* -- x86 calling conventions --------------------------------------------- */
#if LJ_ABI_WIN
#define CCALL_HANDLE_STRUCTRET \
/* Return structs bigger than 8 by reference (on stack only). */ \
cc->retref = (sz > 8); \
if (cc->retref) cc->stack[nsp++] = (GPRArg)dp;
#define CCALL_HANDLE_COMPLEXRET CCALL_HANDLE_STRUCTRET
#else
#define CCALL_HANDLE_STRUCTRET \
cc->retref = 1; /* Return all structs by reference (in reg or on stack). */ \
if (ngpr < maxgpr) \
cc->gpr[ngpr++] = (GPRArg)dp; \
else \
cc->stack[nsp++] = (GPRArg)dp;
#define CCALL_HANDLE_COMPLEXRET \
/* Return complex float in GPRs and complex double by reference. */ \
cc->retref = (sz > 8); \
if (cc->retref) { \
if (ngpr < maxgpr) \
cc->gpr[ngpr++] = (GPRArg)dp; \
else \
cc->stack[nsp++] = (GPRArg)dp; \
}
#endif
#define CCALL_HANDLE_COMPLEXRET2 \
if (!cc->retref) \
*(int64_t *)dp = *(int64_t *)sp; /* Copy complex float from GPRs. */
#define CCALL_HANDLE_STRUCTARG \
ngpr = maxgpr; /* Pass all structs by value on the stack. */
#define CCALL_HANDLE_COMPLEXARG \
isfp = 1; /* Pass complex by value on stack. */
#define CCALL_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) { \
dp = &cc->gpr[ngpr]; \
ngpr += n; \
goto done; \
} \
}
#elif LJ_TARGET_X64 && LJ_ABI_WIN
/* -- Windows/x64 calling conventions ------------------------------------- */
#define CCALL_HANDLE_STRUCTRET \
/* Return structs of size 1, 2, 4 or 8 in a GPR. */ \
cc->retref = !(sz == 1 || sz == 2 || sz == 4 || sz == 8); \
if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp;
#define CCALL_HANDLE_COMPLEXRET CCALL_HANDLE_STRUCTRET
#define CCALL_HANDLE_COMPLEXRET2 \
if (!cc->retref) \
*(int64_t *)dp = *(int64_t *)sp; /* Copy complex float from GPRs. */
#define CCALL_HANDLE_STRUCTARG \
/* Pass structs of size 1, 2, 4 or 8 in a GPR by value. */ \
if (!(sz == 1 || sz == 2 || sz == 4 || sz == 8)) { \
rp = cdataptr(lj_cdata_new(cts, did, sz)); \
sz = CTSIZE_PTR; /* Pass all other structs by reference. */ \
}
#define CCALL_HANDLE_COMPLEXARG \
/* Pass complex float in a GPR and complex double by reference. */ \
if (sz != 2*sizeof(float)) { \
rp = cdataptr(lj_cdata_new(cts, did, sz)); \
sz = CTSIZE_PTR; \
}
/* Windows/x64 argument registers are strictly positional (use ngpr). */
#define CCALL_HANDLE_REGARG \
if (isfp) { \
if (ngpr < 4) { dp = &cc->fpr[ngpr++]; nfpr = ngpr; goto done; } \
} else { \
if (ngpr < 4) { dp = &cc->gpr[ngpr++]; goto done; } \
}
#elif LJ_TARGET_X64
/* -- POSIX/x64 calling conventions --------------------------------------- */
#define CCALL_HANDLE_STRUCTRET \
int rcl[2]; rcl[0] = rcl[1] = 0; \
if (ccall_classify_struct(cts, ctr, rcl, 0)) { \
cc->retref = 1; /* Return struct by reference. */ \
cc->gpr[ngpr++] = (GPRArg)dp; \
} else { \
cc->retref = 0; /* Return small structs in registers. */ \
}
#define CCALL_HANDLE_STRUCTRET2 \
int rcl[2]; rcl[0] = rcl[1] = 0; \
ccall_classify_struct(cts, ctr, rcl, 0); \
ccall_struct_ret(cc, rcl, dp, ctr->size);
#define CCALL_HANDLE_COMPLEXRET \
/* Complex values are returned in one or two FPRs. */ \
cc->retref = 0;
#define CCALL_HANDLE_COMPLEXRET2 \
if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPR. */ \
*(int64_t *)dp = cc->fpr[0].l[0]; \
} else { /* Copy non-contiguous complex double from FPRs. */ \
((int64_t *)dp)[0] = cc->fpr[0].l[0]; \
((int64_t *)dp)[1] = cc->fpr[1].l[0]; \
}
#define CCALL_HANDLE_STRUCTARG \
int rcl[2]; rcl[0] = rcl[1] = 0; \
if (!ccall_classify_struct(cts, d, rcl, 0)) { \
cc->nsp = nsp; cc->ngpr = ngpr; cc->nfpr = nfpr; \
if (ccall_struct_arg(cc, cts, d, rcl, o, narg)) goto err_nyi; \
nsp = cc->nsp; ngpr = cc->ngpr; nfpr = cc->nfpr; \
continue; \
} /* Pass all other structs by value on stack. */
#define CCALL_HANDLE_COMPLEXARG \
isfp = 2; /* Pass complex in FPRs or on stack. Needs postprocessing. */
#define CCALL_HANDLE_REGARG \
if (isfp) { /* Try to pass argument in FPRs. */ \
if (nfpr + n <= CCALL_NARG_FPR) { \
dp = &cc->fpr[nfpr]; \
nfpr += n; \
goto done; \
} \
} else { /* Try to pass argument in GPRs. */ \
/* Note that reordering is explicitly allowed in the x64 ABI. */ \
if (n <= 2 && ngpr + n <= maxgpr) { \
dp = &cc->gpr[ngpr]; \
ngpr += n; \
goto done; \
} \
}
#elif LJ_TARGET_ARM
/* -- ARM calling conventions --------------------------------------------- */
#if LJ_ABI_SOFTFP
#define CCALL_HANDLE_STRUCTRET \
/* Return structs of size <= 4 in a GPR. */ \
cc->retref = !(sz <= 4); \
if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp;
#define CCALL_HANDLE_COMPLEXRET \
cc->retref = 1; /* Return all complex values by reference. */ \
cc->gpr[ngpr++] = (GPRArg)dp;
#define CCALL_HANDLE_COMPLEXRET2 \
UNUSED(dp); /* Nothing to do. */
#define CCALL_HANDLE_STRUCTARG \
/* Pass all structs by value in registers and/or on the stack. */
#define CCALL_HANDLE_COMPLEXARG \
/* Pass complex by value in 2 or 4 GPRs. */
#define CCALL_HANDLE_REGARG_FP1
#define CCALL_HANDLE_REGARG_FP2
#else
#define CCALL_HANDLE_STRUCTRET \
cc->retref = !ccall_classify_struct(cts, ctr, ct); \
if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp;
#define CCALL_HANDLE_STRUCTRET2 \
if (ccall_classify_struct(cts, ctr, ct) > 1) sp = (uint8_t *)&cc->fpr[0]; \
memcpy(dp, sp, ctr->size);
#define CCALL_HANDLE_COMPLEXRET \
if (!(ct->info & CTF_VARARG)) cc->retref = 0; /* Return complex in FPRs. */
#define CCALL_HANDLE_COMPLEXRET2 \
if (!(ct->info & CTF_VARARG)) memcpy(dp, &cc->fpr[0], ctr->size);
#define CCALL_HANDLE_STRUCTARG \
isfp = (ccall_classify_struct(cts, d, ct) > 1);
/* Pass all structs by value in registers and/or on the stack. */
#define CCALL_HANDLE_COMPLEXARG \
isfp = 1; /* Pass complex by value in FPRs or on stack. */
#define CCALL_HANDLE_REGARG_FP1 \
if (isfp && !(ct->info & CTF_VARARG)) { \
if ((d->info & CTF_ALIGN) > CTALIGN_PTR) { \
if (nfpr + (n >> 1) <= CCALL_NARG_FPR) { \
dp = &cc->fpr[nfpr]; \
nfpr += (n >> 1); \
goto done; \
} \
} else { \
if (sz > 1 && fprodd != nfpr) fprodd = 0; \
if (fprodd) { \
if (2*nfpr+n <= 2*CCALL_NARG_FPR+1) { \
dp = (void *)&cc->fpr[fprodd-1].f[1]; \
nfpr += (n >> 1); \
if ((n & 1)) fprodd = 0; else fprodd = nfpr-1; \
goto done; \
} \
} else { \
if (2*nfpr+n <= 2*CCALL_NARG_FPR) { \
dp = (void *)&cc->fpr[nfpr]; \
nfpr += (n >> 1); \
if ((n & 1)) fprodd = ++nfpr; else fprodd = 0; \
goto done; \
} \
} \
} \
fprodd = 0; /* No reordering after the first FP value is on stack. */ \
} else {
#define CCALL_HANDLE_REGARG_FP2 }
#endif
#define CCALL_HANDLE_REGARG \
CCALL_HANDLE_REGARG_FP1 \
if ((d->info & CTF_ALIGN) > CTALIGN_PTR) { \
if (ngpr < maxgpr) \
ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
} \
if (ngpr < maxgpr) { \
dp = &cc->gpr[ngpr]; \
if (ngpr + n > maxgpr) { \
nsp += ngpr + n - maxgpr; /* Assumes contiguous gpr/stack fields. */ \
if (nsp > CCALL_MAXSTACK) goto err_nyi; /* Too many arguments. */ \
ngpr = maxgpr; \
} else { \
ngpr += n; \
} \
goto done; \
} CCALL_HANDLE_REGARG_FP2
#define CCALL_HANDLE_RET \
if ((ct->info & CTF_VARARG)) sp = (uint8_t *)&cc->gpr[0];
#elif LJ_TARGET_PPC
/* -- PPC calling conventions --------------------------------------------- */
#define CCALL_HANDLE_STRUCTRET \
cc->retref = 1; /* Return all structs by reference. */ \
cc->gpr[ngpr++] = (GPRArg)dp;
#define CCALL_HANDLE_COMPLEXRET \
/* Complex values are returned in 2 or 4 GPRs. */ \
cc->retref = 0;
#define CCALL_HANDLE_COMPLEXRET2 \
memcpy(dp, sp, ctr->size); /* Copy complex from GPRs. */
#define CCALL_HANDLE_STRUCTARG \
rp = cdataptr(lj_cdata_new(cts, did, sz)); \
sz = CTSIZE_PTR; /* Pass all structs by reference. */
#define CCALL_HANDLE_COMPLEXARG \
/* Pass complex by value in 2 or 4 GPRs. */
#define CCALL_HANDLE_REGARG \
if (isfp) { /* Try to pass argument in FPRs. */ \
if (nfpr + 1 <= CCALL_NARG_FPR) { \
dp = &cc->fpr[nfpr]; \
nfpr += 1; \
d = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ \
goto done; \
} \
} else { /* Try to pass argument in GPRs. */ \
if (n > 1) { \
lua_assert(n == 2 || n == 4); /* int64_t or complex (float). */ \
if (ctype_isinteger(d->info)) \
ngpr = (ngpr + 1u) & ~1u; /* Align int64_t to regpair. */ \
else if (ngpr + n > maxgpr) \
ngpr = maxgpr; /* Prevent reordering. */ \
} \
if (ngpr + n <= maxgpr) { \
dp = &cc->gpr[ngpr]; \
ngpr += n; \
goto done; \
} \
}
#define CCALL_HANDLE_RET \
if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
ctr = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */
#elif LJ_TARGET_PPCSPE
/* -- PPC/SPE calling conventions ----------------------------------------- */
#define CCALL_HANDLE_STRUCTRET \
cc->retref = 1; /* Return all structs by reference. */ \
cc->gpr[ngpr++] = (GPRArg)dp;
#define CCALL_HANDLE_COMPLEXRET \
/* Complex values are returned in 2 or 4 GPRs. */ \
cc->retref = 0;
#define CCALL_HANDLE_COMPLEXRET2 \
memcpy(dp, sp, ctr->size); /* Copy complex from GPRs. */
#define CCALL_HANDLE_STRUCTARG \
rp = cdataptr(lj_cdata_new(cts, did, sz)); \
sz = CTSIZE_PTR; /* Pass all structs by reference. */
#define CCALL_HANDLE_COMPLEXARG \
/* Pass complex by value in 2 or 4 GPRs. */
/* PPC/SPE has a softfp ABI. */
#define CCALL_HANDLE_REGARG \
if (n > 1) { /* Doesn't fit in a single GPR? */ \
lua_assert(n == 2 || n == 4); /* int64_t, double or complex (float). */ \
if (n == 2) \
ngpr = (ngpr + 1u) & ~1u; /* Only align 64 bit value to regpair. */ \
else if (ngpr + n > maxgpr) \
ngpr = maxgpr; /* Prevent reordering. */ \
} \
if (ngpr + n <= maxgpr) { \
dp = &cc->gpr[ngpr]; \
ngpr += n; \
goto done; \
}
#elif LJ_TARGET_MIPS
/* -- MIPS calling conventions -------------------------------------------- */
#define CCALL_HANDLE_STRUCTRET \
cc->retref = 1; /* Return all structs by reference. */ \
cc->gpr[ngpr++] = (GPRArg)dp;
#define CCALL_HANDLE_COMPLEXRET \
/* Complex values are returned in 1 or 2 FPRs. */ \
cc->retref = 0;
#define CCALL_HANDLE_COMPLEXRET2 \
if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPRs. */ \
((float *)dp)[0] = cc->fpr[0].f; \
((float *)dp)[1] = cc->fpr[1].f; \
} else { /* Copy complex double from FPRs. */ \
((double *)dp)[0] = cc->fpr[0].d; \
((double *)dp)[1] = cc->fpr[1].d; \
}
#define CCALL_HANDLE_STRUCTARG \
/* Pass all structs by value in registers and/or on the stack. */
#define CCALL_HANDLE_COMPLEXARG \
/* Pass complex by value in 2 or 4 GPRs. */
#define CCALL_HANDLE_REGARG \
if (isfp && nfpr < CCALL_NARG_FPR && !(ct->info & CTF_VARARG)) { \
/* Try to pass argument in FPRs. */ \
dp = n == 1 ? (void *)&cc->fpr[nfpr].f : (void *)&cc->fpr[nfpr].d; \
nfpr++; ngpr += n; \
goto done; \
} else { /* Try to pass argument in GPRs. */ \
nfpr = CCALL_NARG_FPR; \
if ((d->info & CTF_ALIGN) > CTALIGN_PTR) \
ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
if (ngpr < maxgpr) { \
dp = &cc->gpr[ngpr]; \
if (ngpr + n > maxgpr) { \
nsp += ngpr + n - maxgpr; /* Assumes contiguous gpr/stack fields. */ \
if (nsp > CCALL_MAXSTACK) goto err_nyi; /* Too many arguments. */ \
ngpr = maxgpr; \
} else { \
ngpr += n; \
} \
goto done; \
} \
}
#define CCALL_HANDLE_RET \
if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
sp = (uint8_t *)&cc->fpr[0].f;
#else
#error "Missing calling convention definitions for this architecture"
#endif
#ifndef CCALL_HANDLE_STRUCTRET2
#define CCALL_HANDLE_STRUCTRET2 \
memcpy(dp, sp, ctr->size); /* Copy struct return value from GPRs. */
#endif
/* -- x64 struct classification ------------------------------------------- */
#if LJ_TARGET_X64 && !LJ_ABI_WIN
/* Register classes for x64 struct classification. */
#define CCALL_RCL_INT 1
#define CCALL_RCL_SSE 2
#define CCALL_RCL_MEM 4
/* NYI: classify vectors. */
static int ccall_classify_struct(CTState *cts, CType *ct, int *rcl, CTSize ofs);
/* Classify a C type. */
static void ccall_classify_ct(CTState *cts, CType *ct, int *rcl, CTSize ofs)
{
if (ctype_isarray(ct->info)) {
CType *cct = ctype_rawchild(cts, ct);
CTSize eofs, esz = cct->size, asz = ct->size;
for (eofs = 0; eofs < asz; eofs += esz)
ccall_classify_ct(cts, cct, rcl, ofs+eofs);
} else if (ctype_isstruct(ct->info)) {
ccall_classify_struct(cts, ct, rcl, ofs);
} else {
int cl = ctype_isfp(ct->info) ? CCALL_RCL_SSE : CCALL_RCL_INT;
lua_assert(ctype_hassize(ct->info));
if ((ofs & (ct->size-1))) cl = CCALL_RCL_MEM; /* Unaligned. */
rcl[(ofs >= 8)] |= cl;
}
}
/* Recursively classify a struct based on its fields. */
static int ccall_classify_struct(CTState *cts, CType *ct, int *rcl, CTSize ofs)
{
if (ct->size > 16) return CCALL_RCL_MEM; /* Too big, gets memory class. */
while (ct->sib) {
CTSize fofs;
ct = ctype_get(cts, ct->sib);
fofs = ofs+ct->size;
if (ctype_isfield(ct->info))
ccall_classify_ct(cts, ctype_rawchild(cts, ct), rcl, fofs);
else if (ctype_isbitfield(ct->info))
rcl[(fofs >= 8)] |= CCALL_RCL_INT; /* NYI: unaligned bitfields? */
else if (ctype_isxattrib(ct->info, CTA_SUBTYPE))
ccall_classify_struct(cts, ctype_rawchild(cts, ct), rcl, fofs);
}
return ((rcl[0]|rcl[1]) & CCALL_RCL_MEM); /* Memory class? */
}
/* Try to split up a small struct into registers. */
static int ccall_struct_reg(CCallState *cc, GPRArg *dp, int *rcl)
{
MSize ngpr = cc->ngpr, nfpr = cc->nfpr;
uint32_t i;
for (i = 0; i < 2; i++) {
lua_assert(!(rcl[i] & CCALL_RCL_MEM));
if ((rcl[i] & CCALL_RCL_INT)) { /* Integer class takes precedence. */
if (ngpr >= CCALL_NARG_GPR) return 1; /* Register overflow. */
cc->gpr[ngpr++] = dp[i];
} else if ((rcl[i] & CCALL_RCL_SSE)) {
if (nfpr >= CCALL_NARG_FPR) return 1; /* Register overflow. */
cc->fpr[nfpr++].l[0] = dp[i];
}
}
cc->ngpr = ngpr; cc->nfpr = nfpr;
return 0; /* Ok. */
}
/* Pass a small struct argument. */
static int ccall_struct_arg(CCallState *cc, CTState *cts, CType *d, int *rcl,
TValue *o, int narg)
{
GPRArg dp[2];
dp[0] = dp[1] = 0;
/* Convert to temp. struct. */
lj_cconv_ct_tv(cts, d, (uint8_t *)dp, o, CCF_ARG(narg));
if (ccall_struct_reg(cc, dp, rcl)) { /* Register overflow? Pass on stack. */
MSize nsp = cc->nsp, n = rcl[1] ? 2 : 1;
if (nsp + n > CCALL_MAXSTACK) return 1; /* Too many arguments. */
cc->nsp = nsp + n;
memcpy(&cc->stack[nsp], dp, n*CTSIZE_PTR);
}
return 0; /* Ok. */
}
/* Combine returned small struct. */
static void ccall_struct_ret(CCallState *cc, int *rcl, uint8_t *dp, CTSize sz)
{
GPRArg sp[2];
MSize ngpr = 0, nfpr = 0;
uint32_t i;
for (i = 0; i < 2; i++) {
if ((rcl[i] & CCALL_RCL_INT)) { /* Integer class takes precedence. */
sp[i] = cc->gpr[ngpr++];
} else if ((rcl[i] & CCALL_RCL_SSE)) {
sp[i] = cc->fpr[nfpr++].l[0];
}
}
memcpy(dp, sp, sz);
}
#endif
/* -- ARM hard-float ABI struct classification ---------------------------- */
#if LJ_TARGET_ARM && !LJ_ABI_SOFTFP
/* Classify a struct based on its fields. */
static unsigned int ccall_classify_struct(CTState *cts, CType *ct, CType *ctf)
{
CTSize sz = ct->size;
unsigned int r = 0, n = 0, isu = (ct->info & CTF_UNION);
if ((ctf->info & CTF_VARARG)) goto noth;
while (ct->sib) {
ct = ctype_get(cts, ct->sib);
if (ctype_isfield(ct->info)) {
CType *sct = ctype_rawchild(cts, ct);
if (ctype_isfp(sct->info)) {
r |= sct->size;
if (!isu) n++; else if (n == 0) n = 1;
} else if (ctype_iscomplex(sct->info)) {
r |= (sct->size >> 1);
if (!isu) n += 2; else if (n < 2) n = 2;
} else {
goto noth;
}
} else if (ctype_isbitfield(ct->info)) {
goto noth;
} else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) {
CType *sct = ctype_rawchild(cts, ct);
if (sct->size > 0) {
unsigned int s = ccall_classify_struct(cts, sct, ctf);
if (s <= 1) goto noth;
r |= (s & 255);
if (!isu) n += (s >> 8); else if (n < (s >>8)) n = (s >> 8);
}
}
}
if ((r == 4 || r == 8) && n <= 4)
return r + (n << 8);
noth: /* Not a homogeneous float/double aggregate. */
return (sz <= 4); /* Return structs of size <= 4 in a GPR. */
}
#endif
/* -- Common C call handling ---------------------------------------------- */
/* Infer the destination CTypeID for a vararg argument. */
CTypeID lj_ccall_ctid_vararg(CTState *cts, cTValue *o)
{
if (tvisnumber(o)) {
return CTID_DOUBLE;
} else if (tviscdata(o)) {
CTypeID id = cdataV(o)->ctypeid;
CType *s = ctype_get(cts, id);
if (ctype_isrefarray(s->info)) {
return lj_ctype_intern(cts,
CTINFO(CT_PTR, CTALIGN_PTR|ctype_cid(s->info)), CTSIZE_PTR);
} else if (ctype_isstruct(s->info) || ctype_isfunc(s->info)) {
/* NYI: how to pass a struct by value in a vararg argument? */
return lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|id), CTSIZE_PTR);
} else if (ctype_isfp(s->info) && s->size == sizeof(float)) {
return CTID_DOUBLE;
} else {
return id;
}
} else if (tvisstr(o)) {
return CTID_P_CCHAR;
} else if (tvisbool(o)) {
return CTID_BOOL;
} else {
return CTID_P_VOID;
}
}
/* Setup arguments for C call. */
static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
CCallState *cc)
{
int gcsteps = 0;
TValue *o, *top = L->top;
CTypeID fid;
CType *ctr;
MSize maxgpr, ngpr = 0, nsp = 0, narg;
#if CCALL_NARG_FPR
MSize nfpr = 0;
#if LJ_TARGET_ARM
MSize fprodd = 0;
#endif
#endif
/* Clear unused regs to get some determinism in case of misdeclaration. */
memset(cc->gpr, 0, sizeof(cc->gpr));
#if CCALL_NUM_FPR
memset(cc->fpr, 0, sizeof(cc->fpr));
#endif
#if LJ_TARGET_X86
/* x86 has several different calling conventions. */
cc->resx87 = 0;
switch (ctype_cconv(ct->info)) {
case CTCC_FASTCALL: maxgpr = 2; break;
case CTCC_THISCALL: maxgpr = 1; break;
default: maxgpr = 0; break;
}
#else
maxgpr = CCALL_NARG_GPR;
#endif
/* Perform required setup for some result types. */
ctr = ctype_rawchild(cts, ct);
if (ctype_isvector(ctr->info)) {
if (!(CCALL_VECTOR_REG && (ctr->size == 8 || ctr->size == 16)))
goto err_nyi;
} else if (ctype_iscomplex(ctr->info) || ctype_isstruct(ctr->info)) {
/* Preallocate cdata object and anchor it after arguments. */
CTSize sz = ctr->size;
GCcdata *cd = lj_cdata_new(cts, ctype_cid(ct->info), sz);
void *dp = cdataptr(cd);
setcdataV(L, L->top++, cd);
if (ctype_isstruct(ctr->info)) {
CCALL_HANDLE_STRUCTRET
} else {
CCALL_HANDLE_COMPLEXRET
}
#if LJ_TARGET_X86
} else if (ctype_isfp(ctr->info)) {
cc->resx87 = ctr->size == sizeof(float) ? 1 : 2;
#endif
}
/* Skip initial attributes. */
fid = ct->sib;
while (fid) {
CType *ctf = ctype_get(cts, fid);
if (!ctype_isattrib(ctf->info)) break;
fid = ctf->sib;
}
/* Walk through all passed arguments. */
for (o = L->base+1, narg = 1; o < top; o++, narg++) {
CTypeID did;
CType *d;
CTSize sz;
MSize n, isfp = 0, isva = 0;
void *dp, *rp = NULL;
if (fid) { /* Get argument type from field. */
CType *ctf = ctype_get(cts, fid);
fid = ctf->sib;
lua_assert(ctype_isfield(ctf->info));
did = ctype_cid(ctf->info);
} else {
if (!(ct->info & CTF_VARARG))
lj_err_caller(L, LJ_ERR_FFI_NUMARG); /* Too many arguments. */
did = lj_ccall_ctid_vararg(cts, o); /* Infer vararg type. */
isva = 1;
}
d = ctype_raw(cts, did);
sz = d->size;
/* Find out how (by value/ref) and where (GPR/FPR) to pass an argument. */
if (ctype_isnum(d->info)) {
if (sz > 8) goto err_nyi;
if ((d->info & CTF_FP))
isfp = 1;
} else if (ctype_isvector(d->info)) {
if (CCALL_VECTOR_REG && (sz == 8 || sz == 16))
isfp = 1;
else
goto err_nyi;
} else if (ctype_isstruct(d->info)) {
CCALL_HANDLE_STRUCTARG
} else if (ctype_iscomplex(d->info)) {
CCALL_HANDLE_COMPLEXARG
} else {
sz = CTSIZE_PTR;
}
sz = (sz + CTSIZE_PTR-1) & ~(CTSIZE_PTR-1);
n = sz / CTSIZE_PTR; /* Number of GPRs or stack slots needed. */
CCALL_HANDLE_REGARG /* Handle register arguments. */
/* Otherwise pass argument on stack. */
if (CCALL_ALIGN_STACKARG && !rp && (d->info & CTF_ALIGN) > CTALIGN_PTR) {
MSize align = (1u << ctype_align(d->info-CTALIGN_PTR)) -1;
nsp = (nsp + align) & ~align; /* Align argument on stack. */
}
if (nsp + n > CCALL_MAXSTACK) { /* Too many arguments. */
err_nyi:
lj_err_caller(L, LJ_ERR_FFI_NYICALL);
}
dp = &cc->stack[nsp];
nsp += n;
isva = 0;
done:
if (rp) { /* Pass by reference. */
gcsteps++;
*(void **)dp = rp;
dp = rp;
}
lj_cconv_ct_tv(cts, d, (uint8_t *)dp, o, CCF_ARG(narg));
/* Extend passed integers to 32 bits at least. */
if (ctype_isinteger_or_bool(d->info) && d->size < 4) {
if (d->info & CTF_UNSIGNED)
*(uint32_t *)dp = d->size == 1 ? (uint32_t)*(uint8_t *)dp :
(uint32_t)*(uint16_t *)dp;
else
*(int32_t *)dp = d->size == 1 ? (int32_t)*(int8_t *)dp :
(int32_t)*(int16_t *)dp;
}
#if LJ_TARGET_X64 && LJ_ABI_WIN
if (isva) { /* Windows/x64 mirrors varargs in both register sets. */
if (nfpr == ngpr)
cc->gpr[ngpr-1] = cc->fpr[ngpr-1].l[0];
else
cc->fpr[ngpr-1].l[0] = cc->gpr[ngpr-1];
}
#else
UNUSED(isva);
#endif
#if LJ_TARGET_X64 && !LJ_ABI_WIN
if (isfp == 2 && n == 2 && (uint8_t *)dp == (uint8_t *)&cc->fpr[nfpr-2]) {
cc->fpr[nfpr-1].d[0] = cc->fpr[nfpr-2].d[1]; /* Split complex double. */
cc->fpr[nfpr-2].d[1] = 0;
}
#else
UNUSED(isfp);
#endif
}
if (fid) lj_err_caller(L, LJ_ERR_FFI_NUMARG); /* Too few arguments. */
#if LJ_TARGET_X64 || LJ_TARGET_PPC
cc->nfpr = nfpr; /* Required for vararg functions. */
#endif
cc->nsp = nsp;
cc->spadj = (CCALL_SPS_FREE + CCALL_SPS_EXTRA)*CTSIZE_PTR;
if (nsp > CCALL_SPS_FREE)
cc->spadj += (((nsp-CCALL_SPS_FREE)*CTSIZE_PTR + 15u) & ~15u);
return gcsteps;
}
/* Get results from C call. */
static int ccall_get_results(lua_State *L, CTState *cts, CType *ct,
CCallState *cc, int *ret)
{
CType *ctr = ctype_rawchild(cts, ct);
uint8_t *sp = (uint8_t *)&cc->gpr[0];
if (ctype_isvoid(ctr->info)) {
*ret = 0; /* Zero results. */
return 0; /* No additional GC step. */
}
*ret = 1; /* One result. */
if (ctype_isstruct(ctr->info)) {
/* Return cdata object which is already on top of stack. */
if (!cc->retref) {
void *dp = cdataptr(cdataV(L->top-1)); /* Use preallocated object. */
CCALL_HANDLE_STRUCTRET2
}
return 1; /* One GC step. */
}
if (ctype_iscomplex(ctr->info)) {
/* Return cdata object which is already on top of stack. */
void *dp = cdataptr(cdataV(L->top-1)); /* Use preallocated object. */
CCALL_HANDLE_COMPLEXRET2
return 1; /* One GC step. */
}
if (LJ_BE && ctype_isinteger_or_bool(ctr->info) && ctr->size < CTSIZE_PTR)
sp += (CTSIZE_PTR - ctr->size);
#if CCALL_NUM_FPR
if (ctype_isfp(ctr->info) || ctype_isvector(ctr->info))
sp = (uint8_t *)&cc->fpr[0];
#endif
#ifdef CCALL_HANDLE_RET
CCALL_HANDLE_RET
#endif
/* No reference types end up here, so there's no need for the CTypeID. */
lua_assert(!(ctype_isrefarray(ctr->info) || ctype_isstruct(ctr->info)));
return lj_cconv_tv_ct(cts, ctr, 0, L->top-1, sp);
}
/* Call C function. */
int lj_ccall_func(lua_State *L, GCcdata *cd)
{
CTState *cts = ctype_cts(L);
CType *ct = ctype_raw(cts, cd->ctypeid);
CTSize sz = CTSIZE_PTR;
if (ctype_isptr(ct->info)) {
sz = ct->size;
ct = ctype_rawchild(cts, ct);
}
if (ctype_isfunc(ct->info)) {
CCallState cc;
int gcsteps, ret;
cc.func = (void (*)(void))cdata_getptr(cdataptr(cd), sz);
gcsteps = ccall_set_args(L, cts, ct, &cc);
ct = (CType *)((intptr_t)ct-(intptr_t)cts->tab);
cts->cb.slot = ~0u;
lj_vm_ffi_call(&cc);
if (cts->cb.slot != ~0u) { /* Blacklist function that called a callback. */
TValue tv;
setlightudV(&tv, (void *)cc.func);
setboolV(lj_tab_set(L, cts->miscmap, &tv), 1);
}
ct = (CType *)((intptr_t)ct+(intptr_t)cts->tab); /* May be reallocated. */
gcsteps += ccall_get_results(L, cts, ct, &cc, &ret);
#if LJ_TARGET_X86 && LJ_ABI_WIN
/* Automatically detect __stdcall and fix up C function declaration. */
if (cc.spadj && ctype_cconv(ct->info) == CTCC_CDECL) {
CTF_INSERT(ct->info, CCONV, CTCC_STDCALL);
lj_trace_abort(G(L));
}
#endif
while (gcsteps-- > 0)
lj_gc_check(L);
return ret;
}
return -1; /* Not a function. */
}
#endif
-171
View File
@@ -1,171 +0,0 @@
/*
** FFI C call handling.
** Copyright (C) 2005-2013 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_PPC
#define CCALL_NARG_GPR 8
#define CCALL_NARG_FPR 8
#define CCALL_NRET_GPR 4 /* For complex double. */
#define CCALL_NRET_FPR 1
#define CCALL_SPS_EXTRA 4
#define CCALL_SPS_FREE 0
typedef intptr_t GPRArg;
typedef double FPRArg;
#elif LJ_TARGET_PPCSPE
#define CCALL_NARG_GPR 8
#define CCALL_NARG_FPR 0
#define CCALL_NRET_GPR 4 /* For softfp complex double. */
#define CCALL_NRET_FPR 0
#define CCALL_SPS_FREE 0 /* NYI */
typedef intptr_t GPRArg;
#elif LJ_TARGET_MIPS
#define CCALL_NARG_GPR 4
#define CCALL_NARG_FPR 2
#define CCALL_NRET_GPR 2
#define CCALL_NRET_FPR 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;
#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_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_MAXSTACK 32
/* -- 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 stack slots. */
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_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_MAXSTACK]; /* 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
-641
View File
@@ -1,641 +0,0 @@
/*
** FFI C callback handling.
** Copyright (C) 2005-2013 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
/* Disabled callback support. */
#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+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
#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))
#elif LJ_TARGET_PPC
#define CALLBACK_MCODE_HEAD 24
#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))
#elif LJ_TARGET_MIPS
#define CALLBACK_MCODE_HEAD 24
#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))
#else
/* Missing support for this architecture. */
#define CALLBACK_SLOT2OFS(slot) (0*(slot))
#define CALLBACK_OFS2SLOT(ofs) (0*(ofs))
#define CALLBACK_MAX_SLOT 0
#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) UNUSED(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);
*p++ = XI_MOVri | RID_EBP;
*(int32_t *)p = i32ptr(g); p += 4;
#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);
}
}
lua_assert(p - page <= CALLBACK_MCODE_SIZE);
}
#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++;
}
lua_assert(p - page <= CALLBACK_MCODE_SIZE);
}
#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++;
}
lua_assert(p - page <= CALLBACK_MCODE_SIZE);
}
#elif LJ_TARGET_MIPS
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++ = MIPSI_SW | MIPSF_T(RID_R1)|MIPSF_S(RID_SP) | 0;
*p++ = MIPSI_LUI | MIPSF_T(RID_R3) | (u32ptr(target) >> 16);
*p++ = MIPSI_LUI | MIPSF_T(RID_R2) | (u32ptr(g) >> 16);
*p++ = MIPSI_ORI | MIPSF_T(RID_R3)|MIPSF_S(RID_R3) |(u32ptr(target)&0xffff);
*p++ = MIPSI_JR | MIPSF_S(RID_R3);
*p++ = MIPSI_ORI | MIPSF_T(RID_R2)|MIPSF_S(RID_R2) | (u32ptr(g)&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;
}
lua_assert(p - page <= CALLBACK_MCODE_SIZE);
}
#else
/* Missing support for this architecture. */
#define callback_mcode_init(g, p) UNUSED(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
#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;
if (CALLBACK_MAX_SLOT == 0)
lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
#if LJ_TARGET_WINDOWS
p = VirtualAlloc(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), 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;
callback_mcode_init(cts->g, p);
lj_mcode_sync(p, (char *)p + sz);
#if LJ_TARGET_WINDOWS
{
DWORD oprot;
VirtualProtect(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 < 4) { sp = &cts->cb.fpr[ngpr++]; nfpr = ngpr; goto done; } \
} else { \
if (ngpr < 4) { 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_PPC
#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. */ \
if (n > 1) { \
lua_assert(ctype_isinteger(cta->info) && n == 2); /* int64_t. */ \
ngpr = (ngpr + 1u) & ~1u; /* Align int64_t to regpair. */ \
} \
if (ngpr + n <= maxgpr) { \
sp = &cts->cb.gpr[ngpr]; \
ngpr += n; \
goto done; \
} \
}
#define CALLBACK_HANDLE_RET \
if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
*(double *)dp = *(float *)dp; /* FPRs always hold doubles. */
#elif LJ_TARGET_MIPS
#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; \
if (n > 1) ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
if (ngpr + n <= maxgpr) { \
sp = &cts->cb.gpr[ngpr]; \
ngpr += n; \
goto done; \
} \
}
#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;
CType *ct;
GCfunc *fn;
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);
fn = funcV(lj_tab_getint(cts->miscmap, (int32_t)slot));
} else { /* Must set up frame first, before throwing the error. */
ct = NULL;
rid = 0;
fn = (GCfunc *)L;
}
o->u32.lo = LJ_CONT_FFI_CALLBACK; /* Continuation returns from callback. */
o->u32.hi = rid; /* Return type. x86: +(spadj<<16). */
o++;
setframe_gc(o, obj2gco(fn));
setframe_ftsz(o, (int)((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;
lua_assert(ctype_isfield(ctf->info));
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)
sp = (void *)((uint8_t *)sp + CTSIZE_PTR-cta->size);
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)
(L->base-2)->u32.hi |= (nsp << (16+2));
#endif
}
/* Convert Lua object to callback result. */
static void callback_conv_result(CTState *cts, lua_State *L, TValue *o)
{
CType *ctr = ctype_raw(cts, (uint16_t)(L->base-2)->u32.hi);
#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
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_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;
lua_assert(L != NULL);
if (gcref(g->jit_L)) {
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->cframe = cframe_prev(L->cframe);
L->top -= 2;
L->base = obase;
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;
lua_assert(ctype_isfield(ctf->info));
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
-31
View File
@@ -1,31 +0,0 @@
/*
** Trace recorder for C data operations.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_CRECORD_H
#define _LJ_CRECORD_H
#include "lj_obj.h"
#include "lj_jit.h"
#include "lj_ffrecord.h"
#if LJ_HASJIT && LJ_HASFFI
LJ_FUNC void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_cdata_call(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_clib_index(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_new(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_errno(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_string(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_copy(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_fill(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_typeof(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_istype(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_abi(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_xof(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_gc(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL lj_crecord_tonumber(jit_State *J, RecordFFData *rd);
#endif
#endif
-596
View File
@@ -1,596 +0,0 @@
/*
** Debugging and introspection.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
*/
#define lj_debug_c
#define LUA_CORE
#include "lj_obj.h"
#include "lj_err.h"
#include "lj_debug.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_state.h"
#include "lj_frame.h"
#include "lj_bc.h"
#if LJ_HASJIT
#include "lj_jit.h"
#endif
/* -- Frames -------------------------------------------------------------- */
/* Get frame corresponding to a level. */
cTValue *lj_debug_frame(lua_State *L, int level, int *size)
{
cTValue *frame, *nextframe, *bot = tvref(L->stack);
/* Traverse frames backwards. */
for (nextframe = frame = L->base-1; frame > bot; ) {
if (frame_gc(frame) == obj2gco(L))
level++; /* Skip dummy frames. See lj_meta_call(). */
if (level-- == 0) {
*size = (int)(nextframe - frame);
return frame; /* Level found. */
}
nextframe = frame;
if (frame_islua(frame)) {
frame = frame_prevl(frame);
} else {
if (frame_isvarg(frame))
level++; /* Skip vararg pseudo-frame. */
frame = frame_prevd(frame);
}
}
*size = level;
return NULL; /* Level not found. */
}
/* Invalid bytecode position. */
#define NO_BCPOS (~(BCPos)0)
/* Return bytecode position for function/frame or NO_BCPOS. */
static BCPos debug_framepc(lua_State *L, GCfunc *fn, cTValue *nextframe)
{
const BCIns *ins;
GCproto *pt;
BCPos pos;
lua_assert(fn->c.gct == ~LJ_TFUNC || fn->c.gct == ~LJ_TTHREAD);
if (!isluafunc(fn)) { /* Cannot derive a PC for non-Lua functions. */
return NO_BCPOS;
} else if (nextframe == NULL) { /* Lua function on top. */
void *cf = cframe_raw(L->cframe);
if (cf == NULL || (char *)cframe_pc(cf) == (char *)cframe_L(cf))
return NO_BCPOS;
ins = cframe_pc(cf); /* Only happens during error/hook handling. */
} else {
if (frame_islua(nextframe)) {
ins = frame_pc(nextframe);
} else if (frame_iscont(nextframe)) {
ins = frame_contpc(nextframe);
} else {
/* Lua function below errfunc/gc/hook: find cframe to get the PC. */
void *cf = cframe_raw(L->cframe);
TValue *f = L->base-1;
if (cf == NULL)
return NO_BCPOS;
while (f > nextframe) {
if (frame_islua(f)) {
f = frame_prevl(f);
} else {
if (frame_isc(f))
cf = cframe_raw(cframe_prev(cf));
f = frame_prevd(f);
}
}
if (cframe_prev(cf))
cf = cframe_raw(cframe_prev(cf));
ins = cframe_pc(cf);
}
}
pt = funcproto(fn);
pos = proto_bcpos(pt, ins) - 1;
#if LJ_HASJIT
if (pos > pt->sizebc) { /* Undo the effects of lj_trace_exit for JLOOP. */
GCtrace *T = (GCtrace *)((char *)(ins-1) - offsetof(GCtrace, startins));
lua_assert(bc_isret(bc_op(ins[-1])));
pos = proto_bcpos(pt, mref(T->startpc, const BCIns));
}
#endif
return pos;
}
/* -- Line numbers -------------------------------------------------------- */
/* Get line number for a bytecode position. */
BCLine LJ_FASTCALL lj_debug_line(GCproto *pt, BCPos pc)
{
const void *lineinfo = proto_lineinfo(pt);
if (pc <= pt->sizebc && lineinfo) {
BCLine first = pt->firstline;
if (pc == pt->sizebc) return first + pt->numline;
if (pc-- == 0) return first;
if (pt->numline < 256)
return first + (BCLine)((const uint8_t *)lineinfo)[pc];
else if (pt->numline < 65536)
return first + (BCLine)((const uint16_t *)lineinfo)[pc];
else
return first + (BCLine)((const uint32_t *)lineinfo)[pc];
}
return 0;
}
/* Get line number for function/frame. */
static BCLine debug_frameline(lua_State *L, GCfunc *fn, cTValue *nextframe)
{
BCPos pc = debug_framepc(L, fn, nextframe);
if (pc != NO_BCPOS) {
GCproto *pt = funcproto(fn);
lua_assert(pc <= pt->sizebc);
return lj_debug_line(pt, pc);
}
return -1;
}
/* -- Variable names ------------------------------------------------------ */
/* Read ULEB128 value. */
static uint32_t debug_read_uleb128(const uint8_t **pp)
{
const uint8_t *p = *pp;
uint32_t v = *p++;
if (LJ_UNLIKELY(v >= 0x80)) {
int sh = 0;
v &= 0x7f;
do { v |= ((*p & 0x7f) << (sh += 7)); } while (*p++ >= 0x80);
}
*pp = p;
return v;
}
/* Get name of a local variable from slot number and PC. */
static const char *debug_varname(const GCproto *pt, BCPos pc, BCReg slot)
{
const uint8_t *p = proto_varinfo(pt);
if (p) {
BCPos lastpc = 0;
for (;;) {
const char *name = (const char *)p;
uint32_t vn = *p++;
BCPos startpc, endpc;
if (vn < VARNAME__MAX) {
if (vn == VARNAME_END) break; /* End of varinfo. */
} else {
while (*p++) ; /* Skip over variable name string. */
}
lastpc = startpc = lastpc + debug_read_uleb128(&p);
if (startpc > pc) break;
endpc = startpc + debug_read_uleb128(&p);
if (pc < endpc && slot-- == 0) {
if (vn < VARNAME__MAX) {
#define VARNAMESTR(name, str) str "\0"
name = VARNAMEDEF(VARNAMESTR);
#undef VARNAMESTR
if (--vn) while (*name++ || --vn) ;
}
return name;
}
}
}
return NULL;
}
/* Get name of local variable from 1-based slot number and function/frame. */
static TValue *debug_localname(lua_State *L, const lua_Debug *ar,
const char **name, BCReg slot1)
{
uint32_t offset = (uint32_t)ar->i_ci & 0xffff;
uint32_t size = (uint32_t)ar->i_ci >> 16;
TValue *frame = tvref(L->stack) + offset;
TValue *nextframe = size ? frame + size : NULL;
GCfunc *fn = frame_func(frame);
BCPos pc = debug_framepc(L, fn, nextframe);
if (!nextframe) nextframe = L->top;
if ((int)slot1 < 0) { /* Negative slot number is for varargs. */
if (pc != NO_BCPOS) {
GCproto *pt = funcproto(fn);
if ((pt->flags & PROTO_VARARG)) {
slot1 = pt->numparams + (BCReg)(-(int)slot1);
if (frame_isvarg(frame)) { /* Vararg frame has been set up? (pc!=0) */
nextframe = frame;
frame = frame_prevd(frame);
}
if (frame + slot1 < nextframe) {
*name = "(*vararg)";
return frame+slot1;
}
}
}
return NULL;
}
if (pc != NO_BCPOS &&
(*name = debug_varname(funcproto(fn), pc, slot1-1)) != NULL)
;
else if (slot1 > 0 && frame + slot1 < nextframe)
*name = "(*temporary)";
return frame+slot1;
}
/* Get name of upvalue. */
const char *lj_debug_uvname(GCproto *pt, uint32_t idx)
{
const uint8_t *p = proto_uvinfo(pt);
lua_assert(idx < pt->sizeuv);
if (!p) return "";
if (idx) while (*p++ || --idx) ;
return (const char *)p;
}
/* Get name and value of upvalue. */
const char *lj_debug_uvnamev(cTValue *o, uint32_t idx, TValue **tvp)
{
if (tvisfunc(o)) {
GCfunc *fn = funcV(o);
if (isluafunc(fn)) {
GCproto *pt = funcproto(fn);
if (idx < pt->sizeuv) {
*tvp = uvval(&gcref(fn->l.uvptr[idx])->uv);
return lj_debug_uvname(pt, idx);
}
} else {
if (idx < fn->c.nupvalues) {
*tvp = &fn->c.upvalue[idx];
return "";
}
}
}
return NULL;
}
/* Deduce name of an object from slot number and PC. */
const char *lj_debug_slotname(GCproto *pt, const BCIns *ip, BCReg slot,
const char **name)
{
const char *lname;
restart:
lname = debug_varname(pt, proto_bcpos(pt, ip), slot);
if (lname != NULL) { *name = lname; return "local"; }
while (--ip > proto_bc(pt)) {
BCIns ins = *ip;
BCOp op = bc_op(ins);
BCReg ra = bc_a(ins);
if (bcmode_a(op) == BCMbase) {
if (slot >= ra && (op != BC_KNIL || slot <= bc_d(ins)))
return NULL;
} else if (bcmode_a(op) == BCMdst && ra == slot) {
switch (bc_op(ins)) {
case BC_MOV:
if (ra == slot) { slot = bc_d(ins); goto restart; }
break;
case BC_GGET:
*name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_d(ins))));
return "global";
case BC_TGETS:
*name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_c(ins))));
if (ip > proto_bc(pt)) {
BCIns insp = ip[-1];
if (bc_op(insp) == BC_MOV && bc_a(insp) == ra+1 &&
bc_d(insp) == bc_b(ins))
return "method";
}
return "field";
case BC_UGET:
*name = lj_debug_uvname(pt, bc_d(ins));
return "upvalue";
default:
return NULL;
}
}
}
return NULL;
}
/* Deduce function name from caller of a frame. */
const char *lj_debug_funcname(lua_State *L, TValue *frame, const char **name)
{
TValue *pframe;
GCfunc *fn;
BCPos pc;
if (frame <= tvref(L->stack))
return NULL;
if (frame_isvarg(frame))
frame = frame_prevd(frame);
pframe = frame_prev(frame);
fn = frame_func(pframe);
pc = debug_framepc(L, fn, frame);
if (pc != NO_BCPOS) {
GCproto *pt = funcproto(fn);
const BCIns *ip = &proto_bc(pt)[check_exp(pc < pt->sizebc, pc)];
MMS mm = bcmode_mm(bc_op(*ip));
if (mm == MM_call) {
BCReg slot = bc_a(*ip);
if (bc_op(*ip) == BC_ITERC) slot -= 3;
return lj_debug_slotname(pt, ip, slot, name);
} else if (mm != MM__MAX) {
*name = strdata(mmname_str(G(L), mm));
return "metamethod";
}
}
return NULL;
}
/* -- Source code locations ----------------------------------------------- */
/* Generate shortened source name. */
void lj_debug_shortname(char *out, GCstr *str)
{
const char *src = strdata(str);
if (*src == '=') {
strncpy(out, src+1, LUA_IDSIZE); /* Remove first char. */
out[LUA_IDSIZE-1] = '\0'; /* Ensures null termination. */
} else if (*src == '@') { /* Output "source", or "...source". */
size_t len = str->len-1;
src++; /* Skip the `@' */
if (len >= LUA_IDSIZE) {
src += len-(LUA_IDSIZE-4); /* Get last part of file name. */
*out++ = '.'; *out++ = '.'; *out++ = '.';
}
strcpy(out, src);
} else { /* Output [string "string"]. */
size_t len; /* Length, up to first control char. */
for (len = 0; len < LUA_IDSIZE-12; len++)
if (((const unsigned char *)src)[len] < ' ') break;
strcpy(out, "[string \""); out += 9;
if (src[len] != '\0') { /* Must truncate? */
if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15;
strncpy(out, src, len); out += len;
strcpy(out, "..."); out += 3;
} else {
strcpy(out, src); out += len;
}
strcpy(out, "\"]");
}
}
/* Add current location of a frame to error message. */
void lj_debug_addloc(lua_State *L, const char *msg,
cTValue *frame, cTValue *nextframe)
{
if (frame) {
GCfunc *fn = frame_func(frame);
if (isluafunc(fn)) {
BCLine line = debug_frameline(L, fn, nextframe);
if (line >= 0) {
char buf[LUA_IDSIZE];
lj_debug_shortname(buf, proto_chunkname(funcproto(fn)));
lj_str_pushf(L, "%s:%d: %s", buf, line, msg);
return;
}
}
}
lj_str_pushf(L, "%s", msg);
}
/* Push location string for a bytecode position to Lua stack. */
void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc)
{
GCstr *name = proto_chunkname(pt);
const char *s = strdata(name);
MSize i, len = name->len;
BCLine line = lj_debug_line(pt, pc);
if (*s == '@') {
s++; len--;
for (i = len; i > 0; i--)
if (s[i] == '/' || s[i] == '\\') {
s += i+1;
break;
}
lj_str_pushf(L, "%s:%d", s, line);
} else if (len > 40) {
lj_str_pushf(L, "%p:%d", pt, line);
} else if (*s == '=') {
lj_str_pushf(L, "%s:%d", s+1, line);
} else {
lj_str_pushf(L, "\"%s\":%d", s, line);
}
}
/* -- Public debug API ---------------------------------------------------- */
/* lua_getupvalue() and lua_setupvalue() are in lj_api.c. */
LUA_API const char *lua_getlocal(lua_State *L, const lua_Debug *ar, int n)
{
const char *name = NULL;
if (ar) {
TValue *o = debug_localname(L, ar, &name, (BCReg)n);
if (name) {
copyTV(L, L->top, o);
incr_top(L);
}
} else if (tvisfunc(L->top-1) && isluafunc(funcV(L->top-1))) {
name = debug_varname(funcproto(funcV(L->top-1)), 0, (BCReg)n-1);
}
return name;
}
LUA_API const char *lua_setlocal(lua_State *L, const lua_Debug *ar, int n)
{
const char *name = NULL;
TValue *o = debug_localname(L, ar, &name, (BCReg)n);
if (name)
copyTV(L, o, L->top-1);
L->top--;
return name;
}
int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar, int ext)
{
int opt_f = 0, opt_L = 0;
TValue *frame = NULL;
TValue *nextframe = NULL;
GCfunc *fn;
if (*what == '>') {
TValue *func = L->top - 1;
api_check(L, tvisfunc(func));
fn = funcV(func);
L->top--;
what++;
} else {
uint32_t offset = (uint32_t)ar->i_ci & 0xffff;
uint32_t size = (uint32_t)ar->i_ci >> 16;
lua_assert(offset != 0);
frame = tvref(L->stack) + offset;
if (size) nextframe = frame + size;
lua_assert(frame <= tvref(L->maxstack) &&
(!nextframe || nextframe <= tvref(L->maxstack)));
fn = frame_func(frame);
lua_assert(fn->c.gct == ~LJ_TFUNC);
}
for (; *what; what++) {
if (*what == 'S') {
if (isluafunc(fn)) {
GCproto *pt = funcproto(fn);
BCLine firstline = pt->firstline;
GCstr *name = proto_chunkname(pt);
ar->source = strdata(name);
lj_debug_shortname(ar->short_src, name);
ar->linedefined = (int)firstline;
ar->lastlinedefined = (int)(firstline + pt->numline);
ar->what = firstline ? "Lua" : "main";
} else {
ar->source = "=[C]";
ar->short_src[0] = '[';
ar->short_src[1] = 'C';
ar->short_src[2] = ']';
ar->short_src[3] = '\0';
ar->linedefined = -1;
ar->lastlinedefined = -1;
ar->what = "C";
}
} else if (*what == 'l') {
ar->currentline = frame ? debug_frameline(L, fn, nextframe) : -1;
} else if (*what == 'u') {
ar->nups = fn->c.nupvalues;
if (ext) {
if (isluafunc(fn)) {
GCproto *pt = funcproto(fn);
ar->nparams = pt->numparams;
ar->isvararg = !!(pt->flags & PROTO_VARARG);
} else {
ar->nparams = 0;
ar->isvararg = 1;
}
}
} else if (*what == 'n') {
ar->namewhat = frame ? lj_debug_funcname(L, frame, &ar->name) : NULL;
if (ar->namewhat == NULL) {
ar->namewhat = "";
ar->name = NULL;
}
} else if (*what == 'f') {
opt_f = 1;
} else if (*what == 'L') {
opt_L = 1;
} else {
return 0; /* Bad option. */
}
}
if (opt_f) {
setfuncV(L, L->top, fn);
incr_top(L);
}
if (opt_L) {
if (isluafunc(fn)) {
GCtab *t = lj_tab_new(L, 0, 0);
GCproto *pt = funcproto(fn);
const void *lineinfo = proto_lineinfo(pt);
if (lineinfo) {
BCLine first = pt->firstline;
int sz = pt->numline < 256 ? 1 : pt->numline < 65536 ? 2 : 4;
MSize i, szl = pt->sizebc-1;
for (i = 0; i < szl; i++) {
BCLine line = first +
(sz == 1 ? (BCLine)((const uint8_t *)lineinfo)[i] :
sz == 2 ? (BCLine)((const uint16_t *)lineinfo)[i] :
(BCLine)((const uint32_t *)lineinfo)[i]);
setboolV(lj_tab_setint(L, t, line), 1);
}
}
settabV(L, L->top, t);
} else {
setnilV(L->top);
}
incr_top(L);
}
return 1; /* Ok. */
}
LUA_API int lua_getinfo(lua_State *L, const char *what, lua_Debug *ar)
{
return lj_debug_getinfo(L, what, (lj_Debug *)ar, 0);
}
LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar)
{
int size;
cTValue *frame = lj_debug_frame(L, level, &size);
if (frame) {
ar->i_ci = (size << 16) + (int)(frame - tvref(L->stack));
return 1;
} else {
ar->i_ci = level - size;
return 0;
}
}
/* Number of frames for the leading and trailing part of a traceback. */
#define TRACEBACK_LEVELS1 12
#define TRACEBACK_LEVELS2 10
LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
int level)
{
int top = (int)(L->top - L->base);
int lim = TRACEBACK_LEVELS1;
lua_Debug ar;
if (msg) lua_pushfstring(L, "%s\n", msg);
lua_pushliteral(L, "stack traceback:");
while (lua_getstack(L1, level++, &ar)) {
GCfunc *fn;
if (level > lim) {
if (!lua_getstack(L1, level + TRACEBACK_LEVELS2, &ar)) {
level--;
} else {
lua_pushliteral(L, "\n\t...");
lua_getstack(L1, -10, &ar);
level = ar.i_ci - TRACEBACK_LEVELS2;
}
lim = 2147483647;
continue;
}
lua_getinfo(L1, "Snlf", &ar);
fn = funcV(L1->top-1); L1->top--;
if (isffunc(fn) && !*ar.namewhat)
lua_pushfstring(L, "\n\t[builtin#%d]:", fn->c.ffid);
else
lua_pushfstring(L, "\n\t%s:", ar.short_src);
if (ar.currentline > 0)
lua_pushfstring(L, "%d:", ar.currentline);
if (*ar.namewhat) {
lua_pushfstring(L, " in function " LUA_QS, ar.name);
} else {
if (*ar.what == 'm') {
lua_pushliteral(L, " in main chunk");
} else if (*ar.what == 'C') {
lua_pushfstring(L, " at %p", fn->c.f);
} else {
lua_pushfstring(L, " in function <%s:%d>",
ar.short_src, ar.linedefined);
}
}
if ((int)(L->top - L->base) - top >= 15)
lua_concat(L, (int)(L->top - L->base) - top);
}
lua_concat(L, (int)(L->top - L->base) - top);
}
-349
View File
@@ -1,349 +0,0 @@
/*
** LuaJIT common internal definitions.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_DEF_H
#define _LJ_DEF_H
#include "lua.h"
#if defined(_MSC_VER)
/* MSVC is stuck in the last century and doesn't have C99's stdint.h. */
typedef __int8 int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
#ifdef _WIN64
typedef __int64 intptr_t;
typedef unsigned __int64 uintptr_t;
#else
typedef __int32 intptr_t;
typedef unsigned __int32 uintptr_t;
#endif
#elif defined(__symbian__)
/* Cough. */
typedef signed char int8_t;
typedef short int int16_t;
typedef int int32_t;
typedef long long int64_t;
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef int intptr_t;
typedef unsigned int uintptr_t;
#else
#include <stdint.h>
#endif
/* Needed everywhere. */
#include <string.h>
#include <stdlib.h>
/* Various VM limits. */
#define LJ_MAX_MEM 0x7fffff00 /* Max. total memory allocation. */
#define LJ_MAX_ALLOC LJ_MAX_MEM /* Max. individual allocation length. */
#define LJ_MAX_STR LJ_MAX_MEM /* Max. string length. */
#define LJ_MAX_UDATA LJ_MAX_MEM /* Max. userdata length. */
#define LJ_MAX_STRTAB (1<<26) /* Max. string table size. */
#define LJ_MAX_HBITS 26 /* Max. hash bits. */
#define LJ_MAX_ABITS 28 /* Max. bits of array key. */
#define LJ_MAX_ASIZE ((1<<(LJ_MAX_ABITS-1))+1) /* Max. array part size. */
#define LJ_MAX_COLOSIZE 16 /* Max. elems for colocated array. */
#define LJ_MAX_LINE LJ_MAX_MEM /* Max. source code line number. */
#define LJ_MAX_XLEVEL 200 /* Max. syntactic nesting level. */
#define LJ_MAX_BCINS (1<<26) /* Max. # of bytecode instructions. */
#define LJ_MAX_SLOTS 250 /* Max. # of slots in a Lua func. */
#define LJ_MAX_LOCVAR 200 /* Max. # of local variables. */
#define LJ_MAX_UPVAL 60 /* Max. # of upvalues. */
#define LJ_MAX_IDXCHAIN 100 /* __index/__newindex chain limit. */
#define LJ_STACK_EXTRA 5 /* Extra stack space (metamethods). */
#define LJ_NUM_CBPAGE 1 /* Number of FFI callback pages. */
/* Minimum table/buffer sizes. */
#define LJ_MIN_GLOBAL 6 /* Min. global table size (hbits). */
#define LJ_MIN_REGISTRY 2 /* Min. registry size (hbits). */
#define LJ_MIN_STRTAB 256 /* Min. string table size (pow2). */
#define LJ_MIN_SBUF 32 /* Min. string buffer length. */
#define LJ_MIN_VECSZ 8 /* Min. size for growable vectors. */
#define LJ_MIN_IRSZ 32 /* Min. size for growable IR. */
#define LJ_MIN_K64SZ 16 /* Min. size for chained K64Array. */
/* JIT compiler limits. */
#define LJ_MAX_JSLOTS 250 /* Max. # of stack slots for a trace. */
#define LJ_MAX_PHI 64 /* Max. # of PHIs for a loop. */
#define LJ_MAX_EXITSTUBGR 16 /* Max. # of exit stub groups. */
/* Various macros. */
#ifndef UNUSED
#define UNUSED(x) ((void)(x)) /* to avoid warnings */
#endif
#define U64x(hi, lo) (((uint64_t)0x##hi << 32) + (uint64_t)0x##lo)
#define i32ptr(p) ((int32_t)(intptr_t)(void *)(p))
#define u32ptr(p) ((uint32_t)(intptr_t)(void *)(p))
#define checki8(x) ((x) == (int32_t)(int8_t)(x))
#define checku8(x) ((x) == (int32_t)(uint8_t)(x))
#define checki16(x) ((x) == (int32_t)(int16_t)(x))
#define checku16(x) ((x) == (int32_t)(uint16_t)(x))
#define checki32(x) ((x) == (int32_t)(x))
#define checku32(x) ((x) == (uint32_t)(x))
#define checkptr32(x) ((uintptr_t)(x) == (uint32_t)(uintptr_t)(x))
/* Every half-decent C compiler transforms this into a rotate instruction. */
#define lj_rol(x, n) (((x)<<(n)) | ((x)>>(8*sizeof(x)-(n))))
#define lj_ror(x, n) (((x)<<(8*sizeof(x)-(n))) | ((x)>>(n)))
/* A really naive Bloom filter. But sufficient for our needs. */
typedef uintptr_t BloomFilter;
#define BLOOM_MASK (8*sizeof(BloomFilter) - 1)
#define bloombit(x) ((uintptr_t)1 << ((x) & BLOOM_MASK))
#define bloomset(b, x) ((b) |= bloombit((x)))
#define bloomtest(b, x) ((b) & bloombit((x)))
#if defined(__GNUC__)
#define LJ_NORET __attribute__((noreturn))
#define LJ_ALIGN(n) __attribute__((aligned(n)))
#define LJ_INLINE inline
#define LJ_AINLINE inline __attribute__((always_inline))
#define LJ_NOINLINE __attribute__((noinline))
#if defined(__ELF__) || defined(__MACH__)
#if !((defined(__sun__) && defined(__svr4__)) || defined(__CELLOS_LV2__))
#define LJ_NOAPI extern __attribute__((visibility("hidden")))
#endif
#endif
/* Note: it's only beneficial to use fastcall on x86 and then only for up to
** two non-FP args. The amalgamated compile covers all LJ_FUNC cases. Only
** indirect calls and related tail-called C functions are marked as fastcall.
*/
#if defined(__i386__)
#define LJ_FASTCALL __attribute__((fastcall))
#endif
#define LJ_LIKELY(x) __builtin_expect(!!(x), 1)
#define LJ_UNLIKELY(x) __builtin_expect(!!(x), 0)
#define lj_ffs(x) ((uint32_t)__builtin_ctz(x))
/* Don't ask ... */
#if defined(__INTEL_COMPILER) && (defined(__i386__) || defined(__x86_64__))
static LJ_AINLINE uint32_t lj_fls(uint32_t x)
{
uint32_t r; __asm__("bsrl %1, %0" : "=r" (r) : "rm" (x) : "cc"); return r;
}
#else
#define lj_fls(x) ((uint32_t)(__builtin_clz(x)^31))
#endif
#if defined(__arm__)
static LJ_AINLINE uint32_t lj_bswap(uint32_t x)
{
uint32_t r;
#if __ARM_ARCH_6__ || __ARM_ARCH_6J__ || __ARM_ARCH_6T2__ || __ARM_ARCH_6Z__ ||\
__ARM_ARCH_6ZK__ || __ARM_ARCH_7__ || __ARM_ARCH_7A__ || __ARM_ARCH_7R__
__asm__("rev %0, %1" : "=r" (r) : "r" (x));
return r;
#else
#ifdef __thumb__
r = x ^ lj_ror(x, 16);
#else
__asm__("eor %0, %1, %1, ror #16" : "=r" (r) : "r" (x));
#endif
return ((r & 0xff00ffffu) >> 8) ^ lj_ror(x, 8);
#endif
}
static LJ_AINLINE uint64_t lj_bswap64(uint64_t x)
{
return ((uint64_t)lj_bswap((uint32_t)x)<<32) | lj_bswap((uint32_t)(x>>32));
}
#elif (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
static LJ_AINLINE uint32_t lj_bswap(uint32_t x)
{
return (uint32_t)__builtin_bswap32((int32_t)x);
}
static LJ_AINLINE uint64_t lj_bswap64(uint64_t x)
{
return (uint64_t)__builtin_bswap64((int64_t)x);
}
#elif defined(__i386__) || defined(__x86_64__)
static LJ_AINLINE uint32_t lj_bswap(uint32_t x)
{
uint32_t r; __asm__("bswap %0" : "=r" (r) : "0" (x)); return r;
}
#if defined(__i386__)
static LJ_AINLINE uint64_t lj_bswap64(uint64_t x)
{
return ((uint64_t)lj_bswap((uint32_t)x)<<32) | lj_bswap((uint32_t)(x>>32));
}
#else
static LJ_AINLINE uint64_t lj_bswap64(uint64_t x)
{
uint64_t r; __asm__("bswap %0" : "=r" (r) : "0" (x)); return r;
}
#endif
#else
static LJ_AINLINE uint32_t lj_bswap(uint32_t x)
{
return (x << 24) | ((x & 0xff00) << 8) | ((x >> 8) & 0xff00) | (x >> 24);
}
static LJ_AINLINE uint64_t lj_bswap64(uint64_t x)
{
return (uint64_t)lj_bswap((uint32_t)(x >> 32)) |
((uint64_t)lj_bswap((uint32_t)x) << 32);
}
#endif
typedef union __attribute__((packed)) Unaligned16 {
uint16_t u;
uint8_t b[2];
} Unaligned16;
typedef union __attribute__((packed)) Unaligned32 {
uint32_t u;
uint8_t b[4];
} Unaligned32;
/* Unaligned load of uint16_t. */
static LJ_AINLINE uint16_t lj_getu16(const void *p)
{
return ((const Unaligned16 *)p)->u;
}
/* Unaligned load of uint32_t. */
static LJ_AINLINE uint32_t lj_getu32(const void *p)
{
return ((const Unaligned32 *)p)->u;
}
#elif defined(_MSC_VER)
#define LJ_NORET __declspec(noreturn)
#define LJ_ALIGN(n) __declspec(align(n))
#define LJ_INLINE __inline
#define LJ_AINLINE __forceinline
#define LJ_NOINLINE __declspec(noinline)
#if defined(_M_IX86)
#define LJ_FASTCALL __fastcall
#endif
#ifdef _M_PPC
#pragma intrinsic(_CountLeadingZeros)
unsigned int _CountLeadingZeros(long);
static LJ_AINLINE uint32_t lj_fls(uint32_t x)
{
return _CountLeadingZeros(x) ^ 31;
}
#else
#pragma intrinsic(_BitScanForward)
#pragma intrinsic(_BitScanReverse)
unsigned char _BitScanForward(uint32_t *, unsigned long);
unsigned char _BitScanReverse(uint32_t *, unsigned long);
static LJ_AINLINE uint32_t lj_ffs(uint32_t x)
{
uint32_t r; _BitScanForward(&r, x); return r;
}
static LJ_AINLINE uint32_t lj_fls(uint32_t x)
{
uint32_t r; _BitScanReverse(&r, x); return r;
}
#endif
unsigned long _byteswap_ulong(unsigned long);
uint64_t _byteswap_uint64(uint64_t);
#define lj_bswap(x) (_byteswap_ulong((x)))
#define lj_bswap64(x) (_byteswap_uint64((x)))
#if defined(_M_PPC) && defined(LUAJIT_NO_UNALIGNED)
/*
** Replacement for unaligned loads on Xbox 360. Disabled by default since it's
** usually more costly than the occasional stall when crossing a cache-line.
*/
static LJ_AINLINE uint16_t lj_getu16(const void *v)
{
const uint8_t *p = (const uint8_t *)v;
return (uint16_t)((p[0]<<8) | p[1]);
}
static LJ_AINLINE uint32_t lj_getu32(const void *v)
{
const uint8_t *p = (const uint8_t *)v;
return (uint32_t)((p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]);
}
#else
/* Unaligned loads are generally ok on x86/x64. */
#define lj_getu16(p) (*(uint16_t *)(p))
#define lj_getu32(p) (*(uint32_t *)(p))
#endif
#else
#error "missing defines for your compiler"
#endif
/* Optional defines. */
#ifndef LJ_FASTCALL
#define LJ_FASTCALL
#endif
#ifndef LJ_NORET
#define LJ_NORET
#endif
#ifndef LJ_NOAPI
#define LJ_NOAPI extern
#endif
#ifndef LJ_LIKELY
#define LJ_LIKELY(x) (x)
#define LJ_UNLIKELY(x) (x)
#endif
/* Attributes for internal functions. */
#define LJ_DATA LJ_NOAPI
#define LJ_DATADEF
#define LJ_ASMF LJ_NOAPI
#define LJ_FUNCA LJ_NOAPI
#if defined(ljamalg_c)
#define LJ_FUNC static
#else
#define LJ_FUNC LJ_NOAPI
#endif
#define LJ_FUNC_NORET LJ_FUNC LJ_NORET
#define LJ_FUNCA_NORET LJ_FUNCA LJ_NORET
#define LJ_ASMF_NORET LJ_ASMF LJ_NORET
/* Runtime assertions. */
#ifdef lua_assert
#define check_exp(c, e) (lua_assert(c), (e))
#define api_check(l, e) lua_assert(e)
#else
#define lua_assert(c) ((void)0)
#define check_exp(c, e) (e)
#define api_check luai_apicheck
#endif
/* Static assertions. */
#define LJ_ASSERT_NAME2(name, line) name ## line
#define LJ_ASSERT_NAME(line) LJ_ASSERT_NAME2(lj_assert_, line)
#ifdef __COUNTER__
#define LJ_STATIC_ASSERT(cond) \
extern void LJ_ASSERT_NAME(__COUNTER__)(int STATIC_ASSERTION_FAILED[(cond)?1:-1])
#else
#define LJ_STATIC_ASSERT(cond) \
extern void LJ_ASSERT_NAME(__LINE__)(int STATIC_ASSERTION_FAILED[(cond)?1:-1])
#endif
#endif
-131
View File
@@ -1,131 +0,0 @@
/*
** Instruction dispatch handling.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_DISPATCH_H
#define _LJ_DISPATCH_H
#include "lj_obj.h"
#include "lj_bc.h"
#if LJ_HASJIT
#include "lj_jit.h"
#endif
#if LJ_TARGET_MIPS
/* Need our own global offset table for the dreaded MIPS calling conventions. */
#if LJ_HASJIT
#define JITGOTDEF(_) _(lj_trace_exit) _(lj_trace_hot)
#else
#define JITGOTDEF(_)
#endif
#if LJ_HASFFI
#define FFIGOTDEF(_) \
_(lj_meta_equal_cd) _(lj_ccallback_enter) _(lj_ccallback_leave)
#else
#define FFIGOTDEF(_)
#endif
#define GOTDEF(_) \
_(floor) _(ceil) _(trunc) _(log) _(log10) _(exp) _(sin) _(cos) _(tan) \
_(asin) _(acos) _(atan) _(sinh) _(cosh) _(tanh) _(frexp) _(modf) _(atan2) \
_(pow) _(fmod) _(ldexp) \
_(lj_dispatch_call) _(lj_dispatch_ins) _(lj_err_throw) \
_(lj_ffh_coroutine_wrap_err) _(lj_func_closeuv) _(lj_func_newL_gc) \
_(lj_gc_barrieruv) _(lj_gc_step) _(lj_gc_step_fixtop) _(lj_meta_arith) \
_(lj_meta_call) _(lj_meta_cat) _(lj_meta_comp) _(lj_meta_equal) \
_(lj_meta_for) _(lj_meta_len) _(lj_meta_tget) _(lj_meta_tset) \
_(lj_state_growstack) _(lj_str_fromnum) _(lj_str_fromnumber) _(lj_str_new) \
_(lj_tab_dup) _(lj_tab_get) _(lj_tab_getinth) _(lj_tab_len) _(lj_tab_new) \
_(lj_tab_newkey) _(lj_tab_next) _(lj_tab_reasize) \
JITGOTDEF(_) FFIGOTDEF(_)
enum {
#define GOTENUM(name) LJ_GOT_##name,
GOTDEF(GOTENUM)
#undef GOTENUM
LJ_GOT__MAX
};
#endif
/* Type of hot counter. Must match the code in the assembler VM. */
/* 16 bits are sufficient. Only 0.0015% overhead with maximum slot penalty. */
typedef uint16_t HotCount;
/* Number of hot counter hash table entries (must be a power of two). */
#define HOTCOUNT_SIZE 64
#define HOTCOUNT_PCMASK ((HOTCOUNT_SIZE-1)*sizeof(HotCount))
/* Hotcount decrements. */
#define HOTCOUNT_LOOP 2
#define HOTCOUNT_CALL 1
/* This solves a circular dependency problem -- bump as needed. Sigh. */
#define GG_NUM_ASMFF 62
#define GG_LEN_DDISP (BC__MAX + GG_NUM_ASMFF)
#define GG_LEN_SDISP BC_FUNCF
#define GG_LEN_DISP (GG_LEN_DDISP + GG_LEN_SDISP)
/* Global state, main thread and extra fields are allocated together. */
typedef struct GG_State {
lua_State L; /* Main thread. */
global_State g; /* Global state. */
#if LJ_TARGET_MIPS
ASMFunction got[LJ_GOT__MAX]; /* Global offset table. */
#endif
#if LJ_HASJIT
jit_State J; /* JIT state. */
HotCount hotcount[HOTCOUNT_SIZE]; /* Hot counters. */
#endif
ASMFunction dispatch[GG_LEN_DISP]; /* Instruction dispatch tables. */
BCIns bcff[GG_NUM_ASMFF]; /* Bytecode for ASM fast functions. */
} GG_State;
#define GG_OFS(field) ((int)offsetof(GG_State, field))
#define G2GG(gl) ((GG_State *)((char *)(gl) - GG_OFS(g)))
#define J2GG(j) ((GG_State *)((char *)(j) - GG_OFS(J)))
#define L2GG(L) (G2GG(G(L)))
#define J2G(J) (&J2GG(J)->g)
#define G2J(gl) (&G2GG(gl)->J)
#define L2J(L) (&L2GG(L)->J)
#define GG_G2DISP (GG_OFS(dispatch) - GG_OFS(g))
#define GG_DISP2G (GG_OFS(g) - GG_OFS(dispatch))
#define GG_DISP2J (GG_OFS(J) - GG_OFS(dispatch))
#define GG_DISP2HOT (GG_OFS(hotcount) - GG_OFS(dispatch))
#define GG_DISP2STATIC (GG_LEN_DDISP*(int)sizeof(ASMFunction))
#define hotcount_get(gg, pc) \
(gg)->hotcount[(u32ptr(pc)>>2) & (HOTCOUNT_SIZE-1)]
#define hotcount_set(gg, pc, val) \
(hotcount_get((gg), (pc)) = (HotCount)(val))
/* Dispatch table management. */
LJ_FUNC void lj_dispatch_init(GG_State *GG);
#if LJ_HASJIT
LJ_FUNC void lj_dispatch_init_hotcount(global_State *g);
#endif
LJ_FUNC void lj_dispatch_update(global_State *g);
/* Instruction dispatch callback for hooks or when recording. */
LJ_FUNCA void LJ_FASTCALL lj_dispatch_ins(lua_State *L, const BCIns *pc);
LJ_FUNCA ASMFunction LJ_FASTCALL lj_dispatch_call(lua_State *L, const BCIns*pc);
LJ_FUNCA void LJ_FASTCALL lj_dispatch_return(lua_State *L, const BCIns *pc);
#if LJ_HASFFI && !defined(_BUILDVM_H)
/* Save/restore errno and GetLastError() around hooks, exits and recording. */
#include <errno.h>
#if LJ_TARGET_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define ERRNO_SAVE int olderr = errno; DWORD oldwerr = GetLastError();
#define ERRNO_RESTORE errno = olderr; SetLastError(oldwerr);
#else
#define ERRNO_SAVE int olderr = errno;
#define ERRNO_RESTORE errno = olderr;
#endif
#else
#define ERRNO_SAVE
#define ERRNO_RESTORE
#endif
#endif
-211
View File
@@ -1,211 +0,0 @@
/*
** MIPS instruction emitter.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
*/
/* -- Emit basic instructions --------------------------------------------- */
static void emit_dst(ASMState *as, MIPSIns mi, Reg rd, Reg rs, Reg rt)
{
*--as->mcp = mi | MIPSF_D(rd) | MIPSF_S(rs) | MIPSF_T(rt);
}
static void emit_dta(ASMState *as, MIPSIns mi, Reg rd, Reg rt, uint32_t a)
{
*--as->mcp = mi | MIPSF_D(rd) | MIPSF_T(rt) | MIPSF_A(a);
}
#define emit_ds(as, mi, rd, rs) emit_dst(as, (mi), (rd), (rs), 0)
#define emit_tg(as, mi, rt, rg) emit_dst(as, (mi), (rg)&31, 0, (rt))
static void emit_tsi(ASMState *as, MIPSIns mi, Reg rt, Reg rs, int32_t i)
{
*--as->mcp = mi | MIPSF_T(rt) | MIPSF_S(rs) | (i & 0xffff);
}
#define emit_ti(as, mi, rt, i) emit_tsi(as, (mi), (rt), 0, (i))
#define emit_hsi(as, mi, rh, rs, i) emit_tsi(as, (mi), (rh) & 31, (rs), (i))
static void emit_fgh(ASMState *as, MIPSIns mi, Reg rf, Reg rg, Reg rh)
{
*--as->mcp = mi | MIPSF_F(rf&31) | MIPSF_G(rg&31) | MIPSF_H(rh&31);
}
#define emit_fg(as, mi, rf, rg) emit_fgh(as, (mi), (rf), (rg), 0)
static void emit_rotr(ASMState *as, Reg dest, Reg src, Reg tmp, uint32_t shift)
{
if ((as->flags & JIT_F_MIPS32R2)) {
emit_dta(as, MIPSI_ROTR, dest, src, shift);
} else {
emit_dst(as, MIPSI_OR, dest, dest, tmp);
emit_dta(as, MIPSI_SLL, dest, src, (-shift)&31);
emit_dta(as, MIPSI_SRL, tmp, src, shift);
}
}
/* -- Emit loads/stores --------------------------------------------------- */
/* Prefer rematerialization of BASE/L from global_State over spills. */
#define emit_canremat(ref) ((ref) <= REF_BASE)
/* Try to find a one step delta relative to another constant. */
static int emit_kdelta1(ASMState *as, Reg t, int32_t i)
{
RegSet work = ~as->freeset & RSET_GPR;
while (work) {
Reg r = rset_picktop(work);
IRRef ref = regcost_ref(as->cost[r]);
lua_assert(r != t);
if (ref < ASMREF_L) {
int32_t delta = i - (ra_iskref(ref) ? ra_krefk(as, ref) : IR(ref)->i);
if (checki16(delta)) {
emit_tsi(as, MIPSI_ADDIU, t, r, delta);
return 1;
}
}
rset_clear(work, r);
}
return 0; /* Failed. */
}
/* Load a 32 bit constant into a GPR. */
static void emit_loadi(ASMState *as, Reg r, int32_t i)
{
if (checki16(i)) {
emit_ti(as, MIPSI_LI, r, i);
} else {
if ((i & 0xffff)) {
int32_t jgl = i32ptr(J2G(as->J));
if ((uint32_t)(i-jgl) < 65536) {
emit_tsi(as, MIPSI_ADDIU, r, RID_JGL, i-jgl-32768);
return;
} else if (emit_kdelta1(as, r, i)) {
return;
} else if ((i >> 16) == 0) {
emit_tsi(as, MIPSI_ORI, r, RID_ZERO, i);
return;
}
emit_tsi(as, MIPSI_ORI, r, r, i);
}
emit_ti(as, MIPSI_LUI, r, (i >> 16));
}
}
#define emit_loada(as, r, addr) emit_loadi(as, (r), i32ptr((addr)))
static Reg ra_allock(ASMState *as, int32_t k, RegSet allow);
static void ra_allockreg(ASMState *as, int32_t k, Reg r);
/* Get/set from constant pointer. */
static void emit_lsptr(ASMState *as, MIPSIns mi, Reg r, void *p, RegSet allow)
{
int32_t jgl = i32ptr(J2G(as->J));
int32_t i = i32ptr(p);
Reg base;
if ((uint32_t)(i-jgl) < 65536) {
i = i-jgl-32768;
base = RID_JGL;
} else {
base = ra_allock(as, i-(int16_t)i, allow);
}
emit_tsi(as, mi, r, base, i);
}
#define emit_loadn(as, r, tv) \
emit_lsptr(as, MIPSI_LDC1, ((r) & 31), (void *)(tv), RSET_GPR)
/* Get/set global_State fields. */
static void emit_lsglptr(ASMState *as, MIPSIns mi, Reg r, int32_t ofs)
{
emit_tsi(as, mi, r, RID_JGL, ofs-32768);
}
#define emit_getgl(as, r, field) \
emit_lsglptr(as, MIPSI_LW, (r), (int32_t)offsetof(global_State, field))
#define emit_setgl(as, r, field) \
emit_lsglptr(as, MIPSI_SW, (r), (int32_t)offsetof(global_State, field))
/* Trace number is determined from per-trace exit stubs. */
#define emit_setvmstate(as, i) UNUSED(i)
/* -- Emit control-flow instructions -------------------------------------- */
/* Label for internal jumps. */
typedef MCode *MCLabel;
/* Return label pointing to current PC. */
#define emit_label(as) ((as)->mcp)
static void emit_branch(ASMState *as, MIPSIns mi, Reg rs, Reg rt, MCode *target)
{
MCode *p = as->mcp;
ptrdiff_t delta = target - p;
lua_assert(((delta + 0x8000) >> 16) == 0);
*--p = mi | MIPSF_S(rs) | MIPSF_T(rt) | ((uint32_t)delta & 0xffffu);
as->mcp = p;
}
static void emit_jmp(ASMState *as, MCode *target)
{
*--as->mcp = MIPSI_NOP;
emit_branch(as, MIPSI_B, RID_ZERO, RID_ZERO, (target));
}
static void emit_call(ASMState *as, void *target)
{
MCode *p = as->mcp;
*--p = MIPSI_NOP;
if ((((uintptr_t)target ^ (uintptr_t)p) >> 28) == 0)
*--p = MIPSI_JAL | (((uintptr_t)target >>2) & 0x03ffffffu);
else /* Target out of range: need indirect call. */
*--p = MIPSI_JALR | MIPSF_S(RID_CFUNCADDR);
as->mcp = p;
ra_allockreg(as, i32ptr(target), RID_CFUNCADDR);
}
/* -- Emit generic operations --------------------------------------------- */
#define emit_move(as, dst, src) \
emit_ds(as, MIPSI_MOVE, (dst), (src))
/* Generic move between two regs. */
static void emit_movrr(ASMState *as, IRIns *ir, Reg dst, Reg src)
{
if (dst < RID_MAX_GPR)
emit_move(as, dst, src);
else
emit_fg(as, irt_isnum(ir->t) ? MIPSI_MOV_D : MIPSI_MOV_S, dst, src);
}
/* Generic load of register from stack slot. */
static void emit_spload(ASMState *as, IRIns *ir, Reg r, int32_t ofs)
{
if (r < RID_MAX_GPR)
emit_tsi(as, MIPSI_LW, r, RID_SP, ofs);
else
emit_tsi(as, irt_isnum(ir->t) ? MIPSI_LDC1 : MIPSI_LWC1,
(r & 31), RID_SP, ofs);
}
/* Generic store of register to stack slot. */
static void emit_spstore(ASMState *as, IRIns *ir, Reg r, int32_t ofs)
{
if (r < RID_MAX_GPR)
emit_tsi(as, MIPSI_SW, r, RID_SP, ofs);
else
emit_tsi(as, irt_isnum(ir->t) ? MIPSI_SDC1 : MIPSI_SWC1,
(r&31), RID_SP, ofs);
}
/* Add offset to pointer. */
static void emit_addptr(ASMState *as, Reg r, int32_t ofs)
{
if (ofs) {
lua_assert(checki16(ofs));
emit_tsi(as, MIPSI_ADDIU, r, r, ofs);
}
}
#define emit_spsub(as, ofs) emit_addptr(as, RID_SP, -(ofs))
-466
View File
@@ -1,466 +0,0 @@
/*
** x86/x64 instruction emitter.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
*/
/* -- Emit basic instructions --------------------------------------------- */
#define MODRM(mode, r1, r2) ((MCode)((mode)+(((r1)&7)<<3)+((r2)&7)))
#if LJ_64
#define REXRB(p, rr, rb) \
{ MCode rex = 0x40 + (((rr)>>1)&4) + (((rb)>>3)&1); \
if (rex != 0x40) *--(p) = rex; }
#define FORCE_REX 0x200
#define REX_64 (FORCE_REX|0x080000)
#else
#define REXRB(p, rr, rb) ((void)0)
#define FORCE_REX 0
#define REX_64 0
#endif
#define emit_i8(as, i) (*--as->mcp = (MCode)(i))
#define emit_i32(as, i) (*(int32_t *)(as->mcp-4) = (i), as->mcp -= 4)
#define emit_u32(as, u) (*(uint32_t *)(as->mcp-4) = (u), as->mcp -= 4)
#define emit_x87op(as, xo) \
(*(uint16_t *)(as->mcp-2) = (uint16_t)(xo), as->mcp -= 2)
/* op */
static LJ_AINLINE MCode *emit_op(x86Op xo, Reg rr, Reg rb, Reg rx,
MCode *p, int delta)
{
int n = (int8_t)xo;
#if defined(__GNUC__)
if (__builtin_constant_p(xo) && n == -2)
p[delta-2] = (MCode)(xo >> 24);
else if (__builtin_constant_p(xo) && n == -3)
*(uint16_t *)(p+delta-3) = (uint16_t)(xo >> 16);
else
#endif
*(uint32_t *)(p+delta-5) = (uint32_t)xo;
p += n + delta;
#if LJ_64
{
uint32_t rex = 0x40 + ((rr>>1)&(4+(FORCE_REX>>1)))+((rx>>2)&2)+((rb>>3)&1);
if (rex != 0x40) {
rex |= (rr >> 16);
if (n == -4) { *p = (MCode)rex; rex = (MCode)(xo >> 8); }
else if ((xo & 0xffffff) == 0x6600fd) { *p = (MCode)rex; rex = 0x66; }
*--p = (MCode)rex;
}
}
#else
UNUSED(rr); UNUSED(rb); UNUSED(rx);
#endif
return p;
}
/* op + modrm */
#define emit_opm(xo, mode, rr, rb, p, delta) \
(p[(delta)-1] = MODRM((mode), (rr), (rb)), \
emit_op((xo), (rr), (rb), 0, (p), (delta)))
/* op + modrm + sib */
#define emit_opmx(xo, mode, scale, rr, rb, rx, p) \
(p[-1] = MODRM((scale), (rx), (rb)), \
p[-2] = MODRM((mode), (rr), RID_ESP), \
emit_op((xo), (rr), (rb), (rx), (p), -1))
/* op r1, r2 */
static void emit_rr(ASMState *as, x86Op xo, Reg r1, Reg r2)
{
MCode *p = as->mcp;
as->mcp = emit_opm(xo, XM_REG, r1, r2, p, 0);
}
#if LJ_64 && defined(LUA_USE_ASSERT)
/* [addr] is sign-extended in x64 and must be in lower 2G (not 4G). */
static int32_t ptr2addr(const void *p)
{
lua_assert((uintptr_t)p < (uintptr_t)0x80000000);
return i32ptr(p);
}
#else
#define ptr2addr(p) (i32ptr((p)))
#endif
/* op r, [addr] */
static void emit_rma(ASMState *as, x86Op xo, Reg rr, const void *addr)
{
MCode *p = as->mcp;
*(int32_t *)(p-4) = ptr2addr(addr);
#if LJ_64
p[-5] = MODRM(XM_SCALE1, RID_ESP, RID_EBP);
as->mcp = emit_opm(xo, XM_OFS0, rr, RID_ESP, p, -5);
#else
as->mcp = emit_opm(xo, XM_OFS0, rr, RID_EBP, p, -4);
#endif
}
/* op r, [base+ofs] */
static void emit_rmro(ASMState *as, x86Op xo, Reg rr, Reg rb, int32_t ofs)
{
MCode *p = as->mcp;
x86Mode mode;
if (ra_hasreg(rb)) {
if (ofs == 0 && (rb&7) != RID_EBP) {
mode = XM_OFS0;
} else if (checki8(ofs)) {
*--p = (MCode)ofs;
mode = XM_OFS8;
} else {
p -= 4;
*(int32_t *)p = ofs;
mode = XM_OFS32;
}
if ((rb&7) == RID_ESP)
*--p = MODRM(XM_SCALE1, RID_ESP, RID_ESP);
} else {
*(int32_t *)(p-4) = ofs;
#if LJ_64
p[-5] = MODRM(XM_SCALE1, RID_ESP, RID_EBP);
p -= 5;
rb = RID_ESP;
#else
p -= 4;
rb = RID_EBP;
#endif
mode = XM_OFS0;
}
as->mcp = emit_opm(xo, mode, rr, rb, p, 0);
}
/* op r, [base+idx*scale+ofs] */
static void emit_rmrxo(ASMState *as, x86Op xo, Reg rr, Reg rb, Reg rx,
x86Mode scale, int32_t ofs)
{
MCode *p = as->mcp;
x86Mode mode;
if (ofs == 0 && (rb&7) != RID_EBP) {
mode = XM_OFS0;
} else if (checki8(ofs)) {
mode = XM_OFS8;
*--p = (MCode)ofs;
} else {
mode = XM_OFS32;
p -= 4;
*(int32_t *)p = ofs;
}
as->mcp = emit_opmx(xo, mode, scale, rr, rb, rx, p);
}
/* op r, i */
static void emit_gri(ASMState *as, x86Group xg, Reg rb, int32_t i)
{
MCode *p = as->mcp;
x86Op xo;
if (checki8(i)) {
*--p = (MCode)i;
xo = XG_TOXOi8(xg);
} else {
p -= 4;
*(int32_t *)p = i;
xo = XG_TOXOi(xg);
}
as->mcp = emit_opm(xo, XM_REG, (Reg)(xg & 7) | (rb & REX_64), rb, p, 0);
}
/* op [base+ofs], i */
static void emit_gmroi(ASMState *as, x86Group xg, Reg rb, int32_t ofs,
int32_t i)
{
x86Op xo;
if (checki8(i)) {
emit_i8(as, i);
xo = XG_TOXOi8(xg);
} else {
emit_i32(as, i);
xo = XG_TOXOi(xg);
}
emit_rmro(as, xo, (Reg)(xg & 7), rb, ofs);
}
#define emit_shifti(as, xg, r, i) \
(emit_i8(as, (i)), emit_rr(as, XO_SHIFTi, (Reg)(xg), (r)))
/* op r, rm/mrm */
static void emit_mrm(ASMState *as, x86Op xo, Reg rr, Reg rb)
{
MCode *p = as->mcp;
x86Mode mode = XM_REG;
if (rb == RID_MRM) {
rb = as->mrm.base;
if (rb == RID_NONE) {
rb = RID_EBP;
mode = XM_OFS0;
p -= 4;
*(int32_t *)p = as->mrm.ofs;
if (as->mrm.idx != RID_NONE)
goto mrmidx;
#if LJ_64
*--p = MODRM(XM_SCALE1, RID_ESP, RID_EBP);
rb = RID_ESP;
#endif
} else {
if (as->mrm.ofs == 0 && (rb&7) != RID_EBP) {
mode = XM_OFS0;
} else if (checki8(as->mrm.ofs)) {
*--p = (MCode)as->mrm.ofs;
mode = XM_OFS8;
} else {
p -= 4;
*(int32_t *)p = as->mrm.ofs;
mode = XM_OFS32;
}
if (as->mrm.idx != RID_NONE) {
mrmidx:
as->mcp = emit_opmx(xo, mode, as->mrm.scale, rr, rb, as->mrm.idx, p);
return;
}
if ((rb&7) == RID_ESP)
*--p = MODRM(XM_SCALE1, RID_ESP, RID_ESP);
}
}
as->mcp = emit_opm(xo, mode, rr, rb, p, 0);
}
/* op rm/mrm, i */
static void emit_gmrmi(ASMState *as, x86Group xg, Reg rb, int32_t i)
{
x86Op xo;
if (checki8(i)) {
emit_i8(as, i);
xo = XG_TOXOi8(xg);
} else {
emit_i32(as, i);
xo = XG_TOXOi(xg);
}
emit_mrm(as, xo, (Reg)(xg & 7) | (rb & REX_64), (rb & ~REX_64));
}
/* -- Emit loads/stores --------------------------------------------------- */
/* Instruction selection for XMM moves. */
#define XMM_MOVRR(as) ((as->flags & JIT_F_SPLIT_XMM) ? XO_MOVSD : XO_MOVAPS)
#define XMM_MOVRM(as) ((as->flags & JIT_F_SPLIT_XMM) ? XO_MOVLPD : XO_MOVSD)
/* mov [base+ofs], i */
static void emit_movmroi(ASMState *as, Reg base, int32_t ofs, int32_t i)
{
emit_i32(as, i);
emit_rmro(as, XO_MOVmi, 0, base, ofs);
}
/* mov [base+ofs], r */
#define emit_movtomro(as, r, base, ofs) \
emit_rmro(as, XO_MOVto, (r), (base), (ofs))
/* Get/set global_State fields. */
#define emit_opgl(as, xo, r, field) \
emit_rma(as, (xo), (r), (void *)&J2G(as->J)->field)
#define emit_getgl(as, r, field) emit_opgl(as, XO_MOV, (r), field)
#define emit_setgl(as, r, field) emit_opgl(as, XO_MOVto, (r), field)
#define emit_setvmstate(as, i) \
(emit_i32(as, i), emit_opgl(as, XO_MOVmi, 0, vmstate))
/* mov r, i / xor r, r */
static void emit_loadi(ASMState *as, Reg r, int32_t i)
{
/* XOR r,r is shorter, but modifies the flags. This is bad for HIOP. */
if (i == 0 && !(LJ_32 && (IR(as->curins)->o == IR_HIOP ||
(as->curins+1 < as->T->nins &&
IR(as->curins+1)->o == IR_HIOP)))) {
emit_rr(as, XO_ARITH(XOg_XOR), r, r);
} else {
MCode *p = as->mcp;
*(int32_t *)(p-4) = i;
p[-5] = (MCode)(XI_MOVri+(r&7));
p -= 5;
REXRB(p, 0, r);
as->mcp = p;
}
}
/* mov r, addr */
#define emit_loada(as, r, addr) \
emit_loadi(as, (r), ptr2addr((addr)))
#if LJ_64
/* mov r, imm64 or shorter 32 bit extended load. */
static void emit_loadu64(ASMState *as, Reg r, uint64_t u64)
{
if (checku32(u64)) { /* 32 bit load clears upper 32 bits. */
emit_loadi(as, r, (int32_t)u64);
} else if (checki32((int64_t)u64)) { /* Sign-extended 32 bit load. */
MCode *p = as->mcp;
*(int32_t *)(p-4) = (int32_t)u64;
as->mcp = emit_opm(XO_MOVmi, XM_REG, REX_64, r, p, -4);
} else { /* Full-size 64 bit load. */
MCode *p = as->mcp;
*(uint64_t *)(p-8) = u64;
p[-9] = (MCode)(XI_MOVri+(r&7));
p[-10] = 0x48 + ((r>>3)&1);
p -= 10;
as->mcp = p;
}
}
#endif
/* movsd r, [&tv->n] / xorps r, r */
static void emit_loadn(ASMState *as, Reg r, cTValue *tv)
{
if (tvispzero(tv)) /* Use xor only for +0. */
emit_rr(as, XO_XORPS, r, r);
else
emit_rma(as, XMM_MOVRM(as), r, &tv->n);
}
/* -- Emit control-flow instructions -------------------------------------- */
/* Label for short jumps. */
typedef MCode *MCLabel;
#if LJ_32 && LJ_HASFFI
/* jmp short target */
static void emit_sjmp(ASMState *as, MCLabel target)
{
MCode *p = as->mcp;
ptrdiff_t delta = target - p;
lua_assert(delta == (int8_t)delta);
p[-1] = (MCode)(int8_t)delta;
p[-2] = XI_JMPs;
as->mcp = p - 2;
}
#endif
/* jcc short target */
static void emit_sjcc(ASMState *as, int cc, MCLabel target)
{
MCode *p = as->mcp;
ptrdiff_t delta = target - p;
lua_assert(delta == (int8_t)delta);
p[-1] = (MCode)(int8_t)delta;
p[-2] = (MCode)(XI_JCCs+(cc&15));
as->mcp = p - 2;
}
/* jcc short (pending target) */
static MCLabel emit_sjcc_label(ASMState *as, int cc)
{
MCode *p = as->mcp;
p[-1] = 0;
p[-2] = (MCode)(XI_JCCs+(cc&15));
as->mcp = p - 2;
return p;
}
/* Fixup jcc short target. */
static void emit_sfixup(ASMState *as, MCLabel source)
{
source[-1] = (MCode)(as->mcp-source);
}
/* Return label pointing to current PC. */
#define emit_label(as) ((as)->mcp)
/* Compute relative 32 bit offset for jump and call instructions. */
static LJ_AINLINE int32_t jmprel(MCode *p, MCode *target)
{
ptrdiff_t delta = target - p;
lua_assert(delta == (int32_t)delta);
return (int32_t)delta;
}
/* jcc target */
static void emit_jcc(ASMState *as, int cc, MCode *target)
{
MCode *p = as->mcp;
*(int32_t *)(p-4) = jmprel(p, target);
p[-5] = (MCode)(XI_JCCn+(cc&15));
p[-6] = 0x0f;
as->mcp = p - 6;
}
/* jmp target */
static void emit_jmp(ASMState *as, MCode *target)
{
MCode *p = as->mcp;
*(int32_t *)(p-4) = jmprel(p, target);
p[-5] = XI_JMP;
as->mcp = p - 5;
}
/* call target */
static void emit_call_(ASMState *as, MCode *target)
{
MCode *p = as->mcp;
#if LJ_64
if (target-p != (int32_t)(target-p)) {
/* Assumes RID_RET is never an argument to calls and always clobbered. */
emit_rr(as, XO_GROUP5, XOg_CALL, RID_RET);
emit_loadu64(as, RID_RET, (uint64_t)target);
return;
}
#endif
*(int32_t *)(p-4) = jmprel(p, target);
p[-5] = XI_CALL;
as->mcp = p - 5;
}
#define emit_call(as, f) emit_call_(as, (MCode *)(void *)(f))
/* -- Emit generic operations --------------------------------------------- */
/* Use 64 bit operations to handle 64 bit IR types. */
#if LJ_64
#define REX_64IR(ir, r) ((r) + (irt_is64((ir)->t) ? REX_64 : 0))
#else
#define REX_64IR(ir, r) (r)
#endif
/* Generic move between two regs. */
static void emit_movrr(ASMState *as, IRIns *ir, Reg dst, Reg src)
{
UNUSED(ir);
if (dst < RID_MAX_GPR)
emit_rr(as, XO_MOV, REX_64IR(ir, dst), src);
else
emit_rr(as, XMM_MOVRR(as), dst, src);
}
/* Generic load of register from stack slot. */
static void emit_spload(ASMState *as, IRIns *ir, Reg r, int32_t ofs)
{
if (r < RID_MAX_GPR)
emit_rmro(as, XO_MOV, REX_64IR(ir, r), RID_ESP, ofs);
else
emit_rmro(as, irt_isnum(ir->t) ? XMM_MOVRM(as) : XO_MOVSS, r, RID_ESP, ofs);
}
/* Generic store of register to stack slot. */
static void emit_spstore(ASMState *as, IRIns *ir, Reg r, int32_t ofs)
{
if (r < RID_MAX_GPR)
emit_rmro(as, XO_MOVto, REX_64IR(ir, r), RID_ESP, ofs);
else
emit_rmro(as, irt_isnum(ir->t) ? XO_MOVSDto : XO_MOVSSto, r, RID_ESP, ofs);
}
/* Add offset to pointer. */
static void emit_addptr(ASMState *as, Reg r, int32_t ofs)
{
if (ofs) {
if ((as->flags & JIT_F_LEA_AGU))
emit_rmro(as, XO_LEA, r, r, ofs);
else
emit_gri(as, XG_ARITHi(XOg_ADD), r, ofs);
}
}
#define emit_spsub(as, ofs) emit_addptr(as, RID_ESP|REX_64, -(ofs))
/* Prefer rematerialization of BASE/L from global_State over spills. */
#define emit_canremat(ref) ((ref) <= REF_BASE)
-781
View File
@@ -1,781 +0,0 @@
/*
** Error handling.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
*/
#define lj_err_c
#define LUA_CORE
#include "lj_obj.h"
#include "lj_err.h"
#include "lj_debug.h"
#include "lj_str.h"
#include "lj_func.h"
#include "lj_state.h"
#include "lj_frame.h"
#include "lj_ff.h"
#include "lj_trace.h"
#include "lj_vm.h"
/*
** LuaJIT can either use internal or external frame unwinding:
**
** - Internal frame unwinding (INT) is free-standing and doesn't require
** any OS or library support.
**
** - External frame unwinding (EXT) uses the system-provided unwind handler.
**
** Pros and Cons:
**
** - EXT requires unwind tables for *all* functions on the C stack between
** the pcall/catch and the error/throw. This is the default on x64,
** but needs to be manually enabled on x86/PPC for non-C++ code.
**
** - INT is faster when actually throwing errors (but this happens rarely).
** Setting up error handlers is zero-cost in any case.
**
** - EXT provides full interoperability with C++ exceptions. You can throw
** Lua errors or C++ exceptions through a mix of Lua frames and C++ frames.
** C++ destructors are called as needed. C++ exceptions caught by pcall
** are converted to the string "C++ exception". Lua errors can be caught
** with catch (...) in C++.
**
** - INT has only limited support for automatically catching C++ exceptions
** on POSIX systems using DWARF2 stack unwinding. Other systems may use
** the wrapper function feature. Lua errors thrown through C++ frames
** cannot be caught by C++ code and C++ destructors are not run.
**
** EXT is the default on x64 systems, INT is the default on all other systems.
**
** EXT can be manually enabled on POSIX systems using GCC and DWARF2 stack
** unwinding with -DLUAJIT_UNWIND_EXTERNAL. *All* C code must be compiled
** with -funwind-tables (or -fexceptions). This includes LuaJIT itself (set
** TARGET_CFLAGS), all of your C/Lua binding code, all loadable C modules
** and all C libraries that have callbacks which may be used to call back
** into Lua. C++ code must *not* be compiled with -fno-exceptions.
**
** EXT cannot be enabled on WIN32 since system exceptions use code-driven SEH.
** EXT is mandatory on WIN64 since the calling convention has an abundance
** of callee-saved registers (rbx, rbp, rsi, rdi, r12-r15, xmm6-xmm15).
** EXT is mandatory on POSIX/x64 since the interpreter doesn't save r12/r13.
*/
#if defined(__GNUC__) && (LJ_TARGET_X64 || defined(LUAJIT_UNWIND_EXTERNAL))
#define LJ_UNWIND_EXT 1
#elif LJ_TARGET_X64 && LJ_TARGET_WINDOWS
#define LJ_UNWIND_EXT 1
#endif
/* -- Error messages ------------------------------------------------------ */
/* Error message strings. */
LJ_DATADEF const char *lj_err_allmsg =
#define ERRDEF(name, msg) msg "\0"
#include "lj_errmsg.h"
;
/* -- Internal frame unwinding -------------------------------------------- */
/* Unwind Lua stack and move error message to new top. */
LJ_NOINLINE static void unwindstack(lua_State *L, TValue *top)
{
lj_func_closeuv(L, top);
if (top < L->top-1) {
copyTV(L, top, L->top-1);
L->top = top+1;
}
lj_state_relimitstack(L);
}
/* Unwind until stop frame. Optionally cleanup frames. */
static void *err_unwind(lua_State *L, void *stopcf, int errcode)
{
TValue *frame = L->base-1;
void *cf = L->cframe;
while (cf) {
int32_t nres = cframe_nres(cframe_raw(cf));
if (nres < 0) { /* C frame without Lua frame? */
TValue *top = restorestack(L, -nres);
if (frame < top) { /* Frame reached? */
if (errcode) {
L->cframe = cframe_prev(cf);
L->base = frame+1;
unwindstack(L, top);
}
return cf;
}
}
if (frame <= tvref(L->stack))
break;
switch (frame_typep(frame)) {
case FRAME_LUA: /* Lua frame. */
case FRAME_LUAP:
frame = frame_prevl(frame);
break;
case FRAME_C: /* C frame. */
#if LJ_HASFFI
unwind_c:
#endif
#if LJ_UNWIND_EXT
if (errcode) {
L->cframe = cframe_prev(cf);
L->base = frame_prevd(frame) + 1;
unwindstack(L, frame);
} else if (cf != stopcf) {
cf = cframe_prev(cf);
frame = frame_prevd(frame);
break;
}
return NULL; /* Continue unwinding. */
#else
UNUSED(stopcf);
cf = cframe_prev(cf);
frame = frame_prevd(frame);
break;
#endif
case FRAME_CP: /* Protected C frame. */
if (cframe_canyield(cf)) { /* Resume? */
if (errcode) {
hook_leave(G(L)); /* Assumes nobody uses coroutines inside hooks. */
L->cframe = NULL;
L->status = (uint8_t)errcode;
}
return cf;
}
if (errcode) {
L->cframe = cframe_prev(cf);
L->base = frame_prevd(frame) + 1;
unwindstack(L, frame);
}
return cf;
case FRAME_CONT: /* Continuation frame. */
#if LJ_HASFFI
if ((frame-1)->u32.lo == LJ_CONT_FFI_CALLBACK)
goto unwind_c;
#endif
case FRAME_VARG: /* Vararg frame. */
frame = frame_prevd(frame);
break;
case FRAME_PCALL: /* FF pcall() frame. */
case FRAME_PCALLH: /* FF pcall() frame inside hook. */
if (errcode) {
if (errcode == LUA_YIELD) {
frame = frame_prevd(frame);
break;
}
if (frame_typep(frame) == FRAME_PCALL)
hook_leave(G(L));
L->cframe = cf;
L->base = frame_prevd(frame) + 1;
unwindstack(L, L->base);
}
return (void *)((intptr_t)cf | CFRAME_UNWIND_FF);
}
}
/* No C frame. */
if (errcode) {
L->cframe = NULL;
L->base = tvref(L->stack)+1;
unwindstack(L, L->base);
if (G(L)->panic)
G(L)->panic(L);
exit(EXIT_FAILURE);
}
return L; /* Anything non-NULL will do. */
}
/* -- External frame unwinding -------------------------------------------- */
#if defined(__GNUC__) && !LJ_NO_UNWIND && !LJ_TARGET_WINDOWS
/*
** We have to use our own definitions instead of the mandatory (!) unwind.h,
** since various OS, distros and compilers mess up the header installation.
*/
typedef struct _Unwind_Exception
{
uint64_t exclass;
void (*excleanup)(int, struct _Unwind_Exception);
uintptr_t p1, p2;
} __attribute__((__aligned__)) _Unwind_Exception;
typedef struct _Unwind_Context _Unwind_Context;
#define _URC_OK 0
#define _URC_FATAL_PHASE1_ERROR 3
#define _URC_HANDLER_FOUND 6
#define _URC_INSTALL_CONTEXT 7
#define _URC_CONTINUE_UNWIND 8
#define _URC_FAILURE 9
#if !LJ_TARGET_ARM
extern uintptr_t _Unwind_GetCFA(_Unwind_Context *);
extern void _Unwind_SetGR(_Unwind_Context *, int, uintptr_t);
extern void _Unwind_SetIP(_Unwind_Context *, uintptr_t);
extern void _Unwind_DeleteException(_Unwind_Exception *);
extern int _Unwind_RaiseException(_Unwind_Exception *);
#define _UA_SEARCH_PHASE 1
#define _UA_CLEANUP_PHASE 2
#define _UA_HANDLER_FRAME 4
#define _UA_FORCE_UNWIND 8
#define LJ_UEXCLASS 0x4c55414a49543200ULL /* LUAJIT2\0 */
#define LJ_UEXCLASS_MAKE(c) (LJ_UEXCLASS | (uint64_t)(c))
#define LJ_UEXCLASS_CHECK(cl) (((cl) ^ LJ_UEXCLASS) <= 0xff)
#define LJ_UEXCLASS_ERRCODE(cl) ((int)((cl) & 0xff))
/* DWARF2 personality handler referenced from interpreter .eh_frame. */
LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions,
uint64_t uexclass, _Unwind_Exception *uex, _Unwind_Context *ctx)
{
void *cf;
lua_State *L;
if (version != 1)
return _URC_FATAL_PHASE1_ERROR;
UNUSED(uexclass);
cf = (void *)_Unwind_GetCFA(ctx);
L = cframe_L(cf);
if ((actions & _UA_SEARCH_PHASE)) {
#if LJ_UNWIND_EXT
if (err_unwind(L, cf, 0) == NULL)
return _URC_CONTINUE_UNWIND;
#endif
if (!LJ_UEXCLASS_CHECK(uexclass)) {
setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP));
}
return _URC_HANDLER_FOUND;
}
if ((actions & _UA_CLEANUP_PHASE)) {
int errcode;
if (LJ_UEXCLASS_CHECK(uexclass)) {
errcode = LJ_UEXCLASS_ERRCODE(uexclass);
} else {
if ((actions & _UA_HANDLER_FRAME))
_Unwind_DeleteException(uex);
errcode = LUA_ERRRUN;
}
#if LJ_UNWIND_EXT
cf = err_unwind(L, cf, errcode);
if ((actions & _UA_FORCE_UNWIND)) {
return _URC_CONTINUE_UNWIND;
} else if (cf) {
_Unwind_SetGR(ctx, LJ_TARGET_EHRETREG, errcode);
_Unwind_SetIP(ctx, (uintptr_t)(cframe_unwind_ff(cf) ?
lj_vm_unwind_ff_eh :
lj_vm_unwind_c_eh));
return _URC_INSTALL_CONTEXT;
}
#if LJ_TARGET_X86ORX64
else if ((actions & _UA_HANDLER_FRAME)) {
/* Workaround for ancient libgcc bug. Still present in RHEL 5.5. :-/
** Real fix: http://gcc.gnu.org/viewcvs/trunk/gcc/unwind-dw2.c?r1=121165&r2=124837&pathrev=153877&diff_format=h
*/
_Unwind_SetGR(ctx, LJ_TARGET_EHRETREG, errcode);
_Unwind_SetIP(ctx, (uintptr_t)lj_vm_unwind_rethrow);
return _URC_INSTALL_CONTEXT;
}
#endif
#else
/* This is not the proper way to escape from the unwinder. We get away with
** it on non-x64 because the interpreter restores all callee-saved regs.
*/
lj_err_throw(L, errcode);
#endif
}
return _URC_CONTINUE_UNWIND;
}
#if LJ_UNWIND_EXT
#if LJ_TARGET_OSX || defined(__OpenBSD__)
/* Sorry, no thread safety for OSX. Complain to Apple, not me. */
static _Unwind_Exception static_uex;
#else
static __thread _Unwind_Exception static_uex;
#endif
/* Raise DWARF2 exception. */
static void err_raise_ext(int errcode)
{
static_uex.exclass = LJ_UEXCLASS_MAKE(errcode);
static_uex.excleanup = NULL;
_Unwind_RaiseException(&static_uex);
}
#endif
#else
extern void _Unwind_DeleteException(void *);
extern int __gnu_unwind_frame (void *, _Unwind_Context *);
extern int _Unwind_VRS_Set(_Unwind_Context *, int, uint32_t, int, void *);
extern int _Unwind_VRS_Get(_Unwind_Context *, int, uint32_t, int, void *);
static inline uint32_t _Unwind_GetGR(_Unwind_Context *ctx, int r)
{
uint32_t v;
_Unwind_VRS_Get(ctx, 0, r, 0, &v);
return v;
}
static inline void _Unwind_SetGR(_Unwind_Context *ctx, int r, uint32_t v)
{
_Unwind_VRS_Set(ctx, 0, r, 0, &v);
}
#define _US_VIRTUAL_UNWIND_FRAME 0
#define _US_UNWIND_FRAME_STARTING 1
#define _US_ACTION_MASK 3
#define _US_FORCE_UNWIND 8
/* ARM unwinder personality handler referenced from interpreter .ARM.extab. */
LJ_FUNCA int lj_err_unwind_arm(int state, void *ucb, _Unwind_Context *ctx)
{
void *cf = (void *)_Unwind_GetGR(ctx, 13);
lua_State *L = cframe_L(cf);
if ((state & _US_ACTION_MASK) == _US_VIRTUAL_UNWIND_FRAME) {
setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP));
return _URC_HANDLER_FOUND;
}
if ((state&(_US_ACTION_MASK|_US_FORCE_UNWIND)) == _US_UNWIND_FRAME_STARTING) {
_Unwind_DeleteException(ucb);
_Unwind_SetGR(ctx, 15, (uint32_t)(void *)lj_err_throw);
_Unwind_SetGR(ctx, 0, (uint32_t)L);
_Unwind_SetGR(ctx, 1, (uint32_t)LUA_ERRRUN);
return _URC_INSTALL_CONTEXT;
}
if (__gnu_unwind_frame(ucb, ctx) != _URC_OK)
return _URC_FAILURE;
return _URC_CONTINUE_UNWIND;
}
#endif
#elif LJ_TARGET_X64 && LJ_TARGET_WINDOWS
/*
** Someone in Redmond owes me several days of my life. A lot of this is
** undocumented or just plain wrong on MSDN. Some of it can be gathered
** from 3rd party docs or must be found by trial-and-error. They really
** don't want you to write your own language-specific exception handler
** or to interact gracefully with MSVC. :-(
**
** Apparently MSVC doesn't call C++ destructors for foreign exceptions
** unless you compile your C++ code with /EHa. Unfortunately this means
** catch (...) also catches things like access violations. The use of
** _set_se_translator doesn't really help, because it requires /EHa, too.
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
/* Taken from: http://www.nynaeve.net/?p=99 */
typedef struct UndocumentedDispatcherContext {
ULONG64 ControlPc;
ULONG64 ImageBase;
PRUNTIME_FUNCTION FunctionEntry;
ULONG64 EstablisherFrame;
ULONG64 TargetIp;
PCONTEXT ContextRecord;
PEXCEPTION_ROUTINE LanguageHandler;
PVOID HandlerData;
PUNWIND_HISTORY_TABLE HistoryTable;
ULONG ScopeIndex;
ULONG Fill0;
} UndocumentedDispatcherContext;
#ifdef _MSC_VER
/* Another wild guess. */
extern __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow);
#endif
#define LJ_MSVC_EXCODE ((DWORD)0xe06d7363)
#define LJ_EXCODE ((DWORD)0xe24c4a00)
#define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c))
#define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff)
#define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff))
/* Win64 exception handler for interpreter frame. */
LJ_FUNCA EXCEPTION_DISPOSITION lj_err_unwind_win64(EXCEPTION_RECORD *rec,
void *cf, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch)
{
lua_State *L = cframe_L(cf);
int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ?
LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN;
if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */
/* Unwind internal frames. */
err_unwind(L, cf, errcode);
} else {
void *cf2 = err_unwind(L, cf, 0);
if (cf2) { /* We catch it, so start unwinding the upper frames. */
if (rec->ExceptionCode == LJ_MSVC_EXCODE) {
#ifdef _MSC_VER
__DestructExceptionObject(rec, 1);
#endif
setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP));
} else if (!LJ_EXCODE_CHECK(rec->ExceptionCode)) {
/* Don't catch access violations etc. */
return ExceptionContinueSearch;
}
/* Unwind the stack and call all handlers for all lower C frames
** (including ourselves) again with EH_UNWINDING set. Then set
** rsp = cf, rax = errcode and jump to the specified target.
*/
RtlUnwindEx(cf, (void *)((cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ?
lj_vm_unwind_ff_eh :
lj_vm_unwind_c_eh),
rec, (void *)errcode, ctx, dispatch->HistoryTable);
/* RtlUnwindEx should never return. */
}
}
return ExceptionContinueSearch;
}
/* Raise Windows exception. */
static void err_raise_ext(int errcode)
{
RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL);
}
#endif
/* -- Error handling ------------------------------------------------------ */
/* Throw error. Find catch frame, unwind stack and continue. */
LJ_NOINLINE void LJ_FASTCALL lj_err_throw(lua_State *L, int errcode)
{
global_State *g = G(L);
lj_trace_abort(g);
setgcrefnull(g->jit_L);
L->status = 0;
#if LJ_UNWIND_EXT
err_raise_ext(errcode);
/*
** A return from this function signals a corrupt C stack that cannot be
** unwound. We have no choice but to call the panic function and exit.
**
** Usually this is caused by a C function without unwind information.
** This should never happen on x64, but may happen if you've manually
** enabled LUAJIT_UNWIND_EXTERNAL and forgot to recompile *every*
** non-C++ file with -funwind-tables.
*/
if (G(L)->panic)
G(L)->panic(L);
#else
{
void *cf = err_unwind(L, NULL, errcode);
if (cframe_unwind_ff(cf))
lj_vm_unwind_ff(cframe_raw(cf));
else
lj_vm_unwind_c(cframe_raw(cf), errcode);
}
#endif
exit(EXIT_FAILURE);
}
/* Return string object for error message. */
LJ_NOINLINE GCstr *lj_err_str(lua_State *L, ErrMsg em)
{
return lj_str_newz(L, err2msg(em));
}
/* Out-of-memory error. */
LJ_NOINLINE void lj_err_mem(lua_State *L)
{
if (L->status == LUA_ERRERR+1) /* Don't touch the stack during lua_open. */
lj_vm_unwind_c(L->cframe, LUA_ERRMEM);
setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRMEM));
lj_err_throw(L, LUA_ERRMEM);
}
/* Find error function for runtime errors. Requires an extra stack traversal. */
static ptrdiff_t finderrfunc(lua_State *L)
{
cTValue *frame = L->base-1, *bot = tvref(L->stack);
void *cf = L->cframe;
while (frame > bot) {
lua_assert(cf != NULL);
while (cframe_nres(cframe_raw(cf)) < 0) { /* cframe without frame? */
if (frame >= restorestack(L, -cframe_nres(cf)))
break;
if (cframe_errfunc(cf) >= 0) /* Error handler not inherited (-1)? */
return cframe_errfunc(cf);
cf = cframe_prev(cf); /* Else unwind cframe and continue searching. */
if (cf == NULL)
return 0;
}
switch (frame_typep(frame)) {
case FRAME_LUA:
case FRAME_LUAP:
frame = frame_prevl(frame);
break;
case FRAME_C:
cf = cframe_prev(cf);
/* fallthrough */
case FRAME_CONT:
#if LJ_HASFFI
if ((frame-1)->u32.lo == LJ_CONT_FFI_CALLBACK)
cf = cframe_prev(cf);
#endif
case FRAME_VARG:
frame = frame_prevd(frame);
break;
case FRAME_CP:
if (cframe_canyield(cf)) return 0;
if (cframe_errfunc(cf) >= 0)
return cframe_errfunc(cf);
frame = frame_prevd(frame);
break;
case FRAME_PCALL:
case FRAME_PCALLH:
if (frame_ftsz(frame) >= (ptrdiff_t)(2*sizeof(TValue))) /* xpcall? */
return savestack(L, frame-1); /* Point to xpcall's errorfunc. */
return 0;
default:
lua_assert(0);
return 0;
}
}
return 0;
}
/* Runtime error. */
LJ_NOINLINE void lj_err_run(lua_State *L)
{
ptrdiff_t ef = finderrfunc(L);
if (ef) {
TValue *errfunc = restorestack(L, ef);
TValue *top = L->top;
lj_trace_abort(G(L));
if (!tvisfunc(errfunc) || L->status == LUA_ERRERR) {
setstrV(L, top-1, lj_err_str(L, LJ_ERR_ERRERR));
lj_err_throw(L, LUA_ERRERR);
}
L->status = LUA_ERRERR;
copyTV(L, top, top-1);
copyTV(L, top-1, errfunc);
L->top = top+1;
lj_vm_call(L, top, 1+1); /* Stack: |errfunc|msg| -> |msg| */
}
lj_err_throw(L, LUA_ERRRUN);
}
/* Formatted runtime error message. */
LJ_NORET LJ_NOINLINE static void err_msgv(lua_State *L, ErrMsg em, ...)
{
const char *msg;
va_list argp;
va_start(argp, em);
if (curr_funcisL(L)) L->top = curr_topL(L);
msg = lj_str_pushvf(L, err2msg(em), argp);
va_end(argp);
lj_debug_addloc(L, msg, L->base-1, NULL);
lj_err_run(L);
}
/* Non-vararg variant for better calling conventions. */
LJ_NOINLINE void lj_err_msg(lua_State *L, ErrMsg em)
{
err_msgv(L, em);
}
/* Lexer error. */
LJ_NOINLINE void lj_err_lex(lua_State *L, GCstr *src, const char *tok,
BCLine line, ErrMsg em, va_list argp)
{
char buff[LUA_IDSIZE];
const char *msg;
lj_debug_shortname(buff, src);
msg = lj_str_pushvf(L, err2msg(em), argp);
msg = lj_str_pushf(L, "%s:%d: %s", buff, line, msg);
if (tok)
lj_str_pushf(L, err2msg(LJ_ERR_XNEAR), msg, tok);
lj_err_throw(L, LUA_ERRSYNTAX);
}
/* Typecheck error for operands. */
LJ_NOINLINE void lj_err_optype(lua_State *L, cTValue *o, ErrMsg opm)
{
const char *tname = lj_typename(o);
const char *opname = err2msg(opm);
if (curr_funcisL(L)) {
GCproto *pt = curr_proto(L);
const BCIns *pc = cframe_Lpc(L) - 1;
const char *oname = NULL;
const char *kind = lj_debug_slotname(pt, pc, (BCReg)(o-L->base), &oname);
if (kind)
err_msgv(L, LJ_ERR_BADOPRT, opname, kind, oname, tname);
}
err_msgv(L, LJ_ERR_BADOPRV, opname, tname);
}
/* Typecheck error for ordered comparisons. */
LJ_NOINLINE void lj_err_comp(lua_State *L, cTValue *o1, cTValue *o2)
{
const char *t1 = lj_typename(o1);
const char *t2 = lj_typename(o2);
err_msgv(L, t1 == t2 ? LJ_ERR_BADCMPV : LJ_ERR_BADCMPT, t1, t2);
/* This assumes the two "boolean" entries are commoned by the C compiler. */
}
/* Typecheck error for __call. */
LJ_NOINLINE void lj_err_optype_call(lua_State *L, TValue *o)
{
/* Gross hack if lua_[p]call or pcall/xpcall fail for a non-callable object:
** L->base still points to the caller. So add a dummy frame with L instead
** of a function. See lua_getstack().
*/
const BCIns *pc = cframe_Lpc(L);
if (((ptrdiff_t)pc & FRAME_TYPE) != FRAME_LUA) {
const char *tname = lj_typename(o);
setframe_pc(o, pc);
setframe_gc(o, obj2gco(L));
L->top = L->base = o+1;
err_msgv(L, LJ_ERR_BADCALL, tname);
}
lj_err_optype(L, o, LJ_ERR_OPCALL);
}
/* Error in context of caller. */
LJ_NOINLINE void lj_err_callermsg(lua_State *L, const char *msg)
{
TValue *frame = L->base-1;
TValue *pframe = NULL;
if (frame_islua(frame)) {
pframe = frame_prevl(frame);
} else if (frame_iscont(frame)) {
#if LJ_HASFFI
if ((frame-1)->u32.lo == LJ_CONT_FFI_CALLBACK) {
pframe = frame;
frame = NULL;
} else
#endif
{
pframe = frame_prevd(frame);
#if LJ_HASFFI
/* Remove frame for FFI metamethods. */
if (frame_func(frame)->c.ffid >= FF_ffi_meta___index &&
frame_func(frame)->c.ffid <= FF_ffi_meta___tostring) {
L->base = pframe+1;
L->top = frame;
setcframe_pc(cframe_raw(L->cframe), frame_contpc(frame));
}
#endif
}
}
lj_debug_addloc(L, msg, pframe, frame);
lj_err_run(L);
}
/* Formatted error in context of caller. */
LJ_NOINLINE void lj_err_callerv(lua_State *L, ErrMsg em, ...)
{
const char *msg;
va_list argp;
va_start(argp, em);
msg = lj_str_pushvf(L, err2msg(em), argp);
va_end(argp);
lj_err_callermsg(L, msg);
}
/* Error in context of caller. */
LJ_NOINLINE void lj_err_caller(lua_State *L, ErrMsg em)
{
lj_err_callermsg(L, err2msg(em));
}
/* Argument error message. */
LJ_NORET LJ_NOINLINE static void err_argmsg(lua_State *L, int narg,
const char *msg)
{
const char *fname = "?";
const char *ftype = lj_debug_funcname(L, L->base - 1, &fname);
if (narg < 0 && narg > LUA_REGISTRYINDEX)
narg = (int)(L->top - L->base) + narg + 1;
if (ftype && ftype[3] == 'h' && --narg == 0) /* Check for "method". */
msg = lj_str_pushf(L, err2msg(LJ_ERR_BADSELF), fname, msg);
else
msg = lj_str_pushf(L, err2msg(LJ_ERR_BADARG), narg, fname, msg);
lj_err_callermsg(L, msg);
}
/* Formatted argument error. */
LJ_NOINLINE void lj_err_argv(lua_State *L, int narg, ErrMsg em, ...)
{
const char *msg;
va_list argp;
va_start(argp, em);
msg = lj_str_pushvf(L, err2msg(em), argp);
va_end(argp);
err_argmsg(L, narg, msg);
}
/* Argument error. */
LJ_NOINLINE void lj_err_arg(lua_State *L, int narg, ErrMsg em)
{
err_argmsg(L, narg, err2msg(em));
}
/* Typecheck error for arguments. */
LJ_NOINLINE void lj_err_argtype(lua_State *L, int narg, const char *xname)
{
TValue *o = narg < 0 ? L->top + narg : L->base + narg-1;
const char *tname = o < L->top ? lj_typename(o) : lj_obj_typename[0];
const char *msg = lj_str_pushf(L, err2msg(LJ_ERR_BADTYPE), xname, tname);
err_argmsg(L, narg, msg);
}
/* Typecheck error for arguments. */
LJ_NOINLINE void lj_err_argt(lua_State *L, int narg, int tt)
{
lj_err_argtype(L, narg, lj_obj_typename[tt+1]);
}
/* -- Public error handling API ------------------------------------------- */
LUA_API lua_CFunction lua_atpanic(lua_State *L, lua_CFunction panicf)
{
lua_CFunction old = G(L)->panic;
G(L)->panic = panicf;
return old;
}
/* Forwarders for the public API (C calling convention and no LJ_NORET). */
LUA_API int lua_error(lua_State *L)
{
lj_err_run(L);
return 0; /* unreachable */
}
LUALIB_API int luaL_argerror(lua_State *L, int narg, const char *msg)
{
err_argmsg(L, narg, msg);
return 0; /* unreachable */
}
LUALIB_API int luaL_typerror(lua_State *L, int narg, const char *xname)
{
lj_err_argtype(L, narg, xname);
return 0; /* unreachable */
}
LUALIB_API void luaL_where(lua_State *L, int level)
{
int size;
cTValue *frame = lj_debug_frame(L, level, &size);
lj_debug_addloc(L, "", frame, size ? frame+size : NULL);
}
LUALIB_API int luaL_error(lua_State *L, const char *fmt, ...)
{
const char *msg;
va_list argp;
va_start(argp, fmt);
msg = lj_str_pushvf(L, fmt, argp);
va_end(argp);
lj_err_callermsg(L, msg);
return 0; /* unreachable */
}
-41
View File
@@ -1,41 +0,0 @@
/*
** Error handling.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_ERR_H
#define _LJ_ERR_H
#include <stdarg.h>
#include "lj_obj.h"
typedef enum {
#define ERRDEF(name, msg) \
LJ_ERR_##name, LJ_ERR_##name##_ = LJ_ERR_##name + sizeof(msg)-1,
#include "lj_errmsg.h"
LJ_ERR__MAX
} ErrMsg;
LJ_DATA const char *lj_err_allmsg;
#define err2msg(em) (lj_err_allmsg+(int)(em))
LJ_FUNC GCstr *lj_err_str(lua_State *L, ErrMsg em);
LJ_FUNCA_NORET void LJ_FASTCALL lj_err_throw(lua_State *L, int errcode);
LJ_FUNC_NORET void lj_err_mem(lua_State *L);
LJ_FUNC_NORET void lj_err_run(lua_State *L);
LJ_FUNC_NORET void lj_err_msg(lua_State *L, ErrMsg em);
LJ_FUNC_NORET void lj_err_lex(lua_State *L, GCstr *src, const char *tok,
BCLine line, ErrMsg em, va_list argp);
LJ_FUNC_NORET void lj_err_optype(lua_State *L, cTValue *o, ErrMsg opm);
LJ_FUNC_NORET void lj_err_comp(lua_State *L, cTValue *o1, cTValue *o2);
LJ_FUNC_NORET void lj_err_optype_call(lua_State *L, TValue *o);
LJ_FUNC_NORET void lj_err_callermsg(lua_State *L, const char *msg);
LJ_FUNC_NORET void lj_err_callerv(lua_State *L, ErrMsg em, ...);
LJ_FUNC_NORET void lj_err_caller(lua_State *L, ErrMsg em);
LJ_FUNC_NORET void lj_err_arg(lua_State *L, int narg, ErrMsg em);
LJ_FUNC_NORET void lj_err_argv(lua_State *L, int narg, ErrMsg em, ...);
LJ_FUNC_NORET void lj_err_argtype(lua_State *L, int narg, const char *xname);
LJ_FUNC_NORET void lj_err_argt(lua_State *L, int narg, int tt);
#endif
-889
View File
@@ -1,889 +0,0 @@
/*
** Fast function call recorder.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
*/
#define lj_ffrecord_c
#define LUA_CORE
#include "lj_obj.h"
#if LJ_HASJIT
#include "lj_err.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_frame.h"
#include "lj_bc.h"
#include "lj_ff.h"
#include "lj_ir.h"
#include "lj_jit.h"
#include "lj_ircall.h"
#include "lj_iropt.h"
#include "lj_trace.h"
#include "lj_record.h"
#include "lj_ffrecord.h"
#include "lj_crecord.h"
#include "lj_dispatch.h"
#include "lj_vm.h"
#include "lj_strscan.h"
/* Some local macros to save typing. Undef'd at the end. */
#define IR(ref) (&J->cur.ir[(ref)])
/* Pass IR on to next optimization in chain (FOLD). */
#define emitir(ot, a, b) (lj_ir_set(J, (ot), (a), (b)), lj_opt_fold(J))
/* -- Fast function recording handlers ------------------------------------ */
/* Conventions for fast function call handlers:
**
** The argument slots start at J->base[0]. All of them are guaranteed to be
** valid and type-specialized references. J->base[J->maxslot] is set to 0
** as a sentinel. The runtime argument values start at rd->argv[0].
**
** In general fast functions should check for presence of all of their
** arguments and for the correct argument types. Some simplifications
** are allowed if the interpreter throws instead. But even if recording
** is aborted, the generated IR must be consistent (no zero-refs).
**
** The number of results in rd->nres is set to 1. Handlers that return
** a different number of results need to override it. A negative value
** prevents return processing (e.g. for pending calls).
**
** Results need to be stored starting at J->base[0]. Return processing
** moves them to the right slots later.
**
** The per-ffid auxiliary data is the value of the 2nd part of the
** LJLIB_REC() annotation. This allows handling similar functionality
** in a common handler.
*/
/* Type of handler to record a fast function. */
typedef void (LJ_FASTCALL *RecordFunc)(jit_State *J, RecordFFData *rd);
/* Get runtime value of int argument. */
static int32_t argv2int(jit_State *J, TValue *o)
{
if (!lj_strscan_numberobj(o))
lj_trace_err(J, LJ_TRERR_BADTYPE);
return tvisint(o) ? intV(o) : lj_num2int(numV(o));
}
/* Get runtime value of string argument. */
static GCstr *argv2str(jit_State *J, TValue *o)
{
if (LJ_LIKELY(tvisstr(o))) {
return strV(o);
} else {
GCstr *s;
if (!tvisnumber(o))
lj_trace_err(J, LJ_TRERR_BADTYPE);
if (tvisint(o))
s = lj_str_fromint(J->L, intV(o));
else
s = lj_str_fromnum(J->L, &o->n);
setstrV(J->L, o, s);
return s;
}
}
/* Return number of results wanted by caller. */
static ptrdiff_t results_wanted(jit_State *J)
{
TValue *frame = J->L->base-1;
if (frame_islua(frame))
return (ptrdiff_t)bc_b(frame_pc(frame)[-1]) - 1;
else
return -1;
}
/* Throw error for unsupported variant of fast function. */
LJ_NORET static void recff_nyiu(jit_State *J)
{
setfuncV(J->L, &J->errinfo, J->fn);
lj_trace_err_info(J, LJ_TRERR_NYIFFU);
}
/* Fallback handler for all fast functions that are not recorded (yet). */
static void LJ_FASTCALL recff_nyi(jit_State *J, RecordFFData *rd)
{
setfuncV(J->L, &J->errinfo, J->fn);
lj_trace_err_info(J, LJ_TRERR_NYIFF);
UNUSED(rd);
}
/* C functions can have arbitrary side-effects and are not recorded (yet). */
static void LJ_FASTCALL recff_c(jit_State *J, RecordFFData *rd)
{
setfuncV(J->L, &J->errinfo, J->fn);
lj_trace_err_info(J, LJ_TRERR_NYICF);
UNUSED(rd);
}
/* -- Base library fast functions ----------------------------------------- */
static void LJ_FASTCALL recff_assert(jit_State *J, RecordFFData *rd)
{
/* Arguments already specialized. The interpreter throws for nil/false. */
rd->nres = J->maxslot; /* Pass through all arguments. */
}
static void LJ_FASTCALL recff_type(jit_State *J, RecordFFData *rd)
{
/* Arguments already specialized. Result is a constant string. Neat, huh? */
uint32_t t;
if (tvisnumber(&rd->argv[0]))
t = ~LJ_TNUMX;
else if (LJ_64 && tvislightud(&rd->argv[0]))
t = ~LJ_TLIGHTUD;
else
t = ~itype(&rd->argv[0]);
J->base[0] = lj_ir_kstr(J, strV(&J->fn->c.upvalue[t]));
UNUSED(rd);
}
static void LJ_FASTCALL recff_getmetatable(jit_State *J, RecordFFData *rd)
{
TRef tr = J->base[0];
if (tr) {
RecordIndex ix;
ix.tab = tr;
copyTV(J->L, &ix.tabv, &rd->argv[0]);
if (lj_record_mm_lookup(J, &ix, MM_metatable))
J->base[0] = ix.mobj;
else
J->base[0] = ix.mt;
} /* else: Interpreter will throw. */
}
static void LJ_FASTCALL recff_setmetatable(jit_State *J, RecordFFData *rd)
{
TRef tr = J->base[0];
TRef mt = J->base[1];
if (tref_istab(tr) && (tref_istab(mt) || (mt && tref_isnil(mt)))) {
TRef fref, mtref;
RecordIndex ix;
ix.tab = tr;
copyTV(J->L, &ix.tabv, &rd->argv[0]);
lj_record_mm_lookup(J, &ix, MM_metatable); /* Guard for no __metatable. */
fref = emitir(IRT(IR_FREF, IRT_P32), tr, IRFL_TAB_META);
mtref = tref_isnil(mt) ? lj_ir_knull(J, IRT_TAB) : mt;
emitir(IRT(IR_FSTORE, IRT_TAB), fref, mtref);
if (!tref_isnil(mt))
emitir(IRT(IR_TBAR, IRT_TAB), tr, 0);
J->base[0] = tr;
J->needsnap = 1;
} /* else: Interpreter will throw. */
}
static void LJ_FASTCALL recff_rawget(jit_State *J, RecordFFData *rd)
{
RecordIndex ix;
ix.tab = J->base[0]; ix.key = J->base[1];
if (tref_istab(ix.tab) && ix.key) {
ix.val = 0; ix.idxchain = 0;
settabV(J->L, &ix.tabv, tabV(&rd->argv[0]));
copyTV(J->L, &ix.keyv, &rd->argv[1]);
J->base[0] = lj_record_idx(J, &ix);
} /* else: Interpreter will throw. */
}
static void LJ_FASTCALL recff_rawset(jit_State *J, RecordFFData *rd)
{
RecordIndex ix;
ix.tab = J->base[0]; ix.key = J->base[1]; ix.val = J->base[2];
if (tref_istab(ix.tab) && ix.key && ix.val) {
ix.idxchain = 0;
settabV(J->L, &ix.tabv, tabV(&rd->argv[0]));
copyTV(J->L, &ix.keyv, &rd->argv[1]);
copyTV(J->L, &ix.valv, &rd->argv[2]);
lj_record_idx(J, &ix);
/* Pass through table at J->base[0] as result. */
} /* else: Interpreter will throw. */
}
static void LJ_FASTCALL recff_rawequal(jit_State *J, RecordFFData *rd)
{
TRef tra = J->base[0];
TRef trb = J->base[1];
if (tra && trb) {
int diff = lj_record_objcmp(J, tra, trb, &rd->argv[0], &rd->argv[1]);
J->base[0] = diff ? TREF_FALSE : TREF_TRUE;
} /* else: Interpreter will throw. */
}
#if LJ_52
static void LJ_FASTCALL recff_rawlen(jit_State *J, RecordFFData *rd)
{
TRef tr = J->base[0];
if (tref_isstr(tr))
J->base[0] = emitir(IRTI(IR_FLOAD), tr, IRFL_STR_LEN);
else if (tref_istab(tr))
J->base[0] = lj_ir_call(J, IRCALL_lj_tab_len, tr);
/* else: Interpreter will throw. */
UNUSED(rd);
}
#endif
/* Determine mode of select() call. */
int32_t lj_ffrecord_select_mode(jit_State *J, TRef tr, TValue *tv)
{
if (tref_isstr(tr) && *strVdata(tv) == '#') { /* select('#', ...) */
if (strV(tv)->len == 1) {
emitir(IRTG(IR_EQ, IRT_STR), tr, lj_ir_kstr(J, strV(tv)));
} else {
TRef trptr = emitir(IRT(IR_STRREF, IRT_P32), tr, lj_ir_kint(J, 0));
TRef trchar = emitir(IRT(IR_XLOAD, IRT_U8), trptr, IRXLOAD_READONLY);
emitir(IRTG(IR_EQ, IRT_INT), trchar, lj_ir_kint(J, '#'));
}
return 0;
} else { /* select(n, ...) */
int32_t start = argv2int(J, tv);
if (start == 0) lj_trace_err(J, LJ_TRERR_BADTYPE); /* A bit misleading. */
return start;
}
}
static void LJ_FASTCALL recff_select(jit_State *J, RecordFFData *rd)
{
TRef tr = J->base[0];
if (tr) {
ptrdiff_t start = lj_ffrecord_select_mode(J, tr, &rd->argv[0]);
if (start == 0) { /* select('#', ...) */
J->base[0] = lj_ir_kint(J, J->maxslot - 1);
} else if (tref_isk(tr)) { /* select(k, ...) */
ptrdiff_t n = (ptrdiff_t)J->maxslot;
if (start < 0) start += n;
else if (start > n) start = n;
rd->nres = n - start;
if (start >= 1) {
ptrdiff_t i;
for (i = 0; i < n - start; i++)
J->base[i] = J->base[start+i];
} /* else: Interpreter will throw. */
} else {
recff_nyiu(J);
}
} /* else: Interpreter will throw. */
}
static void LJ_FASTCALL recff_tonumber(jit_State *J, RecordFFData *rd)
{
TRef tr = J->base[0];
TRef base = J->base[1];
if (tr && base) {
base = lj_opt_narrow_toint(J, base);
if (!tref_isk(base) || IR(tref_ref(base))->i != 10)
recff_nyiu(J);
}
if (tref_isnumber_str(tr)) {
if (tref_isstr(tr)) {
TValue tmp;
if (!lj_strscan_num(strV(&rd->argv[0]), &tmp))
recff_nyiu(J); /* Would need an inverted STRTO for this case. */
tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0);
}
#if LJ_HASFFI
} else if (tref_iscdata(tr)) {
lj_crecord_tonumber(J, rd);
return;
#endif
} else {
tr = TREF_NIL;
}
J->base[0] = tr;
UNUSED(rd);
}
static TValue *recff_metacall_cp(lua_State *L, lua_CFunction dummy, void *ud)
{
jit_State *J = (jit_State *)ud;
lj_record_tailcall(J, 0, 1);
UNUSED(L); UNUSED(dummy);
return NULL;
}
static int recff_metacall(jit_State *J, RecordFFData *rd, MMS mm)
{
RecordIndex ix;
ix.tab = J->base[0];
copyTV(J->L, &ix.tabv, &rd->argv[0]);
if (lj_record_mm_lookup(J, &ix, mm)) { /* Has metamethod? */
int errcode;
TValue argv0;
/* Temporarily insert metamethod below object. */
J->base[1] = J->base[0];
J->base[0] = ix.mobj;
copyTV(J->L, &argv0, &rd->argv[0]);
copyTV(J->L, &rd->argv[1], &rd->argv[0]);
copyTV(J->L, &rd->argv[0], &ix.mobjv);
/* Need to protect lj_record_tailcall because it may throw. */
errcode = lj_vm_cpcall(J->L, NULL, J, recff_metacall_cp);
/* Always undo Lua stack changes to avoid confusing the interpreter. */
copyTV(J->L, &rd->argv[0], &argv0);
if (errcode)
lj_err_throw(J->L, errcode); /* Propagate errors. */
rd->nres = -1; /* Pending call. */
return 1; /* Tailcalled to metamethod. */
}
return 0;
}
static void LJ_FASTCALL recff_tostring(jit_State *J, RecordFFData *rd)
{
TRef tr = J->base[0];
if (tref_isstr(tr)) {
/* Ignore __tostring in the string base metatable. */
/* Pass on result in J->base[0]. */
} else if (!recff_metacall(J, rd, MM_tostring)) {
if (tref_isnumber(tr)) {
J->base[0] = emitir(IRT(IR_TOSTR, IRT_STR), tr, 0);
} else if (tref_ispri(tr)) {
J->base[0] = lj_ir_kstr(J, strV(&J->fn->c.upvalue[tref_type(tr)]));
} else {
recff_nyiu(J);
}
}
}
static void LJ_FASTCALL recff_ipairs_aux(jit_State *J, RecordFFData *rd)
{
RecordIndex ix;
ix.tab = J->base[0];
if (tref_istab(ix.tab)) {
if (!tvisnumber(&rd->argv[1])) /* No support for string coercion. */
lj_trace_err(J, LJ_TRERR_BADTYPE);
setintV(&ix.keyv, numberVint(&rd->argv[1])+1);
settabV(J->L, &ix.tabv, tabV(&rd->argv[0]));
ix.val = 0; ix.idxchain = 0;
ix.key = lj_opt_narrow_toint(J, J->base[1]);
J->base[0] = ix.key = emitir(IRTI(IR_ADD), ix.key, lj_ir_kint(J, 1));
J->base[1] = lj_record_idx(J, &ix);
rd->nres = tref_isnil(J->base[1]) ? 0 : 2;
} /* else: Interpreter will throw. */
}
static void LJ_FASTCALL recff_ipairs(jit_State *J, RecordFFData *rd)
{
if (!(LJ_52 && recff_metacall(J, rd, MM_ipairs))) {
TRef tab = J->base[0];
if (tref_istab(tab)) {
J->base[0] = lj_ir_kfunc(J, funcV(&J->fn->c.upvalue[0]));
J->base[1] = tab;
J->base[2] = lj_ir_kint(J, 0);
rd->nres = 3;
} /* else: Interpreter will throw. */
}
}
static void LJ_FASTCALL recff_pcall(jit_State *J, RecordFFData *rd)
{
if (J->maxslot >= 1) {
lj_record_call(J, 0, J->maxslot - 1);
rd->nres = -1; /* Pending call. */
} /* else: Interpreter will throw. */
}
static TValue *recff_xpcall_cp(lua_State *L, lua_CFunction dummy, void *ud)
{
jit_State *J = (jit_State *)ud;
lj_record_call(J, 1, J->maxslot - 2);
UNUSED(L); UNUSED(dummy);
return NULL;
}
static void LJ_FASTCALL recff_xpcall(jit_State *J, RecordFFData *rd)
{
if (J->maxslot >= 2) {
TValue argv0, argv1;
TRef tmp;
int errcode;
/* Swap function and traceback. */
tmp = J->base[0]; J->base[0] = J->base[1]; J->base[1] = tmp;
copyTV(J->L, &argv0, &rd->argv[0]);
copyTV(J->L, &argv1, &rd->argv[1]);
copyTV(J->L, &rd->argv[0], &argv1);
copyTV(J->L, &rd->argv[1], &argv0);
/* Need to protect lj_record_call because it may throw. */
errcode = lj_vm_cpcall(J->L, NULL, J, recff_xpcall_cp);
/* Always undo Lua stack swap to avoid confusing the interpreter. */
copyTV(J->L, &rd->argv[0], &argv0);
copyTV(J->L, &rd->argv[1], &argv1);
if (errcode)
lj_err_throw(J->L, errcode); /* Propagate errors. */
rd->nres = -1; /* Pending call. */
} /* else: Interpreter will throw. */
}
/* -- Math library fast functions ----------------------------------------- */
static void LJ_FASTCALL recff_math_abs(jit_State *J, RecordFFData *rd)
{
TRef tr = lj_ir_tonum(J, J->base[0]);
J->base[0] = emitir(IRTN(IR_ABS), tr, lj_ir_knum_abs(J));
UNUSED(rd);
}
/* Record rounding functions math.floor and math.ceil. */
static void LJ_FASTCALL recff_math_round(jit_State *J, RecordFFData *rd)
{
TRef tr = J->base[0];
if (!tref_isinteger(tr)) { /* Pass through integers unmodified. */
tr = emitir(IRTN(IR_FPMATH), lj_ir_tonum(J, tr), rd->data);
/* Result is integral (or NaN/Inf), but may not fit an int32_t. */
if (LJ_DUALNUM) { /* Try to narrow using a guarded conversion to int. */
lua_Number n = lj_vm_foldfpm(numberVnum(&rd->argv[0]), rd->data);
if (n == (lua_Number)lj_num2int(n))
tr = emitir(IRTGI(IR_CONV), tr, IRCONV_INT_NUM|IRCONV_CHECK);
}
J->base[0] = tr;
}
}
/* Record unary math.* functions, mapped to IR_FPMATH opcode. */
static void LJ_FASTCALL recff_math_unary(jit_State *J, RecordFFData *rd)
{
J->base[0] = emitir(IRTN(IR_FPMATH), lj_ir_tonum(J, J->base[0]), rd->data);
}
/* Record math.log. */
static void LJ_FASTCALL recff_math_log(jit_State *J, RecordFFData *rd)
{
TRef tr = lj_ir_tonum(J, J->base[0]);
if (J->base[1]) {
#ifdef LUAJIT_NO_LOG2
uint32_t fpm = IRFPM_LOG;
#else
uint32_t fpm = IRFPM_LOG2;
#endif
TRef trb = lj_ir_tonum(J, J->base[1]);
tr = emitir(IRTN(IR_FPMATH), tr, fpm);
trb = emitir(IRTN(IR_FPMATH), trb, fpm);
trb = emitir(IRTN(IR_DIV), lj_ir_knum_one(J), trb);
tr = emitir(IRTN(IR_MUL), tr, trb);
} else {
tr = emitir(IRTN(IR_FPMATH), tr, IRFPM_LOG);
}
J->base[0] = tr;
UNUSED(rd);
}
/* Record math.atan2. */
static void LJ_FASTCALL recff_math_atan2(jit_State *J, RecordFFData *rd)
{
TRef tr = lj_ir_tonum(J, J->base[0]);
TRef tr2 = lj_ir_tonum(J, J->base[1]);
J->base[0] = emitir(IRTN(IR_ATAN2), tr, tr2);
UNUSED(rd);
}
/* Record math.ldexp. */
static void LJ_FASTCALL recff_math_ldexp(jit_State *J, RecordFFData *rd)
{
TRef tr = lj_ir_tonum(J, J->base[0]);
#if LJ_TARGET_X86ORX64
TRef tr2 = lj_ir_tonum(J, J->base[1]);
#else
TRef tr2 = lj_opt_narrow_toint(J, J->base[1]);
#endif
J->base[0] = emitir(IRTN(IR_LDEXP), tr, tr2);
UNUSED(rd);
}
/* Record math.asin, math.acos, math.atan. */
static void LJ_FASTCALL recff_math_atrig(jit_State *J, RecordFFData *rd)
{
TRef y = lj_ir_tonum(J, J->base[0]);
TRef x = lj_ir_knum_one(J);
uint32_t ffid = rd->data;
if (ffid != FF_math_atan) {
TRef tmp = emitir(IRTN(IR_MUL), y, y);
tmp = emitir(IRTN(IR_SUB), x, tmp);
tmp = emitir(IRTN(IR_FPMATH), tmp, IRFPM_SQRT);
if (ffid == FF_math_asin) { x = tmp; } else { x = y; y = tmp; }
}
J->base[0] = emitir(IRTN(IR_ATAN2), y, x);
}
static void LJ_FASTCALL recff_math_htrig(jit_State *J, RecordFFData *rd)
{
TRef tr = lj_ir_tonum(J, J->base[0]);
J->base[0] = emitir(IRTN(IR_CALLN), tr, rd->data);
}
static void LJ_FASTCALL recff_math_modf(jit_State *J, RecordFFData *rd)
{
TRef tr = J->base[0];
if (tref_isinteger(tr)) {
J->base[0] = tr;
J->base[1] = lj_ir_kint(J, 0);
} else {
TRef trt;
tr = lj_ir_tonum(J, tr);
trt = emitir(IRTN(IR_FPMATH), tr, IRFPM_TRUNC);
J->base[0] = trt;
J->base[1] = emitir(IRTN(IR_SUB), tr, trt);
}
rd->nres = 2;
}
static void LJ_FASTCALL recff_math_degrad(jit_State *J, RecordFFData *rd)
{
TRef tr = lj_ir_tonum(J, J->base[0]);
TRef trm = lj_ir_knum(J, numV(&J->fn->c.upvalue[0]));
J->base[0] = emitir(IRTN(IR_MUL), tr, trm);
UNUSED(rd);
}
static void LJ_FASTCALL recff_math_pow(jit_State *J, RecordFFData *rd)
{
TRef tr = lj_ir_tonum(J, J->base[0]);
if (!tref_isnumber_str(J->base[1]))
lj_trace_err(J, LJ_TRERR_BADTYPE);
J->base[0] = lj_opt_narrow_pow(J, tr, J->base[1], &rd->argv[1]);
UNUSED(rd);
}
static void LJ_FASTCALL recff_math_minmax(jit_State *J, RecordFFData *rd)
{
TRef tr = lj_ir_tonumber(J, J->base[0]);
uint32_t op = rd->data;
BCReg i;
for (i = 1; J->base[i] != 0; i++) {
TRef tr2 = lj_ir_tonumber(J, J->base[i]);
IRType t = IRT_INT;
if (!(tref_isinteger(tr) && tref_isinteger(tr2))) {
if (tref_isinteger(tr)) tr = emitir(IRTN(IR_CONV), tr, IRCONV_NUM_INT);
if (tref_isinteger(tr2)) tr2 = emitir(IRTN(IR_CONV), tr2, IRCONV_NUM_INT);
t = IRT_NUM;
}
tr = emitir(IRT(op, t), tr, tr2);
}
J->base[0] = tr;
}
static void LJ_FASTCALL recff_math_random(jit_State *J, RecordFFData *rd)
{
GCudata *ud = udataV(&J->fn->c.upvalue[0]);
TRef tr, one;
lj_ir_kgc(J, obj2gco(ud), IRT_UDATA); /* Prevent collection. */
tr = lj_ir_call(J, IRCALL_lj_math_random_step, lj_ir_kptr(J, uddata(ud)));
one = lj_ir_knum_one(J);
tr = emitir(IRTN(IR_SUB), tr, one);
if (J->base[0]) {
TRef tr1 = lj_ir_tonum(J, J->base[0]);
if (J->base[1]) { /* d = floor(d*(r2-r1+1.0)) + r1 */
TRef tr2 = lj_ir_tonum(J, J->base[1]);
tr2 = emitir(IRTN(IR_SUB), tr2, tr1);
tr2 = emitir(IRTN(IR_ADD), tr2, one);
tr = emitir(IRTN(IR_MUL), tr, tr2);
tr = emitir(IRTN(IR_FPMATH), tr, IRFPM_FLOOR);
tr = emitir(IRTN(IR_ADD), tr, tr1);
} else { /* d = floor(d*r1) + 1.0 */
tr = emitir(IRTN(IR_MUL), tr, tr1);
tr = emitir(IRTN(IR_FPMATH), tr, IRFPM_FLOOR);
tr = emitir(IRTN(IR_ADD), tr, one);
}
}
J->base[0] = tr;
UNUSED(rd);
}
/* -- Bit library fast functions ------------------------------------------ */
/* Record unary bit.tobit, bit.bnot, bit.bswap. */
static void LJ_FASTCALL recff_bit_unary(jit_State *J, RecordFFData *rd)
{
TRef tr = lj_opt_narrow_tobit(J, J->base[0]);
J->base[0] = (rd->data == IR_TOBIT) ? tr : emitir(IRTI(rd->data), tr, 0);
}
/* Record N-ary bit.band, bit.bor, bit.bxor. */
static void LJ_FASTCALL recff_bit_nary(jit_State *J, RecordFFData *rd)
{
TRef tr = lj_opt_narrow_tobit(J, J->base[0]);
uint32_t op = rd->data;
BCReg i;
for (i = 1; J->base[i] != 0; i++)
tr = emitir(IRTI(op), tr, lj_opt_narrow_tobit(J, J->base[i]));
J->base[0] = tr;
}
/* Record bit shifts. */
static void LJ_FASTCALL recff_bit_shift(jit_State *J, RecordFFData *rd)
{
TRef tr = lj_opt_narrow_tobit(J, J->base[0]);
TRef tsh = lj_opt_narrow_tobit(J, J->base[1]);
IROp op = (IROp)rd->data;
if (!(op < IR_BROL ? LJ_TARGET_MASKSHIFT : LJ_TARGET_MASKROT) &&
!tref_isk(tsh))
tsh = emitir(IRTI(IR_BAND), tsh, lj_ir_kint(J, 31));
#ifdef LJ_TARGET_UNIFYROT
if (op == (LJ_TARGET_UNIFYROT == 1 ? IR_BROR : IR_BROL)) {
op = LJ_TARGET_UNIFYROT == 1 ? IR_BROL : IR_BROR;
tsh = emitir(IRTI(IR_NEG), tsh, tsh);
}
#endif
J->base[0] = emitir(IRTI(op), tr, tsh);
}
/* -- String library fast functions --------------------------------------- */
static void LJ_FASTCALL recff_string_len(jit_State *J, RecordFFData *rd)
{
J->base[0] = emitir(IRTI(IR_FLOAD), lj_ir_tostr(J, J->base[0]), IRFL_STR_LEN);
UNUSED(rd);
}
/* Handle string.byte (rd->data = 0) and string.sub (rd->data = 1). */
static void LJ_FASTCALL recff_string_range(jit_State *J, RecordFFData *rd)
{
TRef trstr = lj_ir_tostr(J, J->base[0]);
TRef trlen = emitir(IRTI(IR_FLOAD), trstr, IRFL_STR_LEN);
TRef tr0 = lj_ir_kint(J, 0);
TRef trstart, trend;
GCstr *str = argv2str(J, &rd->argv[0]);
int32_t start, end;
if (rd->data) { /* string.sub(str, start [,end]) */
start = argv2int(J, &rd->argv[1]);
trstart = lj_opt_narrow_toint(J, J->base[1]);
trend = J->base[2];
if (tref_isnil(trend)) {
trend = lj_ir_kint(J, -1);
end = -1;
} else {
trend = lj_opt_narrow_toint(J, trend);
end = argv2int(J, &rd->argv[2]);
}
} else { /* string.byte(str, [,start [,end]]) */
if (J->base[1]) {
start = argv2int(J, &rd->argv[1]);
trstart = lj_opt_narrow_toint(J, J->base[1]);
trend = J->base[2];
if (tref_isnil(trend)) {
trend = trstart;
end = start;
} else {
trend = lj_opt_narrow_toint(J, trend);
end = argv2int(J, &rd->argv[2]);
}
} else {
trend = trstart = lj_ir_kint(J, 1);
end = start = 1;
}
}
if (end < 0) {
emitir(IRTGI(IR_LT), trend, tr0);
trend = emitir(IRTI(IR_ADD), emitir(IRTI(IR_ADD), trlen, trend),
lj_ir_kint(J, 1));
end = end+(int32_t)str->len+1;
} else if ((MSize)end <= str->len) {
emitir(IRTGI(IR_ULE), trend, trlen);
} else {
emitir(IRTGI(IR_GT), trend, trlen);
end = (int32_t)str->len;
trend = trlen;
}
if (start < 0) {
emitir(IRTGI(IR_LT), trstart, tr0);
trstart = emitir(IRTI(IR_ADD), trlen, trstart);
start = start+(int32_t)str->len;
emitir(start < 0 ? IRTGI(IR_LT) : IRTGI(IR_GE), trstart, tr0);
if (start < 0) {
trstart = tr0;
start = 0;
}
} else {
if (start == 0) {
emitir(IRTGI(IR_EQ), trstart, tr0);
trstart = tr0;
} else {
trstart = emitir(IRTI(IR_ADD), trstart, lj_ir_kint(J, -1));
emitir(IRTGI(IR_GE), trstart, tr0);
start--;
}
}
if (rd->data) { /* Return string.sub result. */
if (end - start >= 0) {
/* Also handle empty range here, to avoid extra traces. */
TRef trptr, trslen = emitir(IRTI(IR_SUB), trend, trstart);
emitir(IRTGI(IR_GE), trslen, tr0);
trptr = emitir(IRT(IR_STRREF, IRT_P32), trstr, trstart);
J->base[0] = emitir(IRT(IR_SNEW, IRT_STR), trptr, trslen);
} else { /* Range underflow: return empty string. */
emitir(IRTGI(IR_LT), trend, trstart);
J->base[0] = lj_ir_kstr(J, lj_str_new(J->L, strdata(str), 0));
}
} else { /* Return string.byte result(s). */
ptrdiff_t i, len = end - start;
if (len > 0) {
TRef trslen = emitir(IRTI(IR_SUB), trend, trstart);
emitir(IRTGI(IR_EQ), trslen, lj_ir_kint(J, (int32_t)len));
if (J->baseslot + len > LJ_MAX_JSLOTS)
lj_trace_err_info(J, LJ_TRERR_STACKOV);
rd->nres = len;
for (i = 0; i < len; i++) {
TRef tmp = emitir(IRTI(IR_ADD), trstart, lj_ir_kint(J, (int32_t)i));
tmp = emitir(IRT(IR_STRREF, IRT_P32), trstr, tmp);
J->base[i] = emitir(IRT(IR_XLOAD, IRT_U8), tmp, IRXLOAD_READONLY);
}
} else { /* Empty range or range underflow: return no results. */
emitir(IRTGI(IR_LE), trend, trstart);
rd->nres = 0;
}
}
}
/* -- Table library fast functions ---------------------------------------- */
static void LJ_FASTCALL recff_table_getn(jit_State *J, RecordFFData *rd)
{
if (tref_istab(J->base[0]))
J->base[0] = lj_ir_call(J, IRCALL_lj_tab_len, J->base[0]);
/* else: Interpreter will throw. */
UNUSED(rd);
}
static void LJ_FASTCALL recff_table_remove(jit_State *J, RecordFFData *rd)
{
TRef tab = J->base[0];
rd->nres = 0;
if (tref_istab(tab)) {
if (!J->base[1] || tref_isnil(J->base[1])) { /* Simple pop: t[#t] = nil */
TRef trlen = lj_ir_call(J, IRCALL_lj_tab_len, tab);
GCtab *t = tabV(&rd->argv[0]);
MSize len = lj_tab_len(t);
emitir(IRTGI(len ? IR_NE : IR_EQ), trlen, lj_ir_kint(J, 0));
if (len) {
RecordIndex ix;
ix.tab = tab;
ix.key = trlen;
settabV(J->L, &ix.tabv, t);
setintV(&ix.keyv, len);
ix.idxchain = 0;
if (results_wanted(J) != 0) { /* Specialize load only if needed. */
ix.val = 0;
J->base[0] = lj_record_idx(J, &ix); /* Load previous value. */
rd->nres = 1;
/* Assumes ix.key/ix.tab is not modified for raw lj_record_idx(). */
}
ix.val = TREF_NIL;
lj_record_idx(J, &ix); /* Remove value. */
}
} else { /* Complex case: remove in the middle. */
recff_nyiu(J);
}
} /* else: Interpreter will throw. */
}
static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd)
{
RecordIndex ix;
ix.tab = J->base[0];
ix.val = J->base[1];
rd->nres = 0;
if (tref_istab(ix.tab) && ix.val) {
if (!J->base[2]) { /* Simple push: t[#t+1] = v */
TRef trlen = lj_ir_call(J, IRCALL_lj_tab_len, ix.tab);
GCtab *t = tabV(&rd->argv[0]);
ix.key = emitir(IRTI(IR_ADD), trlen, lj_ir_kint(J, 1));
settabV(J->L, &ix.tabv, t);
setintV(&ix.keyv, lj_tab_len(t) + 1);
ix.idxchain = 0;
lj_record_idx(J, &ix); /* Set new value. */
} else { /* Complex case: insert in the middle. */
recff_nyiu(J);
}
} /* else: Interpreter will throw. */
}
/* -- I/O library fast functions ------------------------------------------ */
/* Get FILE* for I/O function. Any I/O error aborts recording, so there's
** no need to encode the alternate cases for any of the guards.
*/
static TRef recff_io_fp(jit_State *J, TRef *udp, int32_t id)
{
TRef tr, ud, fp;
if (id) { /* io.func() */
tr = lj_ir_kptr(J, &J2G(J)->gcroot[id]);
ud = emitir(IRT(IR_XLOAD, IRT_UDATA), tr, 0);
} else { /* fp:method() */
ud = J->base[0];
if (!tref_isudata(ud))
lj_trace_err(J, LJ_TRERR_BADTYPE);
tr = emitir(IRT(IR_FLOAD, IRT_U8), ud, IRFL_UDATA_UDTYPE);
emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, UDTYPE_IO_FILE));
}
*udp = ud;
fp = emitir(IRT(IR_FLOAD, IRT_PTR), ud, IRFL_UDATA_FILE);
emitir(IRTG(IR_NE, IRT_PTR), fp, lj_ir_knull(J, IRT_PTR));
return fp;
}
static void LJ_FASTCALL recff_io_write(jit_State *J, RecordFFData *rd)
{
TRef ud, fp = recff_io_fp(J, &ud, rd->data);
TRef zero = lj_ir_kint(J, 0);
TRef one = lj_ir_kint(J, 1);
ptrdiff_t i = rd->data == 0 ? 1 : 0;
for (; J->base[i]; i++) {
TRef str = lj_ir_tostr(J, J->base[i]);
TRef buf = emitir(IRT(IR_STRREF, IRT_P32), str, zero);
TRef len = emitir(IRTI(IR_FLOAD), str, IRFL_STR_LEN);
if (tref_isk(len) && IR(tref_ref(len))->i == 1) {
TRef tr = emitir(IRT(IR_XLOAD, IRT_U8), buf, IRXLOAD_READONLY);
tr = lj_ir_call(J, IRCALL_fputc, tr, fp);
if (results_wanted(J) != 0) /* Check result only if not ignored. */
emitir(IRTGI(IR_NE), tr, lj_ir_kint(J, -1));
} else {
TRef tr = lj_ir_call(J, IRCALL_fwrite, buf, one, len, fp);
if (results_wanted(J) != 0) /* Check result only if not ignored. */
emitir(IRTGI(IR_EQ), tr, len);
}
}
J->base[0] = LJ_52 ? ud : TREF_TRUE;
}
static void LJ_FASTCALL recff_io_flush(jit_State *J, RecordFFData *rd)
{
TRef ud, fp = recff_io_fp(J, &ud, rd->data);
TRef tr = lj_ir_call(J, IRCALL_fflush, fp);
if (results_wanted(J) != 0) /* Check result only if not ignored. */
emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, 0));
J->base[0] = TREF_TRUE;
}
/* -- Record calls to fast functions -------------------------------------- */
#include "lj_recdef.h"
static uint32_t recdef_lookup(GCfunc *fn)
{
if (fn->c.ffid < sizeof(recff_idmap)/sizeof(recff_idmap[0]))
return recff_idmap[fn->c.ffid];
else
return 0;
}
/* Record entry to a fast function or C function. */
void lj_ffrecord_func(jit_State *J)
{
RecordFFData rd;
uint32_t m = recdef_lookup(J->fn);
rd.data = m & 0xff;
rd.nres = 1; /* Default is one result. */
rd.argv = J->L->base;
J->base[J->maxslot] = 0; /* Mark end of arguments. */
(recff_func[m >> 8])(J, &rd); /* Call recff_* handler. */
if (rd.nres >= 0) {
if (J->postproc == LJ_POST_NONE) J->postproc = LJ_POST_FFRETRY;
lj_record_ret(J, 0, rd.nres);
}
}
#undef IR
#undef emitir
#endif
-183
View File
@@ -1,183 +0,0 @@
/*
** Stack frames.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_FRAME_H
#define _LJ_FRAME_H
#include "lj_obj.h"
#include "lj_bc.h"
/* -- Lua stack frame ----------------------------------------------------- */
/* Frame type markers in callee function slot (callee base-1). */
enum {
FRAME_LUA, FRAME_C, FRAME_CONT, FRAME_VARG,
FRAME_LUAP, FRAME_CP, FRAME_PCALL, FRAME_PCALLH
};
#define FRAME_TYPE 3
#define FRAME_P 4
#define FRAME_TYPEP (FRAME_TYPE|FRAME_P)
/* Macros to access and modify Lua frames. */
#define frame_gc(f) (gcref((f)->fr.func))
#define frame_func(f) (&frame_gc(f)->fn)
#define frame_ftsz(f) ((f)->fr.tp.ftsz)
#define frame_type(f) (frame_ftsz(f) & FRAME_TYPE)
#define frame_typep(f) (frame_ftsz(f) & FRAME_TYPEP)
#define frame_islua(f) (frame_type(f) == FRAME_LUA)
#define frame_isc(f) (frame_type(f) == FRAME_C)
#define frame_iscont(f) (frame_typep(f) == FRAME_CONT)
#define frame_isvarg(f) (frame_typep(f) == FRAME_VARG)
#define frame_ispcall(f) ((frame_ftsz(f) & 6) == FRAME_PCALL)
#define frame_pc(f) (mref((f)->fr.tp.pcr, const BCIns))
#define frame_contpc(f) (frame_pc((f)-1))
#if LJ_64
#define frame_contf(f) \
((ASMFunction)(void *)((intptr_t)lj_vm_asm_begin + \
(intptr_t)(int32_t)((f)-1)->u32.lo))
#else
#define frame_contf(f) ((ASMFunction)gcrefp(((f)-1)->gcr, void))
#endif
#define frame_delta(f) (frame_ftsz(f) >> 3)
#define frame_sized(f) (frame_ftsz(f) & ~FRAME_TYPEP)
#define frame_prevl(f) ((f) - (1+bc_a(frame_pc(f)[-1])))
#define frame_prevd(f) ((TValue *)((char *)(f) - frame_sized(f)))
#define frame_prev(f) (frame_islua(f)?frame_prevl(f):frame_prevd(f))
/* Note: this macro does not skip over FRAME_VARG. */
#define setframe_pc(f, pc) (setmref((f)->fr.tp.pcr, (pc)))
#define setframe_ftsz(f, sz) ((f)->fr.tp.ftsz = (sz))
#define setframe_gc(f, p) (setgcref((f)->fr.func, (p)))
/* -- C stack frame ------------------------------------------------------- */
/* Macros to access and modify the C stack frame chain. */
/* These definitions must match with the arch-specific *.dasc files. */
#if LJ_TARGET_X86
#define CFRAME_OFS_ERRF (15*4)
#define CFRAME_OFS_NRES (14*4)
#define CFRAME_OFS_PREV (13*4)
#define CFRAME_OFS_L (12*4)
#define CFRAME_OFS_PC (6*4)
#define CFRAME_OFS_MULTRES (5*4)
#define CFRAME_SIZE (12*4)
#define CFRAME_SHIFT_MULTRES 0
#elif LJ_TARGET_X64
#if LJ_ABI_WIN
#define CFRAME_OFS_PREV (13*8)
#define CFRAME_OFS_PC (25*4)
#define CFRAME_OFS_L (24*4)
#define CFRAME_OFS_ERRF (23*4)
#define CFRAME_OFS_NRES (22*4)
#define CFRAME_OFS_MULTRES (21*4)
#define CFRAME_SIZE (10*8)
#define CFRAME_SIZE_JIT (CFRAME_SIZE + 9*16 + 4*8)
#define CFRAME_SHIFT_MULTRES 0
#else
#define CFRAME_OFS_PREV (4*8)
#define CFRAME_OFS_PC (7*4)
#define CFRAME_OFS_L (6*4)
#define CFRAME_OFS_ERRF (5*4)
#define CFRAME_OFS_NRES (4*4)
#define CFRAME_OFS_MULTRES (1*4)
#define CFRAME_SIZE (10*8)
#define CFRAME_SIZE_JIT (CFRAME_SIZE + 16)
#define CFRAME_SHIFT_MULTRES 0
#endif
#elif LJ_TARGET_ARM
#define CFRAME_OFS_ERRF 24
#define CFRAME_OFS_NRES 20
#define CFRAME_OFS_PREV 16
#define CFRAME_OFS_L 12
#define CFRAME_OFS_PC 8
#define CFRAME_OFS_MULTRES 4
#if LJ_ARCH_HASFPU
#define CFRAME_SIZE 128
#else
#define CFRAME_SIZE 64
#endif
#define CFRAME_SHIFT_MULTRES 3
#elif LJ_TARGET_PPC
#if LJ_TARGET_XBOX360
#define CFRAME_OFS_ERRF 424
#define CFRAME_OFS_NRES 420
#define CFRAME_OFS_PREV 400
#define CFRAME_OFS_L 416
#define CFRAME_OFS_PC 412
#define CFRAME_OFS_MULTRES 408
#define CFRAME_SIZE 384
#define CFRAME_SHIFT_MULTRES 3
#elif LJ_ARCH_PPC64
#define CFRAME_OFS_ERRF 472
#define CFRAME_OFS_NRES 468
#define CFRAME_OFS_PREV 448
#define CFRAME_OFS_L 464
#define CFRAME_OFS_PC 460
#define CFRAME_OFS_MULTRES 456
#define CFRAME_SIZE 400
#define CFRAME_SHIFT_MULTRES 3
#else
#define CFRAME_OFS_ERRF 48
#define CFRAME_OFS_NRES 44
#define CFRAME_OFS_PREV 40
#define CFRAME_OFS_L 36
#define CFRAME_OFS_PC 32
#define CFRAME_OFS_MULTRES 28
#define CFRAME_SIZE 272
#define CFRAME_SHIFT_MULTRES 3
#endif
#elif LJ_TARGET_PPCSPE
#define CFRAME_OFS_ERRF 28
#define CFRAME_OFS_NRES 24
#define CFRAME_OFS_PREV 20
#define CFRAME_OFS_L 16
#define CFRAME_OFS_PC 12
#define CFRAME_OFS_MULTRES 8
#define CFRAME_SIZE 184
#define CFRAME_SHIFT_MULTRES 3
#elif LJ_TARGET_MIPS
#define CFRAME_OFS_ERRF 124
#define CFRAME_OFS_NRES 120
#define CFRAME_OFS_PREV 116
#define CFRAME_OFS_L 112
#define CFRAME_OFS_PC 20
#define CFRAME_OFS_MULTRES 16
#define CFRAME_SIZE 112
#define CFRAME_SHIFT_MULTRES 3
#else
#error "Missing CFRAME_* definitions for this architecture"
#endif
#ifndef CFRAME_SIZE_JIT
#define CFRAME_SIZE_JIT CFRAME_SIZE
#endif
#define CFRAME_RESUME 1
#define CFRAME_UNWIND_FF 2 /* Only used in unwinder. */
#define CFRAME_RAWMASK (~(intptr_t)(CFRAME_RESUME|CFRAME_UNWIND_FF))
#define cframe_errfunc(cf) (*(int32_t *)(((char *)(cf))+CFRAME_OFS_ERRF))
#define cframe_nres(cf) (*(int32_t *)(((char *)(cf))+CFRAME_OFS_NRES))
#define cframe_prev(cf) (*(void **)(((char *)(cf))+CFRAME_OFS_PREV))
#define cframe_multres(cf) (*(uint32_t *)(((char *)(cf))+CFRAME_OFS_MULTRES))
#define cframe_multres_n(cf) (cframe_multres((cf)) >> CFRAME_SHIFT_MULTRES)
#define cframe_L(cf) \
(&gcref(*(GCRef *)(((char *)(cf))+CFRAME_OFS_L))->th)
#define cframe_pc(cf) \
(mref(*(MRef *)(((char *)(cf))+CFRAME_OFS_PC), const BCIns))
#define setcframe_L(cf, L) \
(setmref(*(MRef *)(((char *)(cf))+CFRAME_OFS_L), (L)))
#define setcframe_pc(cf, pc) \
(setmref(*(MRef *)(((char *)(cf))+CFRAME_OFS_PC), (pc)))
#define cframe_canyield(cf) ((intptr_t)(cf) & CFRAME_RESUME)
#define cframe_unwind_ff(cf) ((intptr_t)(cf) & CFRAME_UNWIND_FF)
#define cframe_raw(cf) ((void *)((intptr_t)(cf) & CFRAME_RAWMASK))
#define cframe_Lpc(L) cframe_pc(cframe_raw(L->cframe))
#endif
-271
View File
@@ -1,271 +0,0 @@
/*
** IR CALL* instruction definitions.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_IRCALL_H
#define _LJ_IRCALL_H
#include "lj_obj.h"
#include "lj_ir.h"
#include "lj_jit.h"
/* C call info for CALL* instructions. */
typedef struct CCallInfo {
ASMFunction func; /* Function pointer. */
uint32_t flags; /* Number of arguments and flags. */
} CCallInfo;
#define CCI_NARGS(ci) ((ci)->flags & 0xff) /* Extract # of args. */
#define CCI_NARGS_MAX 32 /* Max. # of args. */
#define CCI_OTSHIFT 16
#define CCI_OPTYPE(ci) ((ci)->flags >> CCI_OTSHIFT) /* Get op/type. */
#define CCI_OPSHIFT 24
#define CCI_OP(ci) ((ci)->flags >> CCI_OPSHIFT) /* Get op. */
#define CCI_CALL_N (IR_CALLN << CCI_OPSHIFT)
#define CCI_CALL_L (IR_CALLL << CCI_OPSHIFT)
#define CCI_CALL_S (IR_CALLS << CCI_OPSHIFT)
#define CCI_CALL_FN (CCI_CALL_N|CCI_CC_FASTCALL)
#define CCI_CALL_FL (CCI_CALL_L|CCI_CC_FASTCALL)
#define CCI_CALL_FS (CCI_CALL_S|CCI_CC_FASTCALL)
/* C call info flags. */
#define CCI_L 0x0100 /* Implicit L arg. */
#define CCI_CASTU64 0x0200 /* Cast u64 result to number. */
#define CCI_NOFPRCLOBBER 0x0400 /* Does not clobber any FPRs. */
#define CCI_VARARG 0x0800 /* Vararg function. */
#define CCI_CC_MASK 0x3000 /* Calling convention mask. */
#define CCI_CC_SHIFT 12
/* ORDER CC */
#define CCI_CC_CDECL 0x0000 /* Default cdecl calling convention. */
#define CCI_CC_THISCALL 0x1000 /* Thiscall calling convention. */
#define CCI_CC_FASTCALL 0x2000 /* Fastcall calling convention. */
#define CCI_CC_STDCALL 0x3000 /* Stdcall calling convention. */
/* Helpers for conditional function definitions. */
#define IRCALLCOND_ANY(x) x
#if LJ_TARGET_X86ORX64
#define IRCALLCOND_FPMATH(x) NULL
#else
#define IRCALLCOND_FPMATH(x) x
#endif
#if LJ_SOFTFP
#define IRCALLCOND_SOFTFP(x) x
#if LJ_HASFFI
#define IRCALLCOND_SOFTFP_FFI(x) x
#else
#define IRCALLCOND_SOFTFP_FFI(x) NULL
#endif
#else
#define IRCALLCOND_SOFTFP(x) NULL
#define IRCALLCOND_SOFTFP_FFI(x) NULL
#endif
#define LJ_NEED_FP64 (LJ_TARGET_ARM || LJ_TARGET_PPC || LJ_TARGET_MIPS)
#if LJ_HASFFI && (LJ_SOFTFP || LJ_NEED_FP64)
#define IRCALLCOND_FP64_FFI(x) x
#else
#define IRCALLCOND_FP64_FFI(x) NULL
#endif
#if LJ_HASFFI
#define IRCALLCOND_FFI(x) x
#if LJ_32
#define IRCALLCOND_FFI32(x) x
#else
#define IRCALLCOND_FFI32(x) NULL
#endif
#else
#define IRCALLCOND_FFI(x) NULL
#define IRCALLCOND_FFI32(x) NULL
#endif
#if LJ_SOFTFP
#define ARG1_FP 2 /* Treat as 2 32 bit arguments. */
#else
#define ARG1_FP 1
#endif
#if LJ_32
#define ARG2_64 4 /* Treat as 4 32 bit arguments. */
#else
#define ARG2_64 2
#endif
/* Function definitions for CALL* instructions. */
#define IRCALLDEF(_) \
_(ANY, lj_str_cmp, 2, FN, INT, CCI_NOFPRCLOBBER) \
_(ANY, lj_str_new, 3, S, STR, CCI_L) \
_(ANY, lj_strscan_num, 2, FN, INT, 0) \
_(ANY, lj_str_fromint, 2, FN, STR, CCI_L) \
_(ANY, lj_str_fromnum, 2, FN, STR, CCI_L) \
_(ANY, lj_tab_new1, 2, FS, TAB, CCI_L) \
_(ANY, lj_tab_dup, 2, FS, TAB, CCI_L) \
_(ANY, lj_tab_newkey, 3, S, P32, CCI_L) \
_(ANY, lj_tab_len, 1, FL, INT, 0) \
_(ANY, lj_gc_step_jit, 2, FS, NIL, CCI_L) \
_(ANY, lj_gc_barrieruv, 2, FS, NIL, 0) \
_(ANY, lj_mem_newgco, 2, FS, P32, CCI_L) \
_(ANY, lj_math_random_step, 1, FS, NUM, CCI_CASTU64|CCI_NOFPRCLOBBER) \
_(ANY, lj_vm_modi, 2, FN, INT, 0) \
_(ANY, sinh, ARG1_FP, N, NUM, 0) \
_(ANY, cosh, ARG1_FP, N, NUM, 0) \
_(ANY, tanh, ARG1_FP, N, NUM, 0) \
_(ANY, fputc, 2, S, INT, 0) \
_(ANY, fwrite, 4, S, INT, 0) \
_(ANY, fflush, 1, S, INT, 0) \
/* ORDER FPM */ \
_(FPMATH, lj_vm_floor, ARG1_FP, N, NUM, 0) \
_(FPMATH, lj_vm_ceil, ARG1_FP, N, NUM, 0) \
_(FPMATH, lj_vm_trunc, ARG1_FP, N, NUM, 0) \
_(FPMATH, sqrt, ARG1_FP, N, NUM, 0) \
_(FPMATH, exp, ARG1_FP, N, NUM, 0) \
_(FPMATH, lj_vm_exp2, ARG1_FP, N, NUM, 0) \
_(FPMATH, log, ARG1_FP, N, NUM, 0) \
_(FPMATH, lj_vm_log2, ARG1_FP, N, NUM, 0) \
_(FPMATH, log10, ARG1_FP, N, NUM, 0) \
_(FPMATH, sin, ARG1_FP, N, NUM, 0) \
_(FPMATH, cos, ARG1_FP, N, NUM, 0) \
_(FPMATH, tan, ARG1_FP, N, NUM, 0) \
_(FPMATH, lj_vm_powi, ARG1_FP+1, N, NUM, 0) \
_(FPMATH, pow, ARG1_FP*2, N, NUM, 0) \
_(FPMATH, atan2, ARG1_FP*2, N, NUM, 0) \
_(FPMATH, ldexp, ARG1_FP+1, N, NUM, 0) \
_(SOFTFP, lj_vm_tobit, 2, N, INT, 0) \
_(SOFTFP, softfp_add, 4, N, NUM, 0) \
_(SOFTFP, softfp_sub, 4, N, NUM, 0) \
_(SOFTFP, softfp_mul, 4, N, NUM, 0) \
_(SOFTFP, softfp_div, 4, N, NUM, 0) \
_(SOFTFP, softfp_cmp, 4, N, NIL, 0) \
_(SOFTFP, softfp_i2d, 1, N, NUM, 0) \
_(SOFTFP, softfp_d2i, 2, N, INT, 0) \
_(SOFTFP_FFI, softfp_ui2d, 1, N, NUM, 0) \
_(SOFTFP_FFI, softfp_f2d, 1, N, NUM, 0) \
_(SOFTFP_FFI, softfp_d2ui, 2, N, INT, 0) \
_(SOFTFP_FFI, softfp_d2f, 2, N, FLOAT, 0) \
_(SOFTFP_FFI, softfp_i2f, 1, N, FLOAT, 0) \
_(SOFTFP_FFI, softfp_ui2f, 1, N, FLOAT, 0) \
_(SOFTFP_FFI, softfp_f2i, 1, N, INT, 0) \
_(SOFTFP_FFI, softfp_f2ui, 1, N, INT, 0) \
_(FP64_FFI, fp64_l2d, 2, N, NUM, 0) \
_(FP64_FFI, fp64_ul2d, 2, N, NUM, 0) \
_(FP64_FFI, fp64_l2f, 2, N, FLOAT, 0) \
_(FP64_FFI, fp64_ul2f, 2, N, FLOAT, 0) \
_(FP64_FFI, fp64_d2l, ARG1_FP, N, I64, 0) \
_(FP64_FFI, fp64_d2ul, ARG1_FP, N, U64, 0) \
_(FP64_FFI, fp64_f2l, 1, N, I64, 0) \
_(FP64_FFI, fp64_f2ul, 1, N, U64, 0) \
_(FFI, lj_carith_divi64, ARG2_64, N, I64, CCI_NOFPRCLOBBER) \
_(FFI, lj_carith_divu64, ARG2_64, N, U64, CCI_NOFPRCLOBBER) \
_(FFI, lj_carith_modi64, ARG2_64, N, I64, CCI_NOFPRCLOBBER) \
_(FFI, lj_carith_modu64, ARG2_64, N, U64, CCI_NOFPRCLOBBER) \
_(FFI, lj_carith_powi64, ARG2_64, N, I64, CCI_NOFPRCLOBBER) \
_(FFI, lj_carith_powu64, ARG2_64, N, U64, CCI_NOFPRCLOBBER) \
_(FFI, lj_cdata_setfin, 2, FN, P32, CCI_L) \
_(FFI, strlen, 1, L, INTP, 0) \
_(FFI, memcpy, 3, S, PTR, 0) \
_(FFI, memset, 3, S, PTR, 0) \
_(FFI, lj_vm_errno, 0, S, INT, CCI_NOFPRCLOBBER) \
_(FFI32, lj_carith_mul64, ARG2_64, N, I64, CCI_NOFPRCLOBBER)
\
/* End of list. */
typedef enum {
#define IRCALLENUM(cond, name, nargs, kind, type, flags) IRCALL_##name,
IRCALLDEF(IRCALLENUM)
#undef IRCALLENUM
IRCALL__MAX
} IRCallID;
LJ_FUNC TRef lj_ir_call(jit_State *J, IRCallID id, ...);
LJ_DATA const CCallInfo lj_ir_callinfo[IRCALL__MAX+1];
/* Soft-float declarations. */
#if LJ_SOFTFP
#if LJ_TARGET_ARM
#define softfp_add __aeabi_dadd
#define softfp_sub __aeabi_dsub
#define softfp_mul __aeabi_dmul
#define softfp_div __aeabi_ddiv
#define softfp_cmp __aeabi_cdcmple
#define softfp_i2d __aeabi_i2d
#define softfp_d2i __aeabi_d2iz
#define softfp_ui2d __aeabi_ui2d
#define softfp_f2d __aeabi_f2d
#define softfp_d2ui __aeabi_d2uiz
#define softfp_d2f __aeabi_d2f
#define softfp_i2f __aeabi_i2f
#define softfp_ui2f __aeabi_ui2f
#define softfp_f2i __aeabi_f2iz
#define softfp_f2ui __aeabi_f2uiz
#define fp64_l2d __aeabi_l2d
#define fp64_ul2d __aeabi_ul2d
#define fp64_l2f __aeabi_l2f
#define fp64_ul2f __aeabi_ul2f
#if LJ_TARGET_IOS
#define fp64_d2l __fixdfdi
#define fp64_d2ul __fixunsdfdi
#define fp64_f2l __fixsfdi
#define fp64_f2ul __fixunssfdi
#else
#define fp64_d2l __aeabi_d2lz
#define fp64_d2ul __aeabi_d2ulz
#define fp64_f2l __aeabi_f2lz
#define fp64_f2ul __aeabi_f2ulz
#endif
#else
#error "Missing soft-float definitions for target architecture"
#endif
extern double softfp_add(double a, double b);
extern double softfp_sub(double a, double b);
extern double softfp_mul(double a, double b);
extern double softfp_div(double a, double b);
extern void softfp_cmp(double a, double b);
extern double softfp_i2d(int32_t a);
extern int32_t softfp_d2i(double a);
#if LJ_HASFFI
extern double softfp_ui2d(uint32_t a);
extern double softfp_f2d(float a);
extern uint32_t softfp_d2ui(double a);
extern float softfp_d2f(double a);
extern float softfp_i2f(int32_t a);
extern float softfp_ui2f(uint32_t a);
extern int32_t softfp_f2i(float a);
extern uint32_t softfp_f2ui(float a);
#endif
#endif
#if LJ_HASFFI && LJ_NEED_FP64 && !(LJ_TARGET_ARM && LJ_SOFTFP)
#ifdef __GNUC__
#define fp64_l2d __floatdidf
#define fp64_ul2d __floatundidf
#define fp64_l2f __floatdisf
#define fp64_ul2f __floatundisf
#define fp64_d2l __fixdfdi
#define fp64_d2ul __fixunsdfdi
#define fp64_f2l __fixsfdi
#define fp64_f2ul __fixunssfdi
#else
#error "Missing fp64 helper definitions for this compiler"
#endif
#endif
#if LJ_HASFFI && (LJ_SOFTFP || LJ_NEED_FP64)
extern double fp64_l2d(int64_t a);
extern double fp64_ul2d(uint64_t a);
extern float fp64_l2f(int64_t a);
extern float fp64_ul2f(uint64_t a);
extern int64_t fp64_d2l(double a);
extern uint64_t fp64_d2ul(double a);
extern int64_t fp64_f2l(float a);
extern uint64_t fp64_f2ul(float a);
#endif
#endif
-416
View File
@@ -1,416 +0,0 @@
/*
** Common definitions for the JIT compiler.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_JIT_H
#define _LJ_JIT_H
#include "lj_obj.h"
#include "lj_ir.h"
/* JIT engine flags. */
#define JIT_F_ON 0x00000001
/* CPU-specific JIT engine flags. */
#if LJ_TARGET_X86ORX64
#define JIT_F_CMOV 0x00000010
#define JIT_F_SSE2 0x00000020
#define JIT_F_SSE3 0x00000040
#define JIT_F_SSE4_1 0x00000080
#define JIT_F_P4 0x00000100
#define JIT_F_PREFER_IMUL 0x00000200
#define JIT_F_SPLIT_XMM 0x00000400
#define JIT_F_LEA_AGU 0x00000800
/* Names for the CPU-specific flags. Must match the order above. */
#define JIT_F_CPU_FIRST JIT_F_CMOV
#define JIT_F_CPUSTRING "\4CMOV\4SSE2\4SSE3\6SSE4.1\2P4\3AMD\2K8\4ATOM"
#elif LJ_TARGET_ARM
#define JIT_F_ARMV6_ 0x00000010
#define JIT_F_ARMV6T2_ 0x00000020
#define JIT_F_ARMV7 0x00000040
#define JIT_F_VFPV2 0x00000080
#define JIT_F_VFPV3 0x00000100
#define JIT_F_ARMV6 (JIT_F_ARMV6_|JIT_F_ARMV6T2_|JIT_F_ARMV7)
#define JIT_F_ARMV6T2 (JIT_F_ARMV6T2_|JIT_F_ARMV7)
#define JIT_F_VFP (JIT_F_VFPV2|JIT_F_VFPV3)
/* Names for the CPU-specific flags. Must match the order above. */
#define JIT_F_CPU_FIRST JIT_F_ARMV6_
#define JIT_F_CPUSTRING "\5ARMv6\7ARMv6T2\5ARMv7\5VFPv2\5VFPv3"
#elif LJ_TARGET_PPC
#define JIT_F_SQRT 0x00000010
#define JIT_F_ROUND 0x00000020
/* Names for the CPU-specific flags. Must match the order above. */
#define JIT_F_CPU_FIRST JIT_F_SQRT
#define JIT_F_CPUSTRING "\4SQRT\5ROUND"
#elif LJ_TARGET_MIPS
#define JIT_F_MIPS32R2 0x00000010
/* Names for the CPU-specific flags. Must match the order above. */
#define JIT_F_CPU_FIRST JIT_F_MIPS32R2
#define JIT_F_CPUSTRING "\010MIPS32R2"
#else
#define JIT_F_CPU_FIRST 0
#define JIT_F_CPUSTRING ""
#endif
/* Optimization flags. */
#define JIT_F_OPT_MASK 0x0fff0000
#define JIT_F_OPT_FOLD 0x00010000
#define JIT_F_OPT_CSE 0x00020000
#define JIT_F_OPT_DCE 0x00040000
#define JIT_F_OPT_FWD 0x00080000
#define JIT_F_OPT_DSE 0x00100000
#define JIT_F_OPT_NARROW 0x00200000
#define JIT_F_OPT_LOOP 0x00400000
#define JIT_F_OPT_ABC 0x00800000
#define JIT_F_OPT_SINK 0x01000000
#define JIT_F_OPT_FUSE 0x02000000
/* Optimizations names for -O. Must match the order above. */
#define JIT_F_OPT_FIRST JIT_F_OPT_FOLD
#define JIT_F_OPTSTRING \
"\4fold\3cse\3dce\3fwd\3dse\6narrow\4loop\3abc\4sink\4fuse"
/* Optimization levels set a fixed combination of flags. */
#define JIT_F_OPT_0 0
#define JIT_F_OPT_1 (JIT_F_OPT_FOLD|JIT_F_OPT_CSE|JIT_F_OPT_DCE)
#define JIT_F_OPT_2 (JIT_F_OPT_1|JIT_F_OPT_NARROW|JIT_F_OPT_LOOP)
#define JIT_F_OPT_3 (JIT_F_OPT_2|\
JIT_F_OPT_FWD|JIT_F_OPT_DSE|JIT_F_OPT_ABC|JIT_F_OPT_SINK|JIT_F_OPT_FUSE)
#define JIT_F_OPT_DEFAULT JIT_F_OPT_3
#if LJ_TARGET_WINDOWS || LJ_64
/* See: http://blogs.msdn.com/oldnewthing/archive/2003/10/08/55239.aspx */
#define JIT_P_sizemcode_DEFAULT 64
#else
/* Could go as low as 4K, but the mmap() overhead would be rather high. */
#define JIT_P_sizemcode_DEFAULT 32
#endif
/* Optimization parameters and their defaults. Length is a char in octal! */
#define JIT_PARAMDEF(_) \
_(\010, maxtrace, 1000) /* Max. # of traces in cache. */ \
_(\011, maxrecord, 4000) /* Max. # of recorded IR instructions. */ \
_(\012, maxirconst, 500) /* Max. # of IR constants of a trace. */ \
_(\007, maxside, 100) /* Max. # of side traces of a root trace. */ \
_(\007, maxsnap, 500) /* Max. # of snapshots for a trace. */ \
\
_(\007, hotloop, 56) /* # of iter. to detect a hot loop/call. */ \
_(\007, hotexit, 10) /* # of taken exits to start a side trace. */ \
_(\007, tryside, 4) /* # of attempts to compile a side trace. */ \
\
_(\012, instunroll, 4) /* Max. unroll for instable loops. */ \
_(\012, loopunroll, 15) /* Max. unroll for loop ops in side traces. */ \
_(\012, callunroll, 3) /* Max. unroll for recursive calls. */ \
_(\011, recunroll, 2) /* Min. unroll for true recursion. */ \
\
/* Size of each machine code area (in KBytes). */ \
_(\011, sizemcode, JIT_P_sizemcode_DEFAULT) \
/* Max. total size of all machine code areas (in KBytes). */ \
_(\010, maxmcode, 512) \
/* End of list. */
enum {
#define JIT_PARAMENUM(len, name, value) JIT_P_##name,
JIT_PARAMDEF(JIT_PARAMENUM)
#undef JIT_PARAMENUM
JIT_P__MAX
};
#define JIT_PARAMSTR(len, name, value) #len #name
#define JIT_P_STRING JIT_PARAMDEF(JIT_PARAMSTR)
/* Trace compiler state. */
typedef enum {
LJ_TRACE_IDLE, /* Trace compiler idle. */
LJ_TRACE_ACTIVE = 0x10,
LJ_TRACE_RECORD, /* Bytecode recording active. */
LJ_TRACE_START, /* New trace started. */
LJ_TRACE_END, /* End of trace. */
LJ_TRACE_ASM, /* Assemble trace. */
LJ_TRACE_ERR /* Trace aborted with error. */
} TraceState;
/* Post-processing action. */
typedef enum {
LJ_POST_NONE, /* No action. */
LJ_POST_FIXCOMP, /* Fixup comparison and emit pending guard. */
LJ_POST_FIXGUARD, /* Fixup and emit pending guard. */
LJ_POST_FIXGUARDSNAP, /* Fixup and emit pending guard and snapshot. */
LJ_POST_FIXBOOL, /* Fixup boolean result. */
LJ_POST_FIXCONST, /* Fixup constant results. */
LJ_POST_FFRETRY /* Suppress recording of retried fast functions. */
} PostProc;
/* Machine code type. */
#if LJ_TARGET_X86ORX64
typedef uint8_t MCode;
#else
typedef uint32_t MCode;
#endif
/* Stack snapshot header. */
typedef struct SnapShot {
uint16_t mapofs; /* Offset into snapshot map. */
IRRef1 ref; /* First IR ref for this snapshot. */
uint8_t nslots; /* Number of valid slots. */
uint8_t topslot; /* Maximum frame extent. */
uint8_t nent; /* Number of compressed entries. */
uint8_t count; /* Count of taken exits for this snapshot. */
} SnapShot;
#define SNAPCOUNT_DONE 255 /* Already compiled and linked a side trace. */
/* Compressed snapshot entry. */
typedef uint32_t SnapEntry;
#define SNAP_FRAME 0x010000 /* Frame slot. */
#define SNAP_CONT 0x020000 /* Continuation slot. */
#define SNAP_NORESTORE 0x040000 /* No need to restore slot. */
#define SNAP_SOFTFPNUM 0x080000 /* Soft-float number. */
LJ_STATIC_ASSERT(SNAP_FRAME == TREF_FRAME);
LJ_STATIC_ASSERT(SNAP_CONT == TREF_CONT);
#define SNAP(slot, flags, ref) (((SnapEntry)(slot) << 24) + (flags) + (ref))
#define SNAP_TR(slot, tr) \
(((SnapEntry)(slot) << 24) + ((tr) & (TREF_CONT|TREF_FRAME|TREF_REFMASK)))
#define SNAP_MKPC(pc) ((SnapEntry)u32ptr(pc))
#define SNAP_MKFTSZ(ftsz) ((SnapEntry)(ftsz))
#define snap_ref(sn) ((sn) & 0xffff)
#define snap_slot(sn) ((BCReg)((sn) >> 24))
#define snap_isframe(sn) ((sn) & SNAP_FRAME)
#define snap_pc(sn) ((const BCIns *)(uintptr_t)(sn))
#define snap_setref(sn, ref) (((sn) & (0xffff0000&~SNAP_NORESTORE)) | (ref))
/* Snapshot and exit numbers. */
typedef uint32_t SnapNo;
typedef uint32_t ExitNo;
/* Trace number. */
typedef uint32_t TraceNo; /* Used to pass around trace numbers. */
typedef uint16_t TraceNo1; /* Stored trace number. */
/* Type of link. ORDER LJ_TRLINK */
typedef enum {
LJ_TRLINK_NONE, /* Incomplete trace. No link, yet. */
LJ_TRLINK_ROOT, /* Link to other root trace. */
LJ_TRLINK_LOOP, /* Loop to same trace. */
LJ_TRLINK_TAILREC, /* Tail-recursion. */
LJ_TRLINK_UPREC, /* Up-recursion. */
LJ_TRLINK_DOWNREC, /* Down-recursion. */
LJ_TRLINK_INTERP, /* Fallback to interpreter. */
LJ_TRLINK_RETURN /* Return to interpreter. */
} TraceLink;
/* Trace object. */
typedef struct GCtrace {
GCHeader;
uint8_t topslot; /* Top stack slot already checked to be allocated. */
uint8_t linktype; /* Type of link. */
IRRef nins; /* Next IR instruction. Biased with REF_BIAS. */
GCRef gclist;
IRIns *ir; /* IR instructions/constants. Biased with REF_BIAS. */
IRRef nk; /* Lowest IR constant. Biased with REF_BIAS. */
uint16_t nsnap; /* Number of snapshots. */
uint16_t nsnapmap; /* Number of snapshot map elements. */
SnapShot *snap; /* Snapshot array. */
SnapEntry *snapmap; /* Snapshot map. */
GCRef startpt; /* Starting prototype. */
MRef startpc; /* Bytecode PC of starting instruction. */
BCIns startins; /* Original bytecode of starting instruction. */
MSize szmcode; /* Size of machine code. */
MCode *mcode; /* Start of machine code. */
MSize mcloop; /* Offset of loop start in machine code. */
uint16_t nchild; /* Number of child traces (root trace only). */
uint16_t spadjust; /* Stack pointer adjustment (offset in bytes). */
TraceNo1 traceno; /* Trace number. */
TraceNo1 link; /* Linked trace (or self for loops). */
TraceNo1 root; /* Root trace of side trace (or 0 for root traces). */
TraceNo1 nextroot; /* Next root trace for same prototype. */
TraceNo1 nextside; /* Next side trace of same root trace. */
uint8_t sinktags; /* Trace has SINK tags. */
uint8_t unused1;
#ifdef LUAJIT_USE_GDBJIT
void *gdbjit_entry; /* GDB JIT entry. */
#endif
} GCtrace;
#define gco2trace(o) check_exp((o)->gch.gct == ~LJ_TTRACE, (GCtrace *)(o))
#define traceref(J, n) \
check_exp((n)>0 && (MSize)(n)<J->sizetrace, (GCtrace *)gcref(J->trace[(n)]))
LJ_STATIC_ASSERT(offsetof(GChead, gclist) == offsetof(GCtrace, gclist));
static LJ_AINLINE MSize snap_nextofs(GCtrace *T, SnapShot *snap)
{
if (snap+1 == &T->snap[T->nsnap])
return T->nsnapmap;
else
return (snap+1)->mapofs;
}
/* Round-robin penalty cache for bytecodes leading to aborted traces. */
typedef struct HotPenalty {
MRef pc; /* Starting bytecode PC. */
uint16_t val; /* Penalty value, i.e. hotcount start. */
uint16_t reason; /* Abort reason (really TraceErr). */
} HotPenalty;
#define PENALTY_SLOTS 64 /* Penalty cache slot. Must be a power of 2. */
#define PENALTY_MIN (36*2) /* Minimum penalty value. */
#define PENALTY_MAX 60000 /* Maximum penalty value. */
#define PENALTY_RNDBITS 4 /* # of random bits to add to penalty value. */
/* Round-robin backpropagation cache for narrowing conversions. */
typedef struct BPropEntry {
IRRef1 key; /* Key: original reference. */
IRRef1 val; /* Value: reference after conversion. */
IRRef mode; /* Mode for this entry (currently IRCONV_*). */
} BPropEntry;
/* Number of slots for the backpropagation cache. Must be a power of 2. */
#define BPROP_SLOTS 16
/* Scalar evolution analysis cache. */
typedef struct ScEvEntry {
IRRef1 idx; /* Index reference. */
IRRef1 start; /* Constant start reference. */
IRRef1 stop; /* Constant stop reference. */
IRRef1 step; /* Constant step reference. */
IRType1 t; /* Scalar type. */
uint8_t dir; /* Direction. 1: +, 0: -. */
} ScEvEntry;
/* 128 bit SIMD constants. */
enum {
LJ_KSIMD_ABS,
LJ_KSIMD_NEG,
LJ_KSIMD__MAX
};
/* Get 16 byte aligned pointer to SIMD constant. */
#define LJ_KSIMD(J, n) \
((TValue *)(((intptr_t)&J->ksimd[2*(n)] + 15) & ~(intptr_t)15))
/* Set/reset flag to activate the SPLIT pass for the current trace. */
#if LJ_SOFTFP || (LJ_32 && LJ_HASFFI)
#define lj_needsplit(J) (J->needsplit = 1)
#define lj_resetsplit(J) (J->needsplit = 0)
#else
#define lj_needsplit(J) UNUSED(J)
#define lj_resetsplit(J) UNUSED(J)
#endif
/* Fold state is used to fold instructions on-the-fly. */
typedef struct FoldState {
IRIns ins; /* Currently emitted instruction. */
IRIns left; /* Instruction referenced by left operand. */
IRIns right; /* Instruction referenced by right operand. */
} FoldState;
/* JIT compiler state. */
typedef struct jit_State {
GCtrace cur; /* Current trace. */
lua_State *L; /* Current Lua state. */
const BCIns *pc; /* Current PC. */
GCfunc *fn; /* Current function. */
GCproto *pt; /* Current prototype. */
TRef *base; /* Current frame base, points into J->slots. */
uint32_t flags; /* JIT engine flags. */
BCReg maxslot; /* Relative to baseslot. */
BCReg baseslot; /* Current frame base, offset into J->slots. */
uint8_t mergesnap; /* Allowed to merge with next snapshot. */
uint8_t needsnap; /* Need snapshot before recording next bytecode. */
IRType1 guardemit; /* Accumulated IRT_GUARD for emitted instructions. */
uint8_t bcskip; /* Number of bytecode instructions to skip. */
FoldState fold; /* Fold state. */
const BCIns *bc_min; /* Start of allowed bytecode range for root trace. */
MSize bc_extent; /* Extent of the range. */
TraceState state; /* Trace compiler state. */
int32_t instunroll; /* Unroll counter for instable loops. */
int32_t loopunroll; /* Unroll counter for loop ops in side traces. */
int32_t tailcalled; /* Number of successive tailcalls. */
int32_t framedepth; /* Current frame depth. */
int32_t retdepth; /* Return frame depth (count of RETF). */
MRef k64; /* Pointer to chained array of 64 bit constants. */
TValue ksimd[LJ_KSIMD__MAX*2+1]; /* 16 byte aligned SIMD constants. */
IRIns *irbuf; /* Temp. IR instruction buffer. Biased with REF_BIAS. */
IRRef irtoplim; /* Upper limit of instuction buffer (biased). */
IRRef irbotlim; /* Lower limit of instuction buffer (biased). */
IRRef loopref; /* Last loop reference or ref of final LOOP (or 0). */
MSize sizesnap; /* Size of temp. snapshot buffer. */
SnapShot *snapbuf; /* Temp. snapshot buffer. */
SnapEntry *snapmapbuf; /* Temp. snapshot map buffer. */
MSize sizesnapmap; /* Size of temp. snapshot map buffer. */
PostProc postproc; /* Required post-processing after execution. */
#if LJ_SOFTFP || (LJ_32 && LJ_HASFFI)
int needsplit; /* Need SPLIT pass. */
#endif
GCRef *trace; /* Array of traces. */
TraceNo freetrace; /* Start of scan for next free trace. */
MSize sizetrace; /* Size of trace array. */
IRRef1 chain[IR__MAX]; /* IR instruction skip-list chain anchors. */
TRef slot[LJ_MAX_JSLOTS+LJ_STACK_EXTRA]; /* Stack slot map. */
int32_t param[JIT_P__MAX]; /* JIT engine parameters. */
MCode *exitstubgroup[LJ_MAX_EXITSTUBGR]; /* Exit stub group addresses. */
HotPenalty penalty[PENALTY_SLOTS]; /* Penalty slots. */
uint32_t penaltyslot; /* Round-robin index into penalty slots. */
uint32_t prngstate; /* PRNG state. */
BPropEntry bpropcache[BPROP_SLOTS]; /* Backpropagation cache slots. */
uint32_t bpropslot; /* Round-robin index into bpropcache slots. */
ScEvEntry scev; /* Scalar evolution analysis cache slots. */
const BCIns *startpc; /* Bytecode PC of starting instruction. */
TraceNo parent; /* Parent of current side trace (0 for root traces). */
ExitNo exitno; /* Exit number in parent of current side trace. */
BCIns *patchpc; /* PC for pending re-patch. */
BCIns patchins; /* Instruction for pending re-patch. */
int mcprot; /* Protection of current mcode area. */
MCode *mcarea; /* Base of current mcode area. */
MCode *mctop; /* Top of current mcode area. */
MCode *mcbot; /* Bottom of current mcode area. */
size_t szmcarea; /* Size of current mcode area. */
size_t szallmcarea; /* Total size of all allocated mcode areas. */
TValue errinfo; /* Additional info element for trace errors. */
}
#if LJ_TARGET_ARM
LJ_ALIGN(16) /* For DISPATCH-relative addresses in assembler part. */
#endif
jit_State;
/* Trivial PRNG e.g. used for penalty randomization. */
static LJ_AINLINE uint32_t LJ_PRNG_BITS(jit_State *J, int bits)
{
/* Yes, this LCG is very weak, but that doesn't matter for our use case. */
J->prngstate = J->prngstate * 1103515245 + 12345;
return J->prngstate >> (32-bits);
}
#endif
-481
View File
@@ -1,481 +0,0 @@
/*
** Lexical analyzer.
** Copyright (C) 2005-2013 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 lj_lex_c
#define LUA_CORE
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_str.h"
#if LJ_HASFFI
#include "lj_tab.h"
#include "lj_ctype.h"
#include "lj_cdata.h"
#include "lualib.h"
#endif
#include "lj_state.h"
#include "lj_lex.h"
#include "lj_parse.h"
#include "lj_char.h"
#include "lj_strscan.h"
/* Lua lexer token names. */
static const char *const tokennames[] = {
#define TKSTR1(name) #name,
#define TKSTR2(name, sym) #sym,
TKDEF(TKSTR1, TKSTR2)
#undef TKSTR1
#undef TKSTR2
NULL
};
/* -- Buffer handling ----------------------------------------------------- */
#define char2int(c) ((int)(uint8_t)(c))
#define next(ls) \
(ls->current = (ls->n--) > 0 ? char2int(*ls->p++) : fillbuf(ls))
#define save_and_next(ls) (save(ls, ls->current), next(ls))
#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r')
#define END_OF_STREAM (-1)
static int fillbuf(LexState *ls)
{
size_t sz;
const char *buf = ls->rfunc(ls->L, ls->rdata, &sz);
if (buf == NULL || sz == 0) return END_OF_STREAM;
ls->n = (MSize)sz - 1;
ls->p = buf;
return char2int(*(ls->p++));
}
static LJ_NOINLINE void save_grow(LexState *ls, int c)
{
MSize newsize;
if (ls->sb.sz >= LJ_MAX_STR/2)
lj_lex_error(ls, 0, LJ_ERR_XELEM);
newsize = ls->sb.sz * 2;
lj_str_resizebuf(ls->L, &ls->sb, newsize);
ls->sb.buf[ls->sb.n++] = (char)c;
}
static LJ_AINLINE void save(LexState *ls, int c)
{
if (LJ_UNLIKELY(ls->sb.n + 1 > ls->sb.sz))
save_grow(ls, c);
else
ls->sb.buf[ls->sb.n++] = (char)c;
}
static void inclinenumber(LexState *ls)
{
int old = ls->current;
lua_assert(currIsNewline(ls));
next(ls); /* skip `\n' or `\r' */
if (currIsNewline(ls) && ls->current != old)
next(ls); /* skip `\n\r' or `\r\n' */
if (++ls->linenumber >= LJ_MAX_LINE)
lj_lex_error(ls, ls->token, LJ_ERR_XLINES);
}
/* -- Scanner for terminals ----------------------------------------------- */
/* Parse a number literal. */
static void lex_number(LexState *ls, TValue *tv)
{
StrScanFmt fmt;
int c, xp = 'e';
lua_assert(lj_char_isdigit(ls->current));
if ((c = ls->current) == '0') {
save_and_next(ls);
if ((ls->current | 0x20) == 'x') xp = 'p';
}
while (lj_char_isident(ls->current) || ls->current == '.' ||
((ls->current == '-' || ls->current == '+') && (c | 0x20) == xp)) {
c = ls->current;
save_and_next(ls);
}
save(ls, '\0');
fmt = lj_strscan_scan((const uint8_t *)ls->sb.buf, tv,
(LJ_DUALNUM ? STRSCAN_OPT_TOINT : STRSCAN_OPT_TONUM) |
(LJ_HASFFI ? (STRSCAN_OPT_LL|STRSCAN_OPT_IMAG) : 0));
if (LJ_DUALNUM && fmt == STRSCAN_INT) {
setitype(tv, LJ_TISNUM);
} else if (fmt == STRSCAN_NUM) {
/* Already in correct format. */
#if LJ_HASFFI
} else if (fmt != STRSCAN_ERROR) {
lua_State *L = ls->L;
GCcdata *cd;
lua_assert(fmt == STRSCAN_I64 || fmt == STRSCAN_U64 || fmt == STRSCAN_IMAG);
if (!ctype_ctsG(G(L))) {
ptrdiff_t oldtop = savestack(L, L->top);
luaopen_ffi(L); /* Load FFI library on-demand. */
L->top = restorestack(L, oldtop);
}
if (fmt == STRSCAN_IMAG) {
cd = lj_cdata_new_(L, CTID_COMPLEX_DOUBLE, 2*sizeof(double));
((double *)cdataptr(cd))[0] = 0;
((double *)cdataptr(cd))[1] = numV(tv);
} else {
cd = lj_cdata_new_(L, fmt==STRSCAN_I64 ? CTID_INT64 : CTID_UINT64, 8);
*(uint64_t *)cdataptr(cd) = tv->u64;
}
lj_parse_keepcdata(ls, tv, cd);
#endif
} else {
lua_assert(fmt == STRSCAN_ERROR);
lj_lex_error(ls, TK_number, LJ_ERR_XNUMBER);
}
}
static int skip_sep(LexState *ls)
{
int count = 0;
int s = ls->current;
lua_assert(s == '[' || s == ']');
save_and_next(ls);
while (ls->current == '=') {
save_and_next(ls);
count++;
}
return (ls->current == s) ? count : (-count) - 1;
}
static void read_long_string(LexState *ls, TValue *tv, int sep)
{
save_and_next(ls); /* skip 2nd `[' */
if (currIsNewline(ls)) /* string starts with a newline? */
inclinenumber(ls); /* skip it */
for (;;) {
switch (ls->current) {
case END_OF_STREAM:
lj_lex_error(ls, TK_eof, tv ? LJ_ERR_XLSTR : LJ_ERR_XLCOM);
break;
case ']':
if (skip_sep(ls) == sep) {
save_and_next(ls); /* skip 2nd `]' */
goto endloop;
}
break;
case '\n':
case '\r':
save(ls, '\n');
inclinenumber(ls);
if (!tv) lj_str_resetbuf(&ls->sb); /* avoid wasting space */
break;
default:
if (tv) save_and_next(ls);
else next(ls);
break;
}
} endloop:
if (tv) {
GCstr *str = lj_parse_keepstr(ls, ls->sb.buf + (2 + (MSize)sep),
ls->sb.n - 2*(2 + (MSize)sep));
setstrV(ls->L, tv, str);
}
}
static void read_string(LexState *ls, int delim, TValue *tv)
{
save_and_next(ls);
while (ls->current != delim) {
switch (ls->current) {
case END_OF_STREAM:
lj_lex_error(ls, TK_eof, LJ_ERR_XSTR);
continue;
case '\n':
case '\r':
lj_lex_error(ls, TK_string, LJ_ERR_XSTR);
continue;
case '\\': {
int c = next(ls); /* Skip the '\\'. */
switch (c) {
case 'a': c = '\a'; break;
case 'b': c = '\b'; break;
case 'f': c = '\f'; break;
case 'n': c = '\n'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
case 'v': c = '\v'; break;
case 'x': /* Hexadecimal escape '\xXX'. */
c = (next(ls) & 15u) << 4;
if (!lj_char_isdigit(ls->current)) {
if (!lj_char_isxdigit(ls->current)) goto err_xesc;
c += 9 << 4;
}
c += (next(ls) & 15u);
if (!lj_char_isdigit(ls->current)) {
if (!lj_char_isxdigit(ls->current)) goto err_xesc;
c += 9;
}
break;
case 'z': /* Skip whitespace. */
next(ls);
while (lj_char_isspace(ls->current))
if (currIsNewline(ls)) inclinenumber(ls); else next(ls);
continue;
case '\n': case '\r': save(ls, '\n'); inclinenumber(ls); continue;
case '\\': case '\"': case '\'': break;
case END_OF_STREAM: continue;
default:
if (!lj_char_isdigit(c))
goto err_xesc;
c -= '0'; /* Decimal escape '\ddd'. */
if (lj_char_isdigit(next(ls))) {
c = c*10 + (ls->current - '0');
if (lj_char_isdigit(next(ls))) {
c = c*10 + (ls->current - '0');
if (c > 255) {
err_xesc:
lj_lex_error(ls, TK_string, LJ_ERR_XESC);
}
next(ls);
}
}
save(ls, c);
continue;
}
save(ls, c);
next(ls);
continue;
}
default:
save_and_next(ls);
break;
}
}
save_and_next(ls); /* skip delimiter */
setstrV(ls->L, tv, lj_parse_keepstr(ls, ls->sb.buf + 1, ls->sb.n - 2));
}
/* -- Main lexical scanner ------------------------------------------------ */
static int llex(LexState *ls, TValue *tv)
{
lj_str_resetbuf(&ls->sb);
for (;;) {
if (lj_char_isident(ls->current)) {
GCstr *s;
if (lj_char_isdigit(ls->current)) { /* Numeric literal. */
lex_number(ls, tv);
return TK_number;
}
/* Identifier or reserved word. */
do {
save_and_next(ls);
} while (lj_char_isident(ls->current));
s = lj_parse_keepstr(ls, ls->sb.buf, ls->sb.n);
setstrV(ls->L, tv, s);
if (s->reserved > 0) /* Reserved word? */
return TK_OFS + s->reserved;
return TK_name;
}
switch (ls->current) {
case '\n':
case '\r':
inclinenumber(ls);
continue;
case ' ':
case '\t':
case '\v':
case '\f':
next(ls);
continue;
case '-':
next(ls);
if (ls->current != '-') return '-';
/* else is a comment */
next(ls);
if (ls->current == '[') {
int sep = skip_sep(ls);
lj_str_resetbuf(&ls->sb); /* `skip_sep' may dirty the buffer */
if (sep >= 0) {
read_long_string(ls, NULL, sep); /* long comment */
lj_str_resetbuf(&ls->sb);
continue;
}
}
/* else short comment */
while (!currIsNewline(ls) && ls->current != END_OF_STREAM)
next(ls);
continue;
case '[': {
int sep = skip_sep(ls);
if (sep >= 0) {
read_long_string(ls, tv, sep);
return TK_string;
} else if (sep == -1) {
return '[';
} else {
lj_lex_error(ls, TK_string, LJ_ERR_XLDELIM);
continue;
}
}
case '=':
next(ls);
if (ls->current != '=') return '='; else { next(ls); return TK_eq; }
case '<':
next(ls);
if (ls->current != '=') return '<'; else { next(ls); return TK_le; }
case '>':
next(ls);
if (ls->current != '=') return '>'; else { next(ls); return TK_ge; }
case '~':
next(ls);
if (ls->current != '=') return '~'; else { next(ls); return TK_ne; }
case ':':
next(ls);
if (ls->current != ':') return ':'; else { next(ls); return TK_label; }
case '"':
case '\'':
read_string(ls, ls->current, tv);
return TK_string;
case '.':
save_and_next(ls);
if (ls->current == '.') {
next(ls);
if (ls->current == '.') {
next(ls);
return TK_dots; /* ... */
}
return TK_concat; /* .. */
} else if (!lj_char_isdigit(ls->current)) {
return '.';
} else {
lex_number(ls, tv);
return TK_number;
}
case END_OF_STREAM:
return TK_eof;
default: {
int c = ls->current;
next(ls);
return c; /* Single-char tokens (+ - / ...). */
}
}
}
}
/* -- Lexer API ----------------------------------------------------------- */
/* Setup lexer state. */
int lj_lex_setup(lua_State *L, LexState *ls)
{
int header = 0;
ls->L = L;
ls->fs = NULL;
ls->n = 0;
ls->p = NULL;
ls->vstack = NULL;
ls->sizevstack = 0;
ls->vtop = 0;
ls->bcstack = NULL;
ls->sizebcstack = 0;
ls->lookahead = TK_eof; /* No look-ahead token. */
ls->linenumber = 1;
ls->lastline = 1;
lj_str_resizebuf(ls->L, &ls->sb, LJ_MIN_SBUF);
next(ls); /* Read-ahead first char. */
if (ls->current == 0xef && ls->n >= 2 && char2int(ls->p[0]) == 0xbb &&
char2int(ls->p[1]) == 0xbf) { /* Skip UTF-8 BOM (if buffered). */
ls->n -= 2;
ls->p += 2;
next(ls);
header = 1;
}
if (ls->current == '#') { /* Skip POSIX #! header line. */
do {
next(ls);
if (ls->current == END_OF_STREAM) return 0;
} while (!currIsNewline(ls));
inclinenumber(ls);
header = 1;
}
if (ls->current == LUA_SIGNATURE[0]) { /* Bytecode dump. */
if (header) {
/*
** Loading bytecode with an extra header is disabled for security
** reasons. This may circumvent the usual check for bytecode vs.
** Lua code by looking at the first char. Since this is a potential
** security violation no attempt is made to echo the chunkname either.
*/
setstrV(L, L->top++, lj_err_str(L, LJ_ERR_BCBAD));
lj_err_throw(L, LUA_ERRSYNTAX);
}
return 1;
}
return 0;
}
/* Cleanup lexer state. */
void lj_lex_cleanup(lua_State *L, LexState *ls)
{
global_State *g = G(L);
lj_mem_freevec(g, ls->bcstack, ls->sizebcstack, BCInsLine);
lj_mem_freevec(g, ls->vstack, ls->sizevstack, VarInfo);
lj_str_freebuf(g, &ls->sb);
}
void lj_lex_next(LexState *ls)
{
ls->lastline = ls->linenumber;
if (LJ_LIKELY(ls->lookahead == TK_eof)) { /* No lookahead token? */
ls->token = llex(ls, &ls->tokenval); /* Get next token. */
} else { /* Otherwise return lookahead token. */
ls->token = ls->lookahead;
ls->lookahead = TK_eof;
ls->tokenval = ls->lookaheadval;
}
}
LexToken lj_lex_lookahead(LexState *ls)
{
lua_assert(ls->lookahead == TK_eof);
ls->lookahead = llex(ls, &ls->lookaheadval);
return ls->lookahead;
}
const char *lj_lex_token2str(LexState *ls, LexToken token)
{
if (token > TK_OFS)
return tokennames[token-TK_OFS-1];
else if (!lj_char_iscntrl(token))
return lj_str_pushf(ls->L, "%c", token);
else
return lj_str_pushf(ls->L, "char(%d)", token);
}
void lj_lex_error(LexState *ls, LexToken token, ErrMsg em, ...)
{
const char *tok;
va_list argp;
if (token == 0) {
tok = NULL;
} else if (token == TK_name || token == TK_string || token == TK_number) {
save(ls, '\0');
tok = ls->sb.buf;
} else {
tok = lj_lex_token2str(ls, token);
}
va_start(argp, em);
lj_err_lex(ls->L, ls->chunkname, tok, ls->linenumber, em, argp);
va_end(argp);
}
void lj_lex_init(lua_State *L)
{
uint32_t i;
for (i = 0; i < TK_RESERVED; i++) {
GCstr *s = lj_str_newz(L, tokennames[i]);
fixstring(s); /* Reserved words are never collected. */
s->reserved = (uint8_t)(i+1);
}
}
-258
View File
@@ -1,258 +0,0 @@
/*
** Library function support.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
*/
#define lj_lib_c
#define LUA_CORE
#include "lauxlib.h"
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_func.h"
#include "lj_bc.h"
#include "lj_dispatch.h"
#include "lj_vm.h"
#include "lj_strscan.h"
#include "lj_lib.h"
/* -- Library initialization ---------------------------------------------- */
static GCtab *lib_create_table(lua_State *L, const char *libname, int hsize)
{
if (libname) {
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 16);
lua_getfield(L, -1, libname);
if (!tvistab(L->top-1)) {
L->top--;
if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, hsize) != NULL)
lj_err_callerv(L, LJ_ERR_BADMODN, libname);
settabV(L, L->top, tabV(L->top-1));
L->top++;
lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */
}
L->top--;
settabV(L, L->top-1, tabV(L->top));
} else {
lua_createtable(L, 0, hsize);
}
return tabV(L->top-1);
}
void lj_lib_register(lua_State *L, const char *libname,
const uint8_t *p, const lua_CFunction *cf)
{
GCtab *env = tabref(L->env);
GCfunc *ofn = NULL;
int ffid = *p++;
BCIns *bcff = &L2GG(L)->bcff[*p++];
GCtab *tab = lib_create_table(L, libname, *p++);
ptrdiff_t tpos = L->top - L->base;
/* Avoid barriers further down. */
lj_gc_anybarriert(L, tab);
tab->nomm = 0;
for (;;) {
uint32_t tag = *p++;
MSize len = tag & LIBINIT_LENMASK;
tag &= LIBINIT_TAGMASK;
if (tag != LIBINIT_STRING) {
const char *name;
MSize nuv = (MSize)(L->top - L->base - tpos);
GCfunc *fn = lj_func_newC(L, nuv, env);
if (nuv) {
L->top = L->base + tpos;
memcpy(fn->c.upvalue, L->top, sizeof(TValue)*nuv);
}
fn->c.ffid = (uint8_t)(ffid++);
name = (const char *)p;
p += len;
if (tag == LIBINIT_CF)
setmref(fn->c.pc, &G(L)->bc_cfunc_int);
else
setmref(fn->c.pc, bcff++);
if (tag == LIBINIT_ASM_)
fn->c.f = ofn->c.f; /* Copy handler from previous function. */
else
fn->c.f = *cf++; /* Get cf or handler from C function table. */
if (len) {
/* NOBARRIER: See above for common barrier. */
setfuncV(L, lj_tab_setstr(L, tab, lj_str_new(L, name, len)), fn);
}
ofn = fn;
} else {
switch (tag | len) {
case LIBINIT_SET:
L->top -= 2;
if (tvisstr(L->top+1) && strV(L->top+1)->len == 0)
env = tabV(L->top);
else /* NOBARRIER: See above for common barrier. */
copyTV(L, lj_tab_set(L, tab, L->top+1), L->top);
break;
case LIBINIT_NUMBER:
memcpy(&L->top->n, p, sizeof(double));
L->top++;
p += sizeof(double);
break;
case LIBINIT_COPY:
copyTV(L, L->top, L->top - *p++);
L->top++;
break;
case LIBINIT_LASTCL:
setfuncV(L, L->top++, ofn);
break;
case LIBINIT_FFID:
ffid++;
break;
case LIBINIT_END:
return;
default:
setstrV(L, L->top++, lj_str_new(L, (const char *)p, len));
p += len;
break;
}
}
}
}
/* -- Type checks --------------------------------------------------------- */
TValue *lj_lib_checkany(lua_State *L, int narg)
{
TValue *o = L->base + narg-1;
if (o >= L->top)
lj_err_arg(L, narg, LJ_ERR_NOVAL);
return o;
}
GCstr *lj_lib_checkstr(lua_State *L, int narg)
{
TValue *o = L->base + narg-1;
if (o < L->top) {
if (LJ_LIKELY(tvisstr(o))) {
return strV(o);
} else if (tvisnumber(o)) {
GCstr *s = lj_str_fromnumber(L, o);
setstrV(L, o, s);
return s;
}
}
lj_err_argt(L, narg, LUA_TSTRING);
return NULL; /* unreachable */
}
GCstr *lj_lib_optstr(lua_State *L, int narg)
{
TValue *o = L->base + narg-1;
return (o < L->top && !tvisnil(o)) ? lj_lib_checkstr(L, narg) : NULL;
}
#if LJ_DUALNUM
void lj_lib_checknumber(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);
}
#endif
lua_Number lj_lib_checknum(lua_State *L, int narg)
{
TValue *o = L->base + narg-1;
if (!(o < L->top &&
(tvisnumber(o) || (tvisstr(o) && lj_strscan_num(strV(o), o)))))
lj_err_argt(L, narg, LUA_TNUMBER);
if (LJ_UNLIKELY(tvisint(o))) {
lua_Number n = (lua_Number)intV(o);
setnumV(o, n);
return n;
} else {
return numV(o);
}
}
int32_t lj_lib_checkint(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_num2int(numV(o));
if (LJ_DUALNUM) setintV(o, i);
return i;
}
}
int32_t lj_lib_optint(lua_State *L, int narg, int32_t def)
{
TValue *o = L->base + narg-1;
return (o < L->top && !tvisnil(o)) ? lj_lib_checkint(L, narg) : def;
}
int32_t lj_lib_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;
}
}
GCfunc *lj_lib_checkfunc(lua_State *L, int narg)
{
TValue *o = L->base + narg-1;
if (!(o < L->top && tvisfunc(o)))
lj_err_argt(L, narg, LUA_TFUNCTION);
return funcV(o);
}
GCtab *lj_lib_checktab(lua_State *L, int narg)
{
TValue *o = L->base + narg-1;
if (!(o < L->top && tvistab(o)))
lj_err_argt(L, narg, LUA_TTABLE);
return tabV(o);
}
GCtab *lj_lib_checktabornil(lua_State *L, int narg)
{
TValue *o = L->base + narg-1;
if (o < L->top) {
if (tvistab(o))
return tabV(o);
else if (tvisnil(o))
return NULL;
}
lj_err_arg(L, narg, LJ_ERR_NOTABN);
return NULL; /* unreachable */
}
int lj_lib_checkopt(lua_State *L, int narg, int def, const char *lst)
{
GCstr *s = def >= 0 ? lj_lib_optstr(L, narg) : lj_lib_checkstr(L, narg);
if (s) {
const char *opt = strdata(s);
MSize len = s->len;
int i;
for (i = 0; *(const uint8_t *)lst; i++) {
if (*(const uint8_t *)lst == len && memcmp(opt, lst+1, len) == 0)
return i;
lst += 1+*(const uint8_t *)lst;
}
lj_err_argv(L, narg, LJ_ERR_INVOPTM, opt);
}
return def;
}
-359
View File
@@ -1,359 +0,0 @@
/*
** Machine code management.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
*/
#define lj_mcode_c
#define LUA_CORE
#include "lj_obj.h"
#if LJ_HASJIT
#include "lj_gc.h"
#include "lj_jit.h"
#include "lj_mcode.h"
#include "lj_trace.h"
#include "lj_dispatch.h"
#endif
#if LJ_HASJIT || LJ_HASFFI
#include "lj_vm.h"
#endif
/* -- OS-specific functions ----------------------------------------------- */
#if LJ_HASJIT || LJ_HASFFI
/* Define this if you want to run LuaJIT with Valgrind. */
#ifdef LUAJIT_USE_VALGRIND
#include <valgrind/valgrind.h>
#endif
#if LJ_TARGET_IOS
void sys_icache_invalidate(void *start, size_t len);
#endif
/* Synchronize data/instruction cache. */
void lj_mcode_sync(void *start, void *end)
{
#ifdef LUAJIT_USE_VALGRIND
VALGRIND_DISCARD_TRANSLATIONS(start, (char *)end-(char *)start);
#endif
#if LJ_TARGET_X86ORX64
UNUSED(start); UNUSED(end);
#elif LJ_TARGET_IOS
sys_icache_invalidate(start, (char *)end-(char *)start);
#elif LJ_TARGET_PPC
lj_vm_cachesync(start, end);
#elif defined(__GNUC__)
__clear_cache(start, end);
#else
#error "Missing builtin to flush instruction cache"
#endif
}
#endif
#if LJ_HASJIT
#if LJ_TARGET_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define MCPROT_RW PAGE_READWRITE
#define MCPROT_RX PAGE_EXECUTE_READ
#define MCPROT_RWX PAGE_EXECUTE_READWRITE
static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, DWORD prot)
{
void *p = VirtualAlloc((void *)hint, sz,
MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, prot);
if (!p && !hint)
lj_trace_err(J, LJ_TRERR_MCODEAL);
return p;
}
static void mcode_free(jit_State *J, void *p, size_t sz)
{
UNUSED(J); UNUSED(sz);
VirtualFree(p, 0, MEM_RELEASE);
}
static void mcode_setprot(void *p, size_t sz, DWORD prot)
{
DWORD oprot;
VirtualProtect(p, sz, prot, &oprot);
}
#elif LJ_TARGET_POSIX
#include <sys/mman.h>
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
#define MCPROT_RW (PROT_READ|PROT_WRITE)
#define MCPROT_RX (PROT_READ|PROT_EXEC)
#define MCPROT_RWX (PROT_READ|PROT_WRITE|PROT_EXEC)
static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, int prot)
{
void *p = mmap((void *)hint, sz, prot, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (p == MAP_FAILED) {
if (!hint) lj_trace_err(J, LJ_TRERR_MCODEAL);
p = NULL;
}
return p;
}
static void mcode_free(jit_State *J, void *p, size_t sz)
{
UNUSED(J);
munmap(p, sz);
}
static void mcode_setprot(void *p, size_t sz, int prot)
{
mprotect(p, sz, prot);
}
#elif LJ_64
#error "Missing OS support for explicit placement of executable memory"
#else
/* Fallback allocator. This will fail if memory is not executable by default. */
#define LUAJIT_UNPROTECT_MCODE
#define MCPROT_RW 0
#define MCPROT_RX 0
#define MCPROT_RWX 0
static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, int prot)
{
UNUSED(hint); UNUSED(prot);
return lj_mem_new(J->L, sz);
}
static void mcode_free(jit_State *J, void *p, size_t sz)
{
lj_mem_free(J2G(J), p, sz);
}
#define mcode_setprot(p, sz, prot) UNUSED(p)
#endif
/* -- MCode area protection ----------------------------------------------- */
/* Define this ONLY if the page protection twiddling becomes a bottleneck. */
#ifdef LUAJIT_UNPROTECT_MCODE
/* It's generally considered to be a potential security risk to have
** pages with simultaneous write *and* execute access in a process.
**
** Do not even think about using this mode for server processes or
** apps handling untrusted external data (such as a browser).
**
** The security risk is not in LuaJIT itself -- but if an adversary finds
** any *other* flaw in your C application logic, then any RWX memory page
** simplifies writing an exploit considerably.
*/
#define MCPROT_GEN MCPROT_RWX
#define MCPROT_RUN MCPROT_RWX
static void mcode_protect(jit_State *J, int prot)
{
UNUSED(J); UNUSED(prot);
}
#else
/* This is the default behaviour and much safer:
**
** Most of the time the memory pages holding machine code are executable,
** but NONE of them is writable.
**
** The current memory area is marked read-write (but NOT executable) only
** during the short time window while the assembler generates machine code.
*/
#define MCPROT_GEN MCPROT_RW
#define MCPROT_RUN MCPROT_RX
/* Change protection of MCode area. */
static void mcode_protect(jit_State *J, int prot)
{
if (J->mcprot != prot) {
mcode_setprot(J->mcarea, J->szmcarea, prot);
J->mcprot = prot;
}
}
#endif
/* -- MCode area allocation ----------------------------------------------- */
#if LJ_TARGET_X64
#define mcode_validptr(p) ((p) && (uintptr_t)(p) < (uintptr_t)1<<47)
#else
#define mcode_validptr(p) ((p) && (uintptr_t)(p) < 0xffff0000)
#endif
#ifdef LJ_TARGET_JUMPRANGE
/* Get memory within relative jump distance of our code in 64 bit mode. */
static void *mcode_alloc(jit_State *J, size_t sz)
{
/* Target an address in the static assembler code (64K aligned).
** Try addresses within a distance of target-range/2+1MB..target+range/2-1MB.
*/
#if LJ_TARGET_MIPS
/* Use the middle of the 256MB-aligned region. */
uintptr_t target = ((uintptr_t)(void *)lj_vm_exit_handler & 0xf0000000u) +
0x08000000u;
#else
uintptr_t target = (uintptr_t)(void *)lj_vm_exit_handler & ~(uintptr_t)0xffff;
#endif
const uintptr_t range = (1u << LJ_TARGET_JUMPRANGE) - (1u << 21);
/* First try a contiguous area below the last one. */
uintptr_t hint = J->mcarea ? (uintptr_t)J->mcarea - sz : 0;
int i;
for (i = 0; i < 32; i++) { /* 32 attempts ought to be enough ... */
if (mcode_validptr(hint)) {
void *p = mcode_alloc_at(J, hint, sz, MCPROT_GEN);
if (mcode_validptr(p) &&
((uintptr_t)p + sz - target < range || target - (uintptr_t)p < range))
return p;
if (p) mcode_free(J, p, sz); /* Free badly placed area. */
}
/* Next try probing pseudo-random addresses. */
do {
hint = (0x78fb ^ LJ_PRNG_BITS(J, 15)) << 16; /* 64K aligned. */
} while (!(hint + sz < range));
hint = target + hint - (range>>1);
}
lj_trace_err(J, LJ_TRERR_MCODEAL); /* Give up. OS probably ignores hints? */
return NULL;
}
#else
/* All memory addresses are reachable by relative jumps. */
#define mcode_alloc(J, sz) mcode_alloc_at((J), 0, (sz), MCPROT_GEN)
#endif
/* -- MCode area management ----------------------------------------------- */
/* Linked list of MCode areas. */
typedef struct MCLink {
MCode *next; /* Next area. */
size_t size; /* Size of current area. */
} MCLink;
/* Allocate a new MCode area. */
static void mcode_allocarea(jit_State *J)
{
MCode *oldarea = J->mcarea;
size_t sz = (size_t)J->param[JIT_P_sizemcode] << 10;
sz = (sz + LJ_PAGESIZE-1) & ~(size_t)(LJ_PAGESIZE - 1);
J->mcarea = (MCode *)mcode_alloc(J, sz);
J->szmcarea = sz;
J->mcprot = MCPROT_GEN;
J->mctop = (MCode *)((char *)J->mcarea + J->szmcarea);
J->mcbot = (MCode *)((char *)J->mcarea + sizeof(MCLink));
((MCLink *)J->mcarea)->next = oldarea;
((MCLink *)J->mcarea)->size = sz;
J->szallmcarea += sz;
}
/* Free all MCode areas. */
void lj_mcode_free(jit_State *J)
{
MCode *mc = J->mcarea;
J->mcarea = NULL;
J->szallmcarea = 0;
while (mc) {
MCode *next = ((MCLink *)mc)->next;
mcode_free(J, mc, ((MCLink *)mc)->size);
mc = next;
}
}
/* -- MCode transactions -------------------------------------------------- */
/* Reserve the remainder of the current MCode area. */
MCode *lj_mcode_reserve(jit_State *J, MCode **lim)
{
if (!J->mcarea)
mcode_allocarea(J);
else
mcode_protect(J, MCPROT_GEN);
*lim = J->mcbot;
return J->mctop;
}
/* Commit the top part of the current MCode area. */
void lj_mcode_commit(jit_State *J, MCode *top)
{
J->mctop = top;
mcode_protect(J, MCPROT_RUN);
}
/* Abort the reservation. */
void lj_mcode_abort(jit_State *J)
{
mcode_protect(J, MCPROT_RUN);
}
/* Set/reset protection to allow patching of MCode areas. */
MCode *lj_mcode_patch(jit_State *J, MCode *ptr, int finish)
{
#ifdef LUAJIT_UNPROTECT_MCODE
UNUSED(J); UNUSED(ptr); UNUSED(finish);
return NULL;
#else
if (finish) {
if (J->mcarea == ptr)
mcode_protect(J, MCPROT_RUN);
else
mcode_setprot(ptr, ((MCLink *)ptr)->size, MCPROT_RUN);
return NULL;
} else {
MCode *mc = J->mcarea;
/* Try current area first to use the protection cache. */
if (ptr >= mc && ptr < (MCode *)((char *)mc + J->szmcarea)) {
mcode_protect(J, MCPROT_GEN);
return mc;
}
/* Otherwise search through the list of MCode areas. */
for (;;) {
mc = ((MCLink *)mc)->next;
lua_assert(mc != NULL);
if (ptr >= mc && ptr < (MCode *)((char *)mc + ((MCLink *)mc)->size)) {
mcode_setprot(mc, ((MCLink *)mc)->size, MCPROT_GEN);
return mc;
}
}
}
#endif
}
/* Limit of MCode reservation reached. */
void lj_mcode_limiterr(jit_State *J, size_t need)
{
size_t sizemcode, maxmcode;
lj_mcode_abort(J);
sizemcode = (size_t)J->param[JIT_P_sizemcode] << 10;
sizemcode = (sizemcode + LJ_PAGESIZE-1) & ~(size_t)(LJ_PAGESIZE - 1);
maxmcode = (size_t)J->param[JIT_P_maxmcode] << 10;
if ((size_t)need > sizemcode)
lj_trace_err(J, LJ_TRERR_MCODEOV); /* Too long for any area. */
if (J->szallmcarea + sizemcode > maxmcode)
lj_trace_err(J, LJ_TRERR_MCODEAL);
mcode_allocarea(J);
lj_trace_err(J, LJ_TRERR_MCODELM); /* Retry with new area. */
}
#endif
-35
View File
@@ -1,35 +0,0 @@
/*
** Miscellaneous object handling.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
*/
#define lj_obj_c
#define LUA_CORE
#include "lj_obj.h"
/* Object type names. */
LJ_DATADEF const char *const lj_obj_typename[] = { /* ORDER LUA_T */
"no value", "nil", "boolean", "userdata", "number", "string",
"table", "function", "userdata", "thread", "proto", "cdata"
};
LJ_DATADEF const char *const lj_obj_itypename[] = { /* ORDER LJ_T */
"nil", "boolean", "boolean", "userdata", "string", "upval", "thread",
"proto", "function", "trace", "cdata", "table", "userdata", "number"
};
/* Compare two objects without calling metamethods. */
int lj_obj_equal(cTValue *o1, cTValue *o2)
{
if (itype(o1) == itype(o2)) {
if (tvispri(o1))
return 1;
if (!tvisnum(o1))
return gcrefeq(o1->gcr, o2->gcr);
} else if (!tvisnumber(o1) || !tvisnumber(o2)) {
return 0;
}
return numberVnum(o1) == numberVnum(o2);
}
File diff suppressed because it is too large Load Diff
-860
View File
@@ -1,860 +0,0 @@
/*
** Snapshot handling.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
*/
#define lj_snap_c
#define LUA_CORE
#include "lj_obj.h"
#if LJ_HASJIT
#include "lj_gc.h"
#include "lj_tab.h"
#include "lj_state.h"
#include "lj_frame.h"
#include "lj_bc.h"
#include "lj_ir.h"
#include "lj_jit.h"
#include "lj_iropt.h"
#include "lj_trace.h"
#include "lj_snap.h"
#include "lj_target.h"
#if LJ_HASFFI
#include "lj_ctype.h"
#include "lj_cdata.h"
#endif
/* Some local macros to save typing. Undef'd at the end. */
#define IR(ref) (&J->cur.ir[(ref)])
/* Pass IR on to next optimization in chain (FOLD). */
#define emitir(ot, a, b) (lj_ir_set(J, (ot), (a), (b)), lj_opt_fold(J))
/* Emit raw IR without passing through optimizations. */
#define emitir_raw(ot, a, b) (lj_ir_set(J, (ot), (a), (b)), lj_ir_emit(J))
/* -- Snapshot buffer allocation ------------------------------------------ */
/* Grow snapshot buffer. */
void lj_snap_grow_buf_(jit_State *J, MSize need)
{
MSize maxsnap = (MSize)J->param[JIT_P_maxsnap];
if (need > maxsnap)
lj_trace_err(J, LJ_TRERR_SNAPOV);
lj_mem_growvec(J->L, J->snapbuf, J->sizesnap, maxsnap, SnapShot);
J->cur.snap = J->snapbuf;
}
/* Grow snapshot map buffer. */
void lj_snap_grow_map_(jit_State *J, MSize need)
{
if (need < 2*J->sizesnapmap)
need = 2*J->sizesnapmap;
else if (need < 64)
need = 64;
J->snapmapbuf = (SnapEntry *)lj_mem_realloc(J->L, J->snapmapbuf,
J->sizesnapmap*sizeof(SnapEntry), need*sizeof(SnapEntry));
J->cur.snapmap = J->snapmapbuf;
J->sizesnapmap = need;
}
/* -- Snapshot generation ------------------------------------------------- */
/* Add all modified slots to the snapshot. */
static MSize snapshot_slots(jit_State *J, SnapEntry *map, BCReg nslots)
{
IRRef retf = J->chain[IR_RETF]; /* Limits SLOAD restore elimination. */
BCReg s;
MSize n = 0;
for (s = 0; s < nslots; s++) {
TRef tr = J->slot[s];
IRRef ref = tref_ref(tr);
if (ref) {
SnapEntry sn = SNAP_TR(s, tr);
IRIns *ir = IR(ref);
if (!(sn & (SNAP_CONT|SNAP_FRAME)) &&
ir->o == IR_SLOAD && ir->op1 == s && ref > retf) {
/* No need to snapshot unmodified non-inherited slots. */
if (!(ir->op2 & IRSLOAD_INHERIT))
continue;
/* No need to restore readonly slots and unmodified non-parent slots. */
if (!(LJ_DUALNUM && (ir->op2 & IRSLOAD_CONVERT)) &&
(ir->op2 & (IRSLOAD_READONLY|IRSLOAD_PARENT)) != IRSLOAD_PARENT)
sn |= SNAP_NORESTORE;
}
if (LJ_SOFTFP && irt_isnum(ir->t))
sn |= SNAP_SOFTFPNUM;
map[n++] = sn;
}
}
return n;
}
/* Add frame links at the end of the snapshot. */
static BCReg snapshot_framelinks(jit_State *J, SnapEntry *map)
{
cTValue *frame = J->L->base - 1;
cTValue *lim = J->L->base - J->baseslot;
cTValue *ftop = frame + funcproto(frame_func(frame))->framesize;
MSize f = 0;
map[f++] = SNAP_MKPC(J->pc); /* The current PC is always the first entry. */
while (frame > lim) { /* Backwards traversal of all frames above base. */
if (frame_islua(frame)) {
map[f++] = SNAP_MKPC(frame_pc(frame));
frame = frame_prevl(frame);
if (frame + funcproto(frame_func(frame))->framesize > ftop)
ftop = frame + funcproto(frame_func(frame))->framesize;
} else if (frame_iscont(frame)) {
map[f++] = SNAP_MKFTSZ(frame_ftsz(frame));
map[f++] = SNAP_MKPC(frame_contpc(frame));
frame = frame_prevd(frame);
} else {
lua_assert(!frame_isc(frame));
map[f++] = SNAP_MKFTSZ(frame_ftsz(frame));
frame = frame_prevd(frame);
}
}
lua_assert(f == (MSize)(1 + J->framedepth));
return (BCReg)(ftop - lim);
}
/* Take a snapshot of the current stack. */
static void snapshot_stack(jit_State *J, SnapShot *snap, MSize nsnapmap)
{
BCReg nslots = J->baseslot + J->maxslot;
MSize nent;
SnapEntry *p;
/* Conservative estimate. */
lj_snap_grow_map(J, nsnapmap + nslots + (MSize)J->framedepth+1);
p = &J->cur.snapmap[nsnapmap];
nent = snapshot_slots(J, p, nslots);
snap->topslot = (uint8_t)snapshot_framelinks(J, p + nent);
snap->mapofs = (uint16_t)nsnapmap;
snap->ref = (IRRef1)J->cur.nins;
snap->nent = (uint8_t)nent;
snap->nslots = (uint8_t)nslots;
snap->count = 0;
J->cur.nsnapmap = (uint16_t)(nsnapmap + nent + 1 + J->framedepth);
}
/* Add or merge a snapshot. */
void lj_snap_add(jit_State *J)
{
MSize nsnap = J->cur.nsnap;
MSize nsnapmap = J->cur.nsnapmap;
/* Merge if no ins. inbetween or if requested and no guard inbetween. */
if (J->mergesnap ? !irt_isguard(J->guardemit) :
(nsnap > 0 && J->cur.snap[nsnap-1].ref == J->cur.nins)) {
if (nsnap == 1) { /* But preserve snap #0 PC. */
emitir_raw(IRT(IR_NOP, IRT_NIL), 0, 0);
goto nomerge;
}
nsnapmap = J->cur.snap[--nsnap].mapofs;
} else {
nomerge:
lj_snap_grow_buf(J, nsnap+1);
J->cur.nsnap = (uint16_t)(nsnap+1);
}
J->mergesnap = 0;
J->guardemit.irt = 0;
snapshot_stack(J, &J->cur.snap[nsnap], nsnapmap);
}
/* -- Snapshot modification ----------------------------------------------- */
#define SNAP_USEDEF_SLOTS (LJ_MAX_JSLOTS+LJ_STACK_EXTRA)
/* Find unused slots with reaching-definitions bytecode data-flow analysis. */
static BCReg snap_usedef(jit_State *J, uint8_t *udf,
const BCIns *pc, BCReg maxslot)
{
BCReg s;
GCobj *o;
if (maxslot == 0) return 0;
#ifdef LUAJIT_USE_VALGRIND
/* Avoid errors for harmless reads beyond maxslot. */
memset(udf, 1, SNAP_USEDEF_SLOTS);
#else
memset(udf, 1, maxslot);
#endif
/* Treat open upvalues as used. */
o = gcref(J->L->openupval);
while (o) {
if (uvval(gco2uv(o)) < J->L->base) break;
udf[uvval(gco2uv(o)) - J->L->base] = 0;
o = gcref(o->gch.nextgc);
}
#define USE_SLOT(s) udf[(s)] &= ~1
#define DEF_SLOT(s) udf[(s)] *= 3
/* Scan through following bytecode and check for uses/defs. */
lua_assert(pc >= proto_bc(J->pt) && pc < proto_bc(J->pt) + J->pt->sizebc);
for (;;) {
BCIns ins = *pc++;
BCOp op = bc_op(ins);
switch (bcmode_b(op)) {
case BCMvar: USE_SLOT(bc_b(ins)); break;
default: break;
}
switch (bcmode_c(op)) {
case BCMvar: USE_SLOT(bc_c(ins)); break;
case BCMrbase:
lua_assert(op == BC_CAT);
for (s = bc_b(ins); s <= bc_c(ins); s++) USE_SLOT(s);
for (; s < maxslot; s++) DEF_SLOT(s);
break;
case BCMjump:
handle_jump: {
BCReg minslot = bc_a(ins);
if (op >= BC_FORI && op <= BC_JFORL) minslot += FORL_EXT;
else if (op >= BC_ITERL && op <= BC_JITERL) minslot += bc_b(pc[-2])-1;
else if (op == BC_UCLO) { pc += bc_j(ins); break; }
for (s = minslot; s < maxslot; s++) DEF_SLOT(s);
return minslot < maxslot ? minslot : maxslot;
}
case BCMlit:
if (op == BC_JFORL || op == BC_JITERL || op == BC_JLOOP) {
goto handle_jump;
} else if (bc_isret(op)) {
BCReg top = op == BC_RETM ? maxslot : (bc_a(ins) + bc_d(ins)-1);
for (s = 0; s < bc_a(ins); s++) DEF_SLOT(s);
for (; s < top; s++) USE_SLOT(s);
for (; s < maxslot; s++) DEF_SLOT(s);
return 0;
}
break;
case BCMfunc: return maxslot; /* NYI: will abort, anyway. */
default: break;
}
switch (bcmode_a(op)) {
case BCMvar: USE_SLOT(bc_a(ins)); break;
case BCMdst:
if (!(op == BC_ISTC || op == BC_ISFC)) DEF_SLOT(bc_a(ins));
break;
case BCMbase:
if (op >= BC_CALLM && op <= BC_VARG) {
BCReg top = (op == BC_CALLM || op == BC_CALLMT || bc_c(ins) == 0) ?
maxslot : (bc_a(ins) + bc_c(ins));
s = bc_a(ins) - ((op == BC_ITERC || op == BC_ITERN) ? 3 : 0);
for (; s < top; s++) USE_SLOT(s);
for (; s < maxslot; s++) DEF_SLOT(s);
if (op == BC_CALLT || op == BC_CALLMT) {
for (s = 0; s < bc_a(ins); s++) DEF_SLOT(s);
return 0;
}
} else if (op == BC_KNIL) {
for (s = bc_a(ins); s <= bc_d(ins); s++) DEF_SLOT(s);
} else if (op == BC_TSETM) {
for (s = bc_a(ins)-1; s < maxslot; s++) USE_SLOT(s);
}
break;
default: break;
}
lua_assert(pc >= proto_bc(J->pt) && pc < proto_bc(J->pt) + J->pt->sizebc);
}
#undef USE_SLOT
#undef DEF_SLOT
return 0; /* unreachable */
}
/* Purge dead slots before the next snapshot. */
void lj_snap_purge(jit_State *J)
{
uint8_t udf[SNAP_USEDEF_SLOTS];
BCReg maxslot = J->maxslot;
BCReg s = snap_usedef(J, udf, J->pc, maxslot);
for (; s < maxslot; s++)
if (udf[s] != 0)
J->base[s] = 0; /* Purge dead slots. */
}
/* Shrink last snapshot. */
void lj_snap_shrink(jit_State *J)
{
SnapShot *snap = &J->cur.snap[J->cur.nsnap-1];
SnapEntry *map = &J->cur.snapmap[snap->mapofs];
MSize n, m, nlim, nent = snap->nent;
uint8_t udf[SNAP_USEDEF_SLOTS];
BCReg maxslot = J->maxslot;
BCReg minslot = snap_usedef(J, udf, snap_pc(map[nent]), maxslot);
BCReg baseslot = J->baseslot;
maxslot += baseslot;
minslot += baseslot;
snap->nslots = (uint8_t)maxslot;
for (n = m = 0; n < nent; n++) { /* Remove unused slots from snapshot. */
BCReg s = snap_slot(map[n]);
if (s < minslot || (s < maxslot && udf[s-baseslot] == 0))
map[m++] = map[n]; /* Only copy used slots. */
}
snap->nent = (uint8_t)m;
nlim = J->cur.nsnapmap - snap->mapofs - 1;
while (n <= nlim) map[m++] = map[n++]; /* Move PC + frame links down. */
J->cur.nsnapmap = (uint16_t)(snap->mapofs + m); /* Free up space in map. */
}
/* -- Snapshot access ----------------------------------------------------- */
/* Initialize a Bloom Filter with all renamed refs.
** There are very few renames (often none), so the filter has
** very few bits set. This makes it suitable for negative filtering.
*/
static BloomFilter snap_renamefilter(GCtrace *T, SnapNo lim)
{
BloomFilter rfilt = 0;
IRIns *ir;
for (ir = &T->ir[T->nins-1]; ir->o == IR_RENAME; ir--)
if (ir->op2 <= lim)
bloomset(rfilt, ir->op1);
return rfilt;
}
/* Process matching renames to find the original RegSP. */
static RegSP snap_renameref(GCtrace *T, SnapNo lim, IRRef ref, RegSP rs)
{
IRIns *ir;
for (ir = &T->ir[T->nins-1]; ir->o == IR_RENAME; ir--)
if (ir->op1 == ref && ir->op2 <= lim)
rs = ir->prev;
return rs;
}
/* Copy RegSP from parent snapshot to the parent links of the IR. */
IRIns *lj_snap_regspmap(GCtrace *T, SnapNo snapno, IRIns *ir)
{
SnapShot *snap = &T->snap[snapno];
SnapEntry *map = &T->snapmap[snap->mapofs];
BloomFilter rfilt = snap_renamefilter(T, snapno);
MSize n = 0;
IRRef ref = 0;
for ( ; ; ir++) {
uint32_t rs;
if (ir->o == IR_SLOAD) {
if (!(ir->op2 & IRSLOAD_PARENT)) break;
for ( ; ; n++) {
lua_assert(n < snap->nent);
if (snap_slot(map[n]) == ir->op1) {
ref = snap_ref(map[n++]);
break;
}
}
} else if (LJ_SOFTFP && ir->o == IR_HIOP) {
ref++;
} else if (ir->o == IR_PVAL) {
ref = ir->op1 + REF_BIAS;
} else {
break;
}
rs = T->ir[ref].prev;
if (bloomtest(rfilt, ref))
rs = snap_renameref(T, snapno, ref, rs);
ir->prev = (uint16_t)rs;
lua_assert(regsp_used(rs));
}
return ir;
}
/* -- Snapshot replay ----------------------------------------------------- */
/* Replay constant from parent trace. */
static TRef snap_replay_const(jit_State *J, IRIns *ir)
{
/* Only have to deal with constants that can occur in stack slots. */
switch ((IROp)ir->o) {
case IR_KPRI: return TREF_PRI(irt_type(ir->t));
case IR_KINT: return lj_ir_kint(J, ir->i);
case IR_KGC: return lj_ir_kgc(J, ir_kgc(ir), irt_t(ir->t));
case IR_KNUM: return lj_ir_k64(J, IR_KNUM, ir_knum(ir));
case IR_KINT64: return lj_ir_k64(J, IR_KINT64, ir_kint64(ir));
case IR_KPTR: return lj_ir_kptr(J, ir_kptr(ir)); /* Continuation. */
default: lua_assert(0); return TREF_NIL; break;
}
}
/* De-duplicate parent reference. */
static TRef snap_dedup(jit_State *J, SnapEntry *map, MSize nmax, IRRef ref)
{
MSize j;
for (j = 0; j < nmax; j++)
if (snap_ref(map[j]) == ref)
return J->slot[snap_slot(map[j])] & ~(SNAP_CONT|SNAP_FRAME);
return 0;
}
/* Emit parent reference with de-duplication. */
static TRef snap_pref(jit_State *J, GCtrace *T, SnapEntry *map, MSize nmax,
BloomFilter seen, IRRef ref)
{
IRIns *ir = &T->ir[ref];
TRef tr;
if (irref_isk(ref))
tr = snap_replay_const(J, ir);
else if (!regsp_used(ir->prev))
tr = 0;
else if (!bloomtest(seen, ref) || (tr = snap_dedup(J, map, nmax, ref)) == 0)
tr = emitir(IRT(IR_PVAL, irt_type(ir->t)), ref - REF_BIAS, 0);
return tr;
}
/* Check whether a sunk store corresponds to an allocation. Slow path. */
static int snap_sunk_store2(jit_State *J, IRIns *ira, IRIns *irs)
{
if (irs->o == IR_ASTORE || irs->o == IR_HSTORE ||
irs->o == IR_FSTORE || irs->o == IR_XSTORE) {
IRIns *irk = IR(irs->op1);
if (irk->o == IR_AREF || irk->o == IR_HREFK)
irk = IR(irk->op1);
return (IR(irk->op1) == ira);
}
return 0;
}
/* Check whether a sunk store corresponds to an allocation. Fast path. */
static LJ_AINLINE int snap_sunk_store(jit_State *J, IRIns *ira, IRIns *irs)
{
if (irs->s != 255)
return (ira + irs->s == irs); /* Fast check. */
return snap_sunk_store2(J, ira, irs);
}
/* Replay snapshot state to setup side trace. */
void lj_snap_replay(jit_State *J, GCtrace *T)
{
SnapShot *snap = &T->snap[J->exitno];
SnapEntry *map = &T->snapmap[snap->mapofs];
MSize n, nent = snap->nent;
BloomFilter seen = 0;
int pass23 = 0;
J->framedepth = 0;
/* Emit IR for slots inherited from parent snapshot. */
for (n = 0; n < nent; n++) {
SnapEntry sn = map[n];
BCReg s = snap_slot(sn);
IRRef ref = snap_ref(sn);
IRIns *ir = &T->ir[ref];
TRef tr;
/* The bloom filter avoids O(nent^2) overhead for de-duping slots. */
if (bloomtest(seen, ref) && (tr = snap_dedup(J, map, n, ref)) != 0)
goto setslot;
bloomset(seen, ref);
if (irref_isk(ref)) {
tr = snap_replay_const(J, ir);
} else if (!regsp_used(ir->prev)) {
pass23 = 1;
lua_assert(s != 0);
tr = s;
} else {
IRType t = irt_type(ir->t);
uint32_t mode = IRSLOAD_INHERIT|IRSLOAD_PARENT;
if (LJ_SOFTFP && (sn & SNAP_SOFTFPNUM)) t = IRT_NUM;
if (ir->o == IR_SLOAD) mode |= (ir->op2 & IRSLOAD_READONLY);
tr = emitir_raw(IRT(IR_SLOAD, t), s, mode);
}
setslot:
J->slot[s] = tr | (sn&(SNAP_CONT|SNAP_FRAME)); /* Same as TREF_* flags. */
J->framedepth += ((sn & (SNAP_CONT|SNAP_FRAME)) && s);
if ((sn & SNAP_FRAME))
J->baseslot = s+1;
}
if (pass23) {
IRIns *irlast = &T->ir[snap->ref];
pass23 = 0;
/* Emit dependent PVALs. */
for (n = 0; n < nent; n++) {
SnapEntry sn = map[n];
IRRef refp = snap_ref(sn);
IRIns *ir = &T->ir[refp];
if (regsp_reg(ir->r) == RID_SUNK) {
if (J->slot[snap_slot(sn)] != snap_slot(sn)) continue;
pass23 = 1;
lua_assert(ir->o == IR_TNEW || ir->o == IR_TDUP ||
ir->o == IR_CNEW || ir->o == IR_CNEWI);
if (ir->op1 >= T->nk) snap_pref(J, T, map, nent, seen, ir->op1);
if (ir->op2 >= T->nk) snap_pref(J, T, map, nent, seen, ir->op2);
if (LJ_HASFFI && ir->o == IR_CNEWI) {
if (LJ_32 && refp+1 < T->nins && (ir+1)->o == IR_HIOP)
snap_pref(J, T, map, nent, seen, (ir+1)->op2);
} else {
IRIns *irs;
for (irs = ir+1; irs < irlast; irs++)
if (irs->r == RID_SINK && snap_sunk_store(J, ir, irs)) {
if (snap_pref(J, T, map, nent, seen, irs->op2) == 0)
snap_pref(J, T, map, nent, seen, T->ir[irs->op2].op1);
else if ((LJ_SOFTFP || (LJ_32 && LJ_HASFFI)) &&
irs+1 < irlast && (irs+1)->o == IR_HIOP)
snap_pref(J, T, map, nent, seen, (irs+1)->op2);
}
}
} else if (!irref_isk(refp) && !regsp_used(ir->prev)) {
lua_assert(ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT);
J->slot[snap_slot(sn)] = snap_pref(J, T, map, nent, seen, ir->op1);
}
}
/* Replay sunk instructions. */
for (n = 0; pass23 && n < nent; n++) {
SnapEntry sn = map[n];
IRRef refp = snap_ref(sn);
IRIns *ir = &T->ir[refp];
if (regsp_reg(ir->r) == RID_SUNK) {
TRef op1, op2;
if (J->slot[snap_slot(sn)] != snap_slot(sn)) { /* De-dup allocs. */
J->slot[snap_slot(sn)] = J->slot[J->slot[snap_slot(sn)]];
continue;
}
op1 = ir->op1;
if (op1 >= T->nk) op1 = snap_pref(J, T, map, nent, seen, op1);
op2 = ir->op2;
if (op2 >= T->nk) op2 = snap_pref(J, T, map, nent, seen, op2);
if (LJ_HASFFI && ir->o == IR_CNEWI) {
if (LJ_32 && refp+1 < T->nins && (ir+1)->o == IR_HIOP) {
lj_needsplit(J); /* Emit joining HIOP. */
op2 = emitir_raw(IRT(IR_HIOP, IRT_I64), op2,
snap_pref(J, T, map, nent, seen, (ir+1)->op2));
}
J->slot[snap_slot(sn)] = emitir(ir->ot, op1, op2);
} else {
IRIns *irs;
TRef tr = emitir(ir->ot, op1, op2);
J->slot[snap_slot(sn)] = tr;
for (irs = ir+1; irs < irlast; irs++)
if (irs->r == RID_SINK && snap_sunk_store(J, ir, irs)) {
IRIns *irr = &T->ir[irs->op1];
TRef val, key = irr->op2, tmp = tr;
if (irr->o != IR_FREF) {
IRIns *irk = &T->ir[key];
if (irr->o == IR_HREFK)
key = lj_ir_kslot(J, snap_replay_const(J, &T->ir[irk->op1]),
irk->op2);
else
key = snap_replay_const(J, irk);
if (irr->o == IR_HREFK || irr->o == IR_AREF) {
IRIns *irf = &T->ir[irr->op1];
tmp = emitir(irf->ot, tmp, irf->op2);
}
}
tmp = emitir(irr->ot, tmp, key);
val = snap_pref(J, T, map, nent, seen, irs->op2);
if (val == 0) {
IRIns *irc = &T->ir[irs->op2];
lua_assert(irc->o == IR_CONV && irc->op2 == IRCONV_NUM_INT);
val = snap_pref(J, T, map, nent, seen, irc->op1);
val = emitir(IRTN(IR_CONV), val, IRCONV_NUM_INT);
} else if ((LJ_SOFTFP || (LJ_32 && LJ_HASFFI)) &&
irs+1 < irlast && (irs+1)->o == IR_HIOP) {
IRType t = IRT_I64;
if (LJ_SOFTFP && irt_type((irs+1)->t) == IRT_SOFTFP)
t = IRT_NUM;
lj_needsplit(J);
if (irref_isk(irs->op2) && irref_isk((irs+1)->op2)) {
uint64_t k = (uint32_t)T->ir[irs->op2].i +
((uint64_t)T->ir[(irs+1)->op2].i << 32);
val = lj_ir_k64(J, t == IRT_I64 ? IR_KINT64 : IR_KNUM,
lj_ir_k64_find(J, k));
} else {
val = emitir_raw(IRT(IR_HIOP, t), val,
snap_pref(J, T, map, nent, seen, (irs+1)->op2));
}
tmp = emitir(IRT(irs->o, t), tmp, val);
continue;
}
tmp = emitir(irs->ot, tmp, val);
}
}
}
}
}
J->base = J->slot + J->baseslot;
J->maxslot = snap->nslots - J->baseslot;
lj_snap_add(J);
if (pass23) /* Need explicit GC step _after_ initial snapshot. */
emitir_raw(IRTG(IR_GCSTEP, IRT_NIL), 0, 0);
}
/* -- Snapshot restore ---------------------------------------------------- */
static void snap_unsink(jit_State *J, GCtrace *T, ExitState *ex,
SnapNo snapno, BloomFilter rfilt,
IRIns *ir, TValue *o);
/* Restore a value from the trace exit state. */
static void snap_restoreval(jit_State *J, GCtrace *T, ExitState *ex,
SnapNo snapno, BloomFilter rfilt,
IRRef ref, TValue *o)
{
IRIns *ir = &T->ir[ref];
IRType1 t = ir->t;
RegSP rs = ir->prev;
if (irref_isk(ref)) { /* Restore constant slot. */
lj_ir_kvalue(J->L, o, ir);
return;
}
if (LJ_UNLIKELY(bloomtest(rfilt, ref)))
rs = snap_renameref(T, snapno, ref, rs);
if (ra_hasspill(regsp_spill(rs))) { /* Restore from spill slot. */
int32_t *sps = &ex->spill[regsp_spill(rs)];
if (irt_isinteger(t)) {
setintV(o, *sps);
#if !LJ_SOFTFP
} else if (irt_isnum(t)) {
o->u64 = *(uint64_t *)sps;
#endif
} else if (LJ_64 && irt_islightud(t)) {
/* 64 bit lightuserdata which may escape already has the tag bits. */
o->u64 = *(uint64_t *)sps;
} else {
lua_assert(!irt_ispri(t)); /* PRI refs never have a spill slot. */
setgcrefi(o->gcr, *sps);
setitype(o, irt_toitype(t));
}
} else { /* Restore from register. */
Reg r = regsp_reg(rs);
if (ra_noreg(r)) {
lua_assert(ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT);
snap_restoreval(J, T, ex, snapno, rfilt, ir->op1, o);
if (LJ_DUALNUM) setnumV(o, (lua_Number)intV(o));
return;
} else if (irt_isinteger(t)) {
setintV(o, (int32_t)ex->gpr[r-RID_MIN_GPR]);
#if !LJ_SOFTFP
} else if (irt_isnum(t)) {
setnumV(o, ex->fpr[r-RID_MIN_FPR]);
#endif
} else if (LJ_64 && irt_islightud(t)) {
/* 64 bit lightuserdata which may escape already has the tag bits. */
o->u64 = ex->gpr[r-RID_MIN_GPR];
} else {
if (!irt_ispri(t))
setgcrefi(o->gcr, ex->gpr[r-RID_MIN_GPR]);
setitype(o, irt_toitype(t));
}
}
}
#if LJ_HASFFI
/* Restore raw data from the trace exit state. */
static void snap_restoredata(GCtrace *T, ExitState *ex,
SnapNo snapno, BloomFilter rfilt,
IRRef ref, void *dst, CTSize sz)
{
IRIns *ir = &T->ir[ref];
RegSP rs = ir->prev;
int32_t *src;
uint64_t tmp;
if (irref_isk(ref)) {
if (ir->o == IR_KNUM || ir->o == IR_KINT64) {
src = mref(ir->ptr, int32_t);
} else if (sz == 8) {
tmp = (uint64_t)(uint32_t)ir->i;
src = (int32_t *)&tmp;
} else {
src = &ir->i;
}
} else {
if (LJ_UNLIKELY(bloomtest(rfilt, ref)))
rs = snap_renameref(T, snapno, ref, rs);
if (ra_hasspill(regsp_spill(rs))) {
src = &ex->spill[regsp_spill(rs)];
if (sz == 8 && !irt_is64(ir->t)) {
tmp = (uint64_t)(uint32_t)*src;
src = (int32_t *)&tmp;
}
} else {
Reg r = regsp_reg(rs);
if (ra_noreg(r)) {
/* Note: this assumes CNEWI is never used for SOFTFP split numbers. */
lua_assert(sz == 8 && ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT);
snap_restoredata(T, ex, snapno, rfilt, ir->op1, dst, 4);
*(lua_Number *)dst = (lua_Number)*(int32_t *)dst;
return;
}
src = (int32_t *)&ex->gpr[r-RID_MIN_GPR];
#if !LJ_SOFTFP
if (r >= RID_MAX_GPR) {
src = (int32_t *)&ex->fpr[r-RID_MIN_FPR];
#if LJ_TARGET_PPC
if (sz == 4) { /* PPC FPRs are always doubles. */
*(float *)dst = (float)*(double *)src;
return;
}
#else
if (LJ_BE && sz == 4) src++;
#endif
}
#endif
}
}
lua_assert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
if (sz == 4) *(int32_t *)dst = *src;
else if (sz == 8) *(int64_t *)dst = *(int64_t *)src;
else if (sz == 1) *(int8_t *)dst = (int8_t)*src;
else *(int16_t *)dst = (int16_t)*src;
}
#endif
/* Unsink allocation from the trace exit state. Unsink sunk stores. */
static void snap_unsink(jit_State *J, GCtrace *T, ExitState *ex,
SnapNo snapno, BloomFilter rfilt,
IRIns *ir, TValue *o)
{
lua_assert(ir->o == IR_TNEW || ir->o == IR_TDUP ||
ir->o == IR_CNEW || ir->o == IR_CNEWI);
#if LJ_HASFFI
if (ir->o == IR_CNEW || ir->o == IR_CNEWI) {
CTState *cts = ctype_ctsG(J2G(J));
CTypeID id = (CTypeID)T->ir[ir->op1].i;
CTSize sz = lj_ctype_size(cts, id);
GCcdata *cd = lj_cdata_new(cts, id, sz);
setcdataV(J->L, o, cd);
if (ir->o == IR_CNEWI) {
uint8_t *p = (uint8_t *)cdataptr(cd);
lua_assert(sz == 4 || sz == 8);
if (LJ_32 && sz == 8 && ir+1 < T->ir + T->nins && (ir+1)->o == IR_HIOP) {
snap_restoredata(T, ex, snapno, rfilt, (ir+1)->op2, LJ_LE?p+4:p, 4);
if (LJ_BE) p += 4;
sz = 4;
}
snap_restoredata(T, ex, snapno, rfilt, ir->op2, p, sz);
} else {
IRIns *irs, *irlast = &T->ir[T->snap[snapno].ref];
for (irs = ir+1; irs < irlast; irs++)
if (irs->r == RID_SINK && snap_sunk_store(J, ir, irs)) {
IRIns *iro = &T->ir[T->ir[irs->op1].op2];
uint8_t *p = (uint8_t *)cd;
CTSize szs;
lua_assert(irs->o == IR_XSTORE && T->ir[irs->op1].o == IR_ADD);
lua_assert(iro->o == IR_KINT || iro->o == IR_KINT64);
if (irt_is64(irs->t)) szs = 8;
else if (irt_isi8(irs->t) || irt_isu8(irs->t)) szs = 1;
else if (irt_isi16(irs->t) || irt_isu16(irs->t)) szs = 2;
else szs = 4;
if (LJ_64 && iro->o == IR_KINT64)
p += (int64_t)ir_k64(iro)->u64;
else
p += iro->i;
lua_assert(p >= (uint8_t *)cdataptr(cd) &&
p + szs <= (uint8_t *)cdataptr(cd) + sz);
if (LJ_32 && irs+1 < T->ir + T->nins && (irs+1)->o == IR_HIOP) {
lua_assert(szs == 4);
snap_restoredata(T, ex, snapno, rfilt, (irs+1)->op2, LJ_LE?p+4:p,4);
if (LJ_BE) p += 4;
}
snap_restoredata(T, ex, snapno, rfilt, irs->op2, p, szs);
}
}
} else
#endif
{
IRIns *irs, *irlast;
GCtab *t = ir->o == IR_TNEW ? lj_tab_new(J->L, ir->op1, ir->op2) :
lj_tab_dup(J->L, ir_ktab(&T->ir[ir->op1]));
settabV(J->L, o, t);
irlast = &T->ir[T->snap[snapno].ref];
for (irs = ir+1; irs < irlast; irs++)
if (irs->r == RID_SINK && snap_sunk_store(J, ir, irs)) {
IRIns *irk = &T->ir[irs->op1];
TValue tmp, *val;
lua_assert(irs->o == IR_ASTORE || irs->o == IR_HSTORE ||
irs->o == IR_FSTORE);
if (irk->o == IR_FREF) {
lua_assert(irk->op2 == IRFL_TAB_META);
snap_restoreval(J, T, ex, snapno, rfilt, irs->op2, &tmp);
/* NOBARRIER: The table is new (marked white). */
setgcref(t->metatable, obj2gco(tabV(&tmp)));
} else {
irk = &T->ir[irk->op2];
if (irk->o == IR_KSLOT) irk = &T->ir[irk->op1];
lj_ir_kvalue(J->L, &tmp, irk);
val = lj_tab_set(J->L, t, &tmp);
/* NOBARRIER: The table is new (marked white). */
snap_restoreval(J, T, ex, snapno, rfilt, irs->op2, val);
if (LJ_SOFTFP && irs+1 < T->ir + T->nins && (irs+1)->o == IR_HIOP) {
snap_restoreval(J, T, ex, snapno, rfilt, (irs+1)->op2, &tmp);
val->u32.hi = tmp.u32.lo;
}
}
}
}
}
/* Restore interpreter state from exit state with the help of a snapshot. */
const BCIns *lj_snap_restore(jit_State *J, void *exptr)
{
ExitState *ex = (ExitState *)exptr;
SnapNo snapno = J->exitno; /* For now, snapno == exitno. */
GCtrace *T = traceref(J, J->parent);
SnapShot *snap = &T->snap[snapno];
MSize n, nent = snap->nent;
SnapEntry *map = &T->snapmap[snap->mapofs];
SnapEntry *flinks = &T->snapmap[snap_nextofs(T, snap)-1];
int32_t ftsz0;
TValue *frame;
BloomFilter rfilt = snap_renamefilter(T, snapno);
const BCIns *pc = snap_pc(map[nent]);
lua_State *L = J->L;
/* Set interpreter PC to the next PC to get correct error messages. */
setcframe_pc(cframe_raw(L->cframe), pc+1);
/* Make sure the stack is big enough for the slots from the snapshot. */
if (LJ_UNLIKELY(L->base + snap->topslot >= tvref(L->maxstack))) {
L->top = curr_topL(L);
lj_state_growstack(L, snap->topslot - curr_proto(L)->framesize);
}
/* Fill stack slots with data from the registers and spill slots. */
frame = L->base-1;
ftsz0 = frame_ftsz(frame); /* Preserve link to previous frame in slot #0. */
for (n = 0; n < nent; n++) {
SnapEntry sn = map[n];
if (!(sn & SNAP_NORESTORE)) {
TValue *o = &frame[snap_slot(sn)];
IRRef ref = snap_ref(sn);
IRIns *ir = &T->ir[ref];
if (ir->r == RID_SUNK) {
MSize j;
for (j = 0; j < n; j++)
if (snap_ref(map[j]) == ref) { /* De-duplicate sunk allocations. */
copyTV(L, o, &frame[snap_slot(map[j])]);
goto dupslot;
}
snap_unsink(J, T, ex, snapno, rfilt, ir, o);
dupslot:
continue;
}
snap_restoreval(J, T, ex, snapno, rfilt, ref, o);
if (LJ_SOFTFP && (sn & SNAP_SOFTFPNUM) && tvisint(o)) {
TValue tmp;
snap_restoreval(J, T, ex, snapno, rfilt, ref+1, &tmp);
o->u32.hi = tmp.u32.lo;
} else if ((sn & (SNAP_CONT|SNAP_FRAME))) {
/* Overwrite tag with frame link. */
o->fr.tp.ftsz = snap_slot(sn) != 0 ? (int32_t)*flinks-- : ftsz0;
L->base = o+1;
}
}
}
lua_assert(map + nent == flinks);
/* Compute current stack top. */
switch (bc_op(*pc)) {
case BC_CALLM: case BC_CALLMT: case BC_RETM: case BC_TSETM:
L->top = frame + snap->nslots;
break;
default:
L->top = curr_topL(L);
break;
}
return pc;
}
#undef IR
#undef emitir_raw
#undef emitir
#endif
-287
View File
@@ -1,287 +0,0 @@
/*
** State and stack handling.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
**
** Portions taken verbatim or adapted from the Lua interpreter.
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#define lj_state_c
#define LUA_CORE
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_func.h"
#include "lj_meta.h"
#include "lj_state.h"
#include "lj_frame.h"
#if LJ_HASFFI
#include "lj_ctype.h"
#endif
#include "lj_trace.h"
#include "lj_dispatch.h"
#include "lj_vm.h"
#include "lj_lex.h"
#include "lj_alloc.h"
/* -- Stack handling ------------------------------------------------------ */
/* Stack sizes. */
#define LJ_STACK_MIN LUA_MINSTACK /* Min. stack size. */
#define LJ_STACK_MAX LUAI_MAXSTACK /* Max. stack size. */
#define LJ_STACK_START (2*LJ_STACK_MIN) /* Starting stack size. */
#define LJ_STACK_MAXEX (LJ_STACK_MAX + 1 + LJ_STACK_EXTRA)
/* Explanation of LJ_STACK_EXTRA:
**
** Calls to metamethods store their arguments beyond the current top
** without checking for the stack limit. This avoids stack resizes which
** would invalidate passed TValue pointers. The stack check is performed
** later by the function header. This can safely resize the stack or raise
** an error. Thus we need some extra slots beyond the current stack limit.
**
** Most metamethods need 4 slots above top (cont, mobj, arg1, arg2) plus
** one extra slot if mobj is not a function. Only lj_meta_tset needs 5
** slots above top, but then mobj is always a function. So we can get by
** with 5 extra slots.
*/
/* Resize stack slots and adjust pointers in state. */
static void resizestack(lua_State *L, MSize n)
{
TValue *st, *oldst = tvref(L->stack);
ptrdiff_t delta;
MSize oldsize = L->stacksize;
MSize realsize = n + 1 + LJ_STACK_EXTRA;
GCobj *up;
lua_assert((MSize)(tvref(L->maxstack)-oldst)==L->stacksize-LJ_STACK_EXTRA-1);
st = (TValue *)lj_mem_realloc(L, tvref(L->stack),
(MSize)(L->stacksize*sizeof(TValue)),
(MSize)(realsize*sizeof(TValue)));
setmref(L->stack, st);
delta = (char *)st - (char *)oldst;
setmref(L->maxstack, st + n);
while (oldsize < realsize) /* Clear new slots. */
setnilV(st + oldsize++);
L->stacksize = realsize;
L->base = (TValue *)((char *)L->base + delta);
L->top = (TValue *)((char *)L->top + delta);
for (up = gcref(L->openupval); up != NULL; up = gcnext(up))
setmref(gco2uv(up)->v, (TValue *)((char *)uvval(gco2uv(up)) + delta));
if (obj2gco(L) == gcref(G(L)->jit_L))
setmref(G(L)->jit_base, mref(G(L)->jit_base, char) + delta);
}
/* Relimit stack after error, in case the limit was overdrawn. */
void lj_state_relimitstack(lua_State *L)
{
if (L->stacksize > LJ_STACK_MAXEX && L->top-tvref(L->stack) < LJ_STACK_MAX-1)
resizestack(L, LJ_STACK_MAX);
}
/* Try to shrink the stack (called from GC). */
void lj_state_shrinkstack(lua_State *L, MSize used)
{
if (L->stacksize > LJ_STACK_MAXEX)
return; /* Avoid stack shrinking while handling stack overflow. */
if (4*used < L->stacksize &&
2*(LJ_STACK_START+LJ_STACK_EXTRA) < L->stacksize &&
obj2gco(L) != gcref(G(L)->jit_L)) /* Don't shrink stack of live trace. */
resizestack(L, L->stacksize >> 1);
}
/* Try to grow stack. */
void LJ_FASTCALL lj_state_growstack(lua_State *L, MSize need)
{
MSize n;
if (L->stacksize > LJ_STACK_MAXEX) /* Overflow while handling overflow? */
lj_err_throw(L, LUA_ERRERR);
n = L->stacksize + need;
if (n > LJ_STACK_MAX) {
n += 2*LUA_MINSTACK;
} else if (n < 2*L->stacksize) {
n = 2*L->stacksize;
if (n >= LJ_STACK_MAX)
n = LJ_STACK_MAX;
}
resizestack(L, n);
if (L->stacksize > LJ_STACK_MAXEX)
lj_err_msg(L, LJ_ERR_STKOV);
}
void LJ_FASTCALL lj_state_growstack1(lua_State *L)
{
lj_state_growstack(L, 1);
}
/* Allocate basic stack for new state. */
static void stack_init(lua_State *L1, lua_State *L)
{
TValue *stend, *st = lj_mem_newvec(L, LJ_STACK_START+LJ_STACK_EXTRA, TValue);
setmref(L1->stack, st);
L1->stacksize = LJ_STACK_START + LJ_STACK_EXTRA;
stend = st + L1->stacksize;
setmref(L1->maxstack, stend - LJ_STACK_EXTRA - 1);
L1->base = L1->top = st+1;
setthreadV(L1, st, L1); /* Needed for curr_funcisL() on empty stack. */
while (st < stend) /* Clear new slots. */
setnilV(st++);
}
/* -- State handling ------------------------------------------------------ */
/* Open parts that may cause memory-allocation errors. */
static TValue *cpluaopen(lua_State *L, lua_CFunction dummy, void *ud)
{
global_State *g = G(L);
UNUSED(dummy);
UNUSED(ud);
stack_init(L, L);
/* NOBARRIER: State initialization, all objects are white. */
setgcref(L->env, obj2gco(lj_tab_new(L, 0, LJ_MIN_GLOBAL)));
settabV(L, registry(L), lj_tab_new(L, 0, LJ_MIN_REGISTRY));
lj_str_resize(L, LJ_MIN_STRTAB-1);
lj_meta_init(L);
lj_lex_init(L);
fixstring(lj_err_str(L, LJ_ERR_ERRMEM)); /* Preallocate memory error msg. */
g->gc.threshold = 4*g->gc.total;
lj_trace_initstate(g);
return NULL;
}
static void close_state(lua_State *L)
{
global_State *g = G(L);
lj_func_closeuv(L, tvref(L->stack));
lj_gc_freeall(g);
lua_assert(gcref(g->gc.root) == obj2gco(L));
lua_assert(g->strnum == 0);
lj_trace_freestate(g);
#if LJ_HASFFI
lj_ctype_freestate(g);
#endif
lj_mem_freevec(g, g->strhash, g->strmask+1, GCRef);
lj_str_freebuf(g, &g->tmpbuf);
lj_mem_freevec(g, tvref(L->stack), L->stacksize, TValue);
lua_assert(g->gc.total == sizeof(GG_State));
#ifndef LUAJIT_USE_SYSMALLOC
if (g->allocf == lj_alloc_f)
lj_alloc_destroy(g->allocd);
else
#endif
g->allocf(g->allocd, G2GG(g), sizeof(GG_State), 0);
}
#if LJ_64
lua_State *lj_state_newstate(lua_Alloc f, void *ud)
#else
LUA_API lua_State *lua_newstate(lua_Alloc f, void *ud)
#endif
{
GG_State *GG = (GG_State *)f(ud, NULL, 0, sizeof(GG_State));
lua_State *L = &GG->L;
global_State *g = &GG->g;
if (GG == NULL || !checkptr32(GG)) return NULL;
memset(GG, 0, sizeof(GG_State));
L->gct = ~LJ_TTHREAD;
L->marked = LJ_GC_WHITE0 | LJ_GC_FIXED | LJ_GC_SFIXED; /* Prevent free. */
L->dummy_ffid = FF_C;
setmref(L->glref, g);
g->gc.currentwhite = LJ_GC_WHITE0 | LJ_GC_FIXED;
g->strempty.marked = LJ_GC_WHITE0;
g->strempty.gct = ~LJ_TSTR;
g->allocf = f;
g->allocd = ud;
setgcref(g->mainthref, obj2gco(L));
setgcref(g->uvhead.prev, obj2gco(&g->uvhead));
setgcref(g->uvhead.next, obj2gco(&g->uvhead));
g->strmask = ~(MSize)0;
setnilV(registry(L));
setnilV(&g->nilnode.val);
setnilV(&g->nilnode.key);
setmref(g->nilnode.freetop, &g->nilnode);
lj_str_initbuf(&g->tmpbuf);
g->gc.state = GCSpause;
setgcref(g->gc.root, obj2gco(L));
setmref(g->gc.sweep, &g->gc.root);
g->gc.total = sizeof(GG_State);
g->gc.pause = LUAI_GCPAUSE;
g->gc.stepmul = LUAI_GCMUL;
lj_dispatch_init((GG_State *)L);
L->status = LUA_ERRERR+1; /* Avoid touching the stack upon memory error. */
if (lj_vm_cpcall(L, NULL, NULL, cpluaopen) != 0) {
/* Memory allocation error: free partial state. */
close_state(L);
return NULL;
}
L->status = 0;
return L;
}
static TValue *cpfinalize(lua_State *L, lua_CFunction dummy, void *ud)
{
UNUSED(dummy);
UNUSED(ud);
lj_gc_finalize_cdata(L);
lj_gc_finalize_udata(L);
/* Frame pop omitted. */
return NULL;
}
LUA_API void lua_close(lua_State *L)
{
global_State *g = G(L);
int i;
L = mainthread(g); /* Only the main thread can be closed. */
lj_func_closeuv(L, tvref(L->stack));
lj_gc_separateudata(g, 1); /* Separate udata which have GC metamethods. */
#if LJ_HASJIT
G2J(g)->flags &= ~JIT_F_ON;
G2J(g)->state = LJ_TRACE_IDLE;
lj_dispatch_update(g);
#endif
for (i = 0;;) {
hook_enter(g);
L->status = 0;
L->cframe = NULL;
L->base = L->top = tvref(L->stack) + 1;
if (lj_vm_cpcall(L, NULL, NULL, cpfinalize) == 0) {
if (++i >= 10) break;
lj_gc_separateudata(g, 1); /* Separate udata again. */
if (gcref(g->gc.mmudata) == NULL) /* Until nothing is left to do. */
break;
}
}
close_state(L);
}
lua_State *lj_state_new(lua_State *L)
{
lua_State *L1 = lj_mem_newobj(L, lua_State);
L1->gct = ~LJ_TTHREAD;
L1->dummy_ffid = FF_C;
L1->status = 0;
L1->stacksize = 0;
setmref(L1->stack, NULL);
L1->cframe = NULL;
/* NOBARRIER: The lua_State is new (marked white). */
setgcrefnull(L1->openupval);
setmrefr(L1->glref, L->glref);
setgcrefr(L1->env, L->env);
stack_init(L1, L); /* init stack */
lua_assert(iswhite(obj2gco(L1)));
return L1;
}
void LJ_FASTCALL lj_state_free(global_State *g, lua_State *L)
{
lua_assert(L != mainthread(g));
lj_func_closeuv(L, tvref(L->stack));
lua_assert(gcref(L->openupval) == NULL);
lj_mem_freevec(g, tvref(L->stack), L->stacksize, TValue);
lj_mem_freet(g, L);
}
-339
View File
@@ -1,339 +0,0 @@
/*
** String handling.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
**
** Portions taken verbatim or adapted from the Lua interpreter.
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#include <stdio.h>
#define lj_str_c
#define LUA_CORE
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_str.h"
#include "lj_state.h"
#include "lj_char.h"
/* -- String interning ---------------------------------------------------- */
/* Ordered compare of strings. Assumes string data is 4-byte aligned. */
int32_t LJ_FASTCALL lj_str_cmp(GCstr *a, GCstr *b)
{
MSize i, n = a->len > b->len ? b->len : a->len;
for (i = 0; i < n; i += 4) {
/* Note: innocuous access up to end of string + 3. */
uint32_t va = *(const uint32_t *)(strdata(a)+i);
uint32_t vb = *(const uint32_t *)(strdata(b)+i);
if (va != vb) {
#if LJ_LE
va = lj_bswap(va); vb = lj_bswap(vb);
#endif
i -= n;
if ((int32_t)i >= -3) {
va >>= 32+(i<<3); vb >>= 32+(i<<3);
if (va == vb) break;
}
return va < vb ? -1 : 1;
}
}
return (int32_t)(a->len - b->len);
}
/* Fast string data comparison. Caveat: unaligned access to 1st string! */
static LJ_AINLINE int str_fastcmp(const char *a, const char *b, MSize len)
{
MSize i = 0;
lua_assert(len > 0);
lua_assert((((uintptr_t)a + len) & (LJ_PAGESIZE-1)) <= LJ_PAGESIZE-4);
do { /* Note: innocuous access up to end of string + 3. */
uint32_t v = lj_getu32(a+i) ^ *(const uint32_t *)(b+i);
if (v) {
i -= len;
#if LJ_LE
return (int32_t)i >= -3 ? (v << (32+(i<<3))) : 1;
#else
return (int32_t)i >= -3 ? (v >> (32+(i<<3))) : 1;
#endif
}
i += 4;
} while (i < len);
return 0;
}
/* Resize the string hash table (grow and shrink). */
void lj_str_resize(lua_State *L, MSize newmask)
{
global_State *g = G(L);
GCRef *newhash;
MSize i;
if (g->gc.state == GCSsweepstring || newmask >= LJ_MAX_STRTAB-1)
return; /* No resizing during GC traversal or if already too big. */
newhash = lj_mem_newvec(L, newmask+1, GCRef);
memset(newhash, 0, (newmask+1)*sizeof(GCRef));
for (i = g->strmask; i != ~(MSize)0; i--) { /* Rehash old table. */
GCobj *p = gcref(g->strhash[i]);
while (p) { /* Follow each hash chain and reinsert all strings. */
MSize h = gco2str(p)->hash & newmask;
GCobj *next = gcnext(p);
/* NOBARRIER: The string table is a GC root. */
setgcrefr(p->gch.nextgc, newhash[h]);
setgcref(newhash[h], p);
p = next;
}
}
lj_mem_freevec(g, g->strhash, g->strmask+1, GCRef);
g->strmask = newmask;
g->strhash = newhash;
}
/* Intern a string and return string object. */
GCstr *lj_str_new(lua_State *L, const char *str, size_t lenx)
{
global_State *g;
GCstr *s;
GCobj *o;
MSize len = (MSize)lenx;
MSize a, b, h = len;
if (lenx >= LJ_MAX_STR)
lj_err_msg(L, LJ_ERR_STROV);
g = G(L);
/* Compute string hash. Constants taken from lookup3 hash by Bob Jenkins. */
if (len >= 4) { /* Caveat: unaligned access! */
a = lj_getu32(str);
h ^= lj_getu32(str+len-4);
b = lj_getu32(str+(len>>1)-2);
h ^= b; h -= lj_rol(b, 14);
b += lj_getu32(str+(len>>2)-1);
} else if (len > 0) {
a = *(const uint8_t *)str;
h ^= *(const uint8_t *)(str+len-1);
b = *(const uint8_t *)(str+(len>>1));
h ^= b; h -= lj_rol(b, 14);
} else {
return &g->strempty;
}
a ^= h; a -= lj_rol(h, 11);
b ^= a; b -= lj_rol(a, 25);
h ^= b; h -= lj_rol(b, 16);
/* Check if the string has already been interned. */
o = gcref(g->strhash[h & g->strmask]);
if (LJ_LIKELY((((uintptr_t)str + len) & (LJ_PAGESIZE-1)) <= LJ_PAGESIZE-4)) {
while (o != NULL) {
GCstr *sx = gco2str(o);
if (sx->len == len && str_fastcmp(str, strdata(sx), len) == 0) {
/* Resurrect if dead. Can only happen with fixstring() (keywords). */
if (isdead(g, o)) flipwhite(o);
return sx; /* Return existing string. */
}
o = gcnext(o);
}
} else { /* Slow path: end of string is too close to a page boundary. */
while (o != NULL) {
GCstr *sx = gco2str(o);
if (sx->len == len && memcmp(str, strdata(sx), len) == 0) {
/* Resurrect if dead. Can only happen with fixstring() (keywords). */
if (isdead(g, o)) flipwhite(o);
return sx; /* Return existing string. */
}
o = gcnext(o);
}
}
/* Nope, create a new string. */
s = lj_mem_newt(L, sizeof(GCstr)+len+1, GCstr);
newwhite(g, s);
s->gct = ~LJ_TSTR;
s->len = len;
s->hash = h;
s->reserved = 0;
memcpy(strdatawr(s), str, len);
strdatawr(s)[len] = '\0'; /* Zero-terminate string. */
/* Add it to string hash table. */
h &= g->strmask;
s->nextgc = g->strhash[h];
/* NOBARRIER: The string table is a GC root. */
setgcref(g->strhash[h], obj2gco(s));
if (g->strnum++ > g->strmask) /* Allow a 100% load factor. */
lj_str_resize(L, (g->strmask<<1)+1); /* Grow string table. */
return s; /* Return newly interned string. */
}
void LJ_FASTCALL lj_str_free(global_State *g, GCstr *s)
{
g->strnum--;
lj_mem_free(g, s, sizestring(s));
}
/* -- Type conversions ---------------------------------------------------- */
/* Print number to buffer. Canonicalizes non-finite values. */
size_t LJ_FASTCALL lj_str_bufnum(char *s, cTValue *o)
{
if (LJ_LIKELY((o->u32.hi << 1) < 0xffe00000)) { /* Finite? */
lua_Number n = o->n;
#if __BIONIC__
if (tvismzero(o)) { s[0] = '-'; s[1] = '0'; return 2; }
#endif
return (size_t)lua_number2str(s, n);
} else if (((o->u32.hi & 0x000fffff) | o->u32.lo) != 0) {
s[0] = 'n'; s[1] = 'a'; s[2] = 'n'; return 3;
} else if ((o->u32.hi & 0x80000000) == 0) {
s[0] = 'i'; s[1] = 'n'; s[2] = 'f'; return 3;
} else {
s[0] = '-'; s[1] = 'i'; s[2] = 'n'; s[3] = 'f'; return 4;
}
}
/* Print integer to buffer. Returns pointer to start. */
char * LJ_FASTCALL lj_str_bufint(char *p, int32_t k)
{
uint32_t u = (uint32_t)(k < 0 ? -k : k);
p += 1+10;
do { *--p = (char)('0' + u % 10); } while (u /= 10);
if (k < 0) *--p = '-';
return p;
}
/* Convert number to string. */
GCstr * LJ_FASTCALL lj_str_fromnum(lua_State *L, const lua_Number *np)
{
char buf[LJ_STR_NUMBUF];
size_t len = lj_str_bufnum(buf, (TValue *)np);
return lj_str_new(L, buf, len);
}
/* Convert integer to string. */
GCstr * LJ_FASTCALL lj_str_fromint(lua_State *L, int32_t k)
{
char s[1+10];
char *p = lj_str_bufint(s, k);
return lj_str_new(L, p, (size_t)(s+sizeof(s)-p));
}
GCstr * LJ_FASTCALL lj_str_fromnumber(lua_State *L, cTValue *o)
{
return tvisint(o) ? lj_str_fromint(L, intV(o)) : lj_str_fromnum(L, &o->n);
}
/* -- String formatting --------------------------------------------------- */
static void addstr(lua_State *L, SBuf *sb, const char *str, MSize len)
{
char *p;
MSize i;
if (sb->n + len > sb->sz) {
MSize sz = sb->sz * 2;
while (sb->n + len > sz) sz = sz * 2;
lj_str_resizebuf(L, sb, sz);
}
p = sb->buf + sb->n;
sb->n += len;
for (i = 0; i < len; i++) p[i] = str[i];
}
static void addchar(lua_State *L, SBuf *sb, int c)
{
if (sb->n + 1 > sb->sz) {
MSize sz = sb->sz * 2;
lj_str_resizebuf(L, sb, sz);
}
sb->buf[sb->n++] = (char)c;
}
/* Push formatted message as a string object to Lua stack. va_list variant. */
const char *lj_str_pushvf(lua_State *L, const char *fmt, va_list argp)
{
SBuf *sb = &G(L)->tmpbuf;
lj_str_needbuf(L, sb, (MSize)strlen(fmt));
lj_str_resetbuf(sb);
for (;;) {
const char *e = strchr(fmt, '%');
if (e == NULL) break;
addstr(L, sb, fmt, (MSize)(e-fmt));
/* This function only handles %s, %c, %d, %f and %p formats. */
switch (e[1]) {
case 's': {
const char *s = va_arg(argp, char *);
if (s == NULL) s = "(null)";
addstr(L, sb, s, (MSize)strlen(s));
break;
}
case 'c':
addchar(L, sb, va_arg(argp, int));
break;
case 'd': {
char buf[LJ_STR_INTBUF];
char *p = lj_str_bufint(buf, va_arg(argp, int32_t));
addstr(L, sb, p, (MSize)(buf+LJ_STR_INTBUF-p));
break;
}
case 'f': {
char buf[LJ_STR_NUMBUF];
TValue tv;
MSize len;
tv.n = (lua_Number)(va_arg(argp, LUAI_UACNUMBER));
len = (MSize)lj_str_bufnum(buf, &tv);
addstr(L, sb, buf, len);
break;
}
case 'p': {
#define FMTP_CHARS (2*sizeof(ptrdiff_t))
char buf[2+FMTP_CHARS];
ptrdiff_t p = (ptrdiff_t)(va_arg(argp, void *));
ptrdiff_t i, lasti = 2+FMTP_CHARS;
if (p == 0) {
addstr(L, sb, "NULL", 4);
break;
}
#if LJ_64
/* Shorten output for 64 bit pointers. */
lasti = 2+2*4+((p >> 32) ? 2+2*(lj_fls((uint32_t)(p >> 32))>>3) : 0);
#endif
buf[0] = '0';
buf[1] = 'x';
for (i = lasti-1; i >= 2; i--, p >>= 4)
buf[i] = "0123456789abcdef"[(p & 15)];
addstr(L, sb, buf, (MSize)lasti);
break;
}
case '%':
addchar(L, sb, '%');
break;
default:
addchar(L, sb, '%');
addchar(L, sb, e[1]);
break;
}
fmt = e+2;
}
addstr(L, sb, fmt, (MSize)strlen(fmt));
setstrV(L, L->top, lj_str_new(L, sb->buf, sb->n));
incr_top(L);
return strVdata(L->top - 1);
}
/* Push formatted message as a string object to Lua stack. Vararg variant. */
const char *lj_str_pushf(lua_State *L, const char *fmt, ...)
{
const char *msg;
va_list argp;
va_start(argp, fmt);
msg = lj_str_pushvf(L, fmt, argp);
va_end(argp);
return msg;
}
/* -- Buffer handling ----------------------------------------------------- */
char *lj_str_needbuf(lua_State *L, SBuf *sb, MSize sz)
{
if (sz > sb->sz) {
if (sz < LJ_MIN_SBUF) sz = LJ_MIN_SBUF;
lj_str_resizebuf(L, sb, sz);
}
return sb->buf;
}
-50
View File
@@ -1,50 +0,0 @@
/*
** String handling.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_STR_H
#define _LJ_STR_H
#include <stdarg.h>
#include "lj_obj.h"
/* String interning. */
LJ_FUNC int32_t LJ_FASTCALL lj_str_cmp(GCstr *a, GCstr *b);
LJ_FUNC void lj_str_resize(lua_State *L, MSize newmask);
LJ_FUNCA GCstr *lj_str_new(lua_State *L, const char *str, size_t len);
LJ_FUNC void LJ_FASTCALL lj_str_free(global_State *g, GCstr *s);
#define lj_str_newz(L, s) (lj_str_new(L, s, strlen(s)))
#define lj_str_newlit(L, s) (lj_str_new(L, "" s, sizeof(s)-1))
/* Type conversions. */
LJ_FUNC size_t LJ_FASTCALL lj_str_bufnum(char *s, cTValue *o);
LJ_FUNC char * LJ_FASTCALL lj_str_bufint(char *p, int32_t k);
LJ_FUNCA GCstr * LJ_FASTCALL lj_str_fromnum(lua_State *L, const lua_Number *np);
LJ_FUNC GCstr * LJ_FASTCALL lj_str_fromint(lua_State *L, int32_t k);
LJ_FUNCA GCstr * LJ_FASTCALL lj_str_fromnumber(lua_State *L, cTValue *o);
#define LJ_STR_INTBUF (1+10)
#define LJ_STR_NUMBUF LUAI_MAXNUMBER2STR
/* String formatting. */
LJ_FUNC const char *lj_str_pushvf(lua_State *L, const char *fmt, va_list argp);
LJ_FUNC const char *lj_str_pushf(lua_State *L, const char *fmt, ...)
#if defined(__GNUC__)
__attribute__ ((format (printf, 2, 3)))
#endif
;
/* Resizable string buffers. Struct definition in lj_obj.h. */
LJ_FUNC char *lj_str_needbuf(lua_State *L, SBuf *sb, MSize sz);
#define lj_str_initbuf(sb) ((sb)->buf = NULL, (sb)->sz = 0)
#define lj_str_resetbuf(sb) ((sb)->n = 0)
#define lj_str_resizebuf(L, sb, size) \
((sb)->buf = (char *)lj_mem_realloc(L, (sb)->buf, (sb)->sz, (size)), \
(sb)->sz = (size))
#define lj_str_freebuf(g, sb) lj_mem_free(g, (void *)(sb)->buf, (sb)->sz)
#endif
-624
View File
@@ -1,624 +0,0 @@
/*
** Table handling.
** Copyright (C) 2005-2013 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 lj_tab_c
#define LUA_CORE
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_tab.h"
/* -- Object hashing ------------------------------------------------------ */
/* Hash values are masked with the table hash mask and used as an index. */
static LJ_AINLINE Node *hashmask(const GCtab *t, uint32_t hash)
{
Node *n = noderef(t->node);
return &n[hash & t->hmask];
}
/* String hashes are precomputed when they are interned. */
#define hashstr(t, s) hashmask(t, (s)->hash)
#define hashlohi(t, lo, hi) hashmask((t), hashrot((lo), (hi)))
#define hashnum(t, o) hashlohi((t), (o)->u32.lo, ((o)->u32.hi << 1))
#define hashptr(t, p) hashlohi((t), u32ptr(p), u32ptr(p) + HASH_BIAS)
#define hashgcref(t, r) hashlohi((t), gcrefu(r), gcrefu(r) + HASH_BIAS)
/* Hash an arbitrary key and return its anchor position in the hash table. */
static Node *hashkey(const GCtab *t, cTValue *key)
{
lua_assert(!tvisint(key));
if (tvisstr(key))
return hashstr(t, strV(key));
else if (tvisnum(key))
return hashnum(t, key);
else if (tvisbool(key))
return hashmask(t, boolV(key));
else
return hashgcref(t, key->gcr);
/* Only hash 32 bits of lightuserdata on a 64 bit CPU. Good enough? */
}
/* -- Table creation and destruction -------------------------------------- */
/* Create new hash part for table. */
static LJ_AINLINE void newhpart(lua_State *L, GCtab *t, uint32_t hbits)
{
uint32_t hsize;
Node *node;
lua_assert(hbits != 0);
if (hbits > LJ_MAX_HBITS)
lj_err_msg(L, LJ_ERR_TABOV);
hsize = 1u << hbits;
node = lj_mem_newvec(L, hsize, Node);
setmref(node->freetop, &node[hsize]);
setmref(t->node, node);
t->hmask = hsize-1;
}
/*
** Q: Why all of these copies of t->hmask, t->node etc. to local variables?
** A: Because alias analysis for C is _really_ tough.
** Even state-of-the-art C compilers won't produce good code without this.
*/
/* Clear hash part of table. */
static LJ_AINLINE void clearhpart(GCtab *t)
{
uint32_t i, hmask = t->hmask;
Node *node = noderef(t->node);
lua_assert(t->hmask != 0);
for (i = 0; i <= hmask; i++) {
Node *n = &node[i];
setmref(n->next, NULL);
setnilV(&n->key);
setnilV(&n->val);
}
}
/* Clear array part of table. */
static LJ_AINLINE void clearapart(GCtab *t)
{
uint32_t i, asize = t->asize;
TValue *array = tvref(t->array);
for (i = 0; i < asize; i++)
setnilV(&array[i]);
}
/* Create a new table. Note: the slots are not initialized (yet). */
static GCtab *newtab(lua_State *L, uint32_t asize, uint32_t hbits)
{
GCtab *t;
/* First try to colocate the array part. */
if (LJ_MAX_COLOSIZE != 0 && asize > 0 && asize <= LJ_MAX_COLOSIZE) {
lua_assert((sizeof(GCtab) & 7) == 0);
t = (GCtab *)lj_mem_newgco(L, sizetabcolo(asize));
t->gct = ~LJ_TTAB;
t->nomm = (uint8_t)~0;
t->colo = (int8_t)asize;
setmref(t->array, (TValue *)((char *)t + sizeof(GCtab)));
setgcrefnull(t->metatable);
t->asize = asize;
t->hmask = 0;
setmref(t->node, &G(L)->nilnode);
} else { /* Otherwise separately allocate the array part. */
t = lj_mem_newobj(L, GCtab);
t->gct = ~LJ_TTAB;
t->nomm = (uint8_t)~0;
t->colo = 0;
setmref(t->array, NULL);
setgcrefnull(t->metatable);
t->asize = 0; /* In case the array allocation fails. */
t->hmask = 0;
setmref(t->node, &G(L)->nilnode);
if (asize > 0) {
if (asize > LJ_MAX_ASIZE)
lj_err_msg(L, LJ_ERR_TABOV);
setmref(t->array, lj_mem_newvec(L, asize, TValue));
t->asize = asize;
}
}
if (hbits)
newhpart(L, t, hbits);
return t;
}
/* Create a new table.
**
** IMPORTANT NOTE: The API differs from lua_createtable()!
**
** The array size is non-inclusive. E.g. asize=128 creates array slots
** for 0..127, but not for 128. If you need slots 1..128, pass asize=129
** (slot 0 is wasted in this case).
**
** The hash size is given in hash bits. hbits=0 means no hash part.
** hbits=1 creates 2 hash slots, hbits=2 creates 4 hash slots and so on.
*/
GCtab *lj_tab_new(lua_State *L, uint32_t asize, uint32_t hbits)
{
GCtab *t = newtab(L, asize, hbits);
clearapart(t);
if (t->hmask > 0) clearhpart(t);
return t;
}
#if LJ_HASJIT
GCtab * LJ_FASTCALL lj_tab_new1(lua_State *L, uint32_t ahsize)
{
GCtab *t = newtab(L, ahsize & 0xffffff, ahsize >> 24);
clearapart(t);
if (t->hmask > 0) clearhpart(t);
return t;
}
#endif
/* Duplicate a table. */
GCtab * LJ_FASTCALL lj_tab_dup(lua_State *L, const GCtab *kt)
{
GCtab *t;
uint32_t asize, hmask;
t = newtab(L, kt->asize, kt->hmask > 0 ? lj_fls(kt->hmask)+1 : 0);
lua_assert(kt->asize == t->asize && kt->hmask == t->hmask);
t->nomm = 0; /* Keys with metamethod names may be present. */
asize = kt->asize;
if (asize > 0) {
TValue *array = tvref(t->array);
TValue *karray = tvref(kt->array);
if (asize < 64) { /* An inlined loop beats memcpy for < 512 bytes. */
uint32_t i;
for (i = 0; i < asize; i++)
copyTV(L, &array[i], &karray[i]);
} else {
memcpy(array, karray, asize*sizeof(TValue));
}
}
hmask = kt->hmask;
if (hmask > 0) {
uint32_t i;
Node *node = noderef(t->node);
Node *knode = noderef(kt->node);
ptrdiff_t d = (char *)node - (char *)knode;
setmref(node->freetop, (Node *)((char *)noderef(knode->freetop) + d));
for (i = 0; i <= hmask; i++) {
Node *kn = &knode[i];
Node *n = &node[i];
Node *next = nextnode(kn);
/* Don't use copyTV here, since it asserts on a copy of a dead key. */
n->val = kn->val; n->key = kn->key;
setmref(n->next, next == NULL? next : (Node *)((char *)next + d));
}
}
return t;
}
/* Free a table. */
void LJ_FASTCALL lj_tab_free(global_State *g, GCtab *t)
{
if (t->hmask > 0)
lj_mem_freevec(g, noderef(t->node), t->hmask+1, Node);
if (t->asize > 0 && LJ_MAX_COLOSIZE != 0 && t->colo <= 0)
lj_mem_freevec(g, tvref(t->array), t->asize, TValue);
if (LJ_MAX_COLOSIZE != 0 && t->colo)
lj_mem_free(g, t, sizetabcolo((uint32_t)t->colo & 0x7f));
else
lj_mem_freet(g, t);
}
/* -- Table resizing ------------------------------------------------------ */
/* Resize a table to fit the new array/hash part sizes. */
static void resizetab(lua_State *L, GCtab *t, uint32_t asize, uint32_t hbits)
{
Node *oldnode = noderef(t->node);
uint32_t oldasize = t->asize;
uint32_t oldhmask = t->hmask;
if (asize > oldasize) { /* Array part grows? */
TValue *array;
uint32_t i;
if (asize > LJ_MAX_ASIZE)
lj_err_msg(L, LJ_ERR_TABOV);
if (LJ_MAX_COLOSIZE != 0 && t->colo > 0) {
/* A colocated array must be separated and copied. */
TValue *oarray = tvref(t->array);
array = lj_mem_newvec(L, asize, TValue);
t->colo = (int8_t)(t->colo | 0x80); /* Mark as separated (colo < 0). */
for (i = 0; i < oldasize; i++)
copyTV(L, &array[i], &oarray[i]);
} else {
array = (TValue *)lj_mem_realloc(L, tvref(t->array),
oldasize*sizeof(TValue), asize*sizeof(TValue));
}
setmref(t->array, array);
t->asize = asize;
for (i = oldasize; i < asize; i++) /* Clear newly allocated slots. */
setnilV(&array[i]);
}
/* Create new (empty) hash part. */
if (hbits) {
newhpart(L, t, hbits);
clearhpart(t);
} else {
global_State *g = G(L);
setmref(t->node, &g->nilnode);
t->hmask = 0;
}
if (asize < oldasize) { /* Array part shrinks? */
TValue *array = tvref(t->array);
uint32_t i;
t->asize = asize; /* Note: This 'shrinks' even colocated arrays. */
for (i = asize; i < oldasize; i++) /* Reinsert old array values. */
if (!tvisnil(&array[i]))
copyTV(L, lj_tab_setinth(L, t, (int32_t)i), &array[i]);
/* Physically shrink only separated arrays. */
if (LJ_MAX_COLOSIZE != 0 && t->colo <= 0)
setmref(t->array, lj_mem_realloc(L, array,
oldasize*sizeof(TValue), asize*sizeof(TValue)));
}
if (oldhmask > 0) { /* Reinsert pairs from old hash part. */
global_State *g;
uint32_t i;
for (i = 0; i <= oldhmask; i++) {
Node *n = &oldnode[i];
if (!tvisnil(&n->val))
copyTV(L, lj_tab_set(L, t, &n->key), &n->val);
}
g = G(L);
lj_mem_freevec(g, oldnode, oldhmask+1, Node);
}
}
static uint32_t countint(cTValue *key, uint32_t *bins)
{
lua_assert(!tvisint(key));
if (tvisnum(key)) {
lua_Number nk = numV(key);
int32_t k = lj_num2int(nk);
if ((uint32_t)k < LJ_MAX_ASIZE && nk == (lua_Number)k) {
bins[(k > 2 ? lj_fls((uint32_t)(k-1)) : 0)]++;
return 1;
}
}
return 0;
}
static uint32_t countarray(const GCtab *t, uint32_t *bins)
{
uint32_t na, b, i;
if (t->asize == 0) return 0;
for (na = i = b = 0; b < LJ_MAX_ABITS; b++) {
uint32_t n, top = 2u << b;
TValue *array;
if (top >= t->asize) {
top = t->asize-1;
if (i > top)
break;
}
array = tvref(t->array);
for (n = 0; i <= top; i++)
if (!tvisnil(&array[i]))
n++;
bins[b] += n;
na += n;
}
return na;
}
static uint32_t counthash(const GCtab *t, uint32_t *bins, uint32_t *narray)
{
uint32_t total, na, i, hmask = t->hmask;
Node *node = noderef(t->node);
for (total = na = 0, i = 0; i <= hmask; i++) {
Node *n = &node[i];
if (!tvisnil(&n->val)) {
na += countint(&n->key, bins);
total++;
}
}
*narray += na;
return total;
}
static uint32_t bestasize(uint32_t bins[], uint32_t *narray)
{
uint32_t b, sum, na = 0, sz = 0, nn = *narray;
for (b = 0, sum = 0; 2*nn > (1u<<b) && sum != nn; b++)
if (bins[b] > 0 && 2*(sum += bins[b]) > (1u<<b)) {
sz = (2u<<b)+1;
na = sum;
}
*narray = sz;
return na;
}
static void rehashtab(lua_State *L, GCtab *t, cTValue *ek)
{
uint32_t bins[LJ_MAX_ABITS];
uint32_t total, asize, na, i;
for (i = 0; i < LJ_MAX_ABITS; i++) bins[i] = 0;
asize = countarray(t, bins);
total = 1 + asize;
total += counthash(t, bins, &asize);
asize += countint(ek, bins);
na = bestasize(bins, &asize);
total -= na;
resizetab(L, t, asize, hsize2hbits(total));
}
void lj_tab_reasize(lua_State *L, GCtab *t, uint32_t nasize)
{
resizetab(L, t, nasize+1, t->hmask > 0 ? lj_fls(t->hmask)+1 : 0);
}
/* -- Table getters ------------------------------------------------------- */
cTValue * LJ_FASTCALL lj_tab_getinth(GCtab *t, int32_t key)
{
TValue k;
Node *n;
k.n = (lua_Number)key;
n = hashnum(t, &k);
do {
if (tvisnum(&n->key) && n->key.n == k.n)
return &n->val;
} while ((n = nextnode(n)));
return NULL;
}
cTValue *lj_tab_getstr(GCtab *t, GCstr *key)
{
Node *n = hashstr(t, key);
do {
if (tvisstr(&n->key) && strV(&n->key) == key)
return &n->val;
} while ((n = nextnode(n)));
return NULL;
}
cTValue *lj_tab_get(lua_State *L, GCtab *t, cTValue *key)
{
if (tvisstr(key)) {
cTValue *tv = lj_tab_getstr(t, strV(key));
if (tv)
return tv;
} else if (tvisint(key)) {
cTValue *tv = lj_tab_getint(t, intV(key));
if (tv)
return tv;
} else if (tvisnum(key)) {
lua_Number nk = numV(key);
int32_t k = lj_num2int(nk);
if (nk == (lua_Number)k) {
cTValue *tv = lj_tab_getint(t, k);
if (tv)
return tv;
} else {
goto genlookup; /* Else use the generic lookup. */
}
} else if (!tvisnil(key)) {
Node *n;
genlookup:
n = hashkey(t, key);
do {
if (lj_obj_equal(&n->key, key))
return &n->val;
} while ((n = nextnode(n)));
}
return niltv(L);
}
/* -- Table setters ------------------------------------------------------- */
/* Insert new key. Use Brent's variation to optimize the chain length. */
TValue *lj_tab_newkey(lua_State *L, GCtab *t, cTValue *key)
{
Node *n = hashkey(t, key);
if (!tvisnil(&n->val) || t->hmask == 0) {
Node *nodebase = noderef(t->node);
Node *collide, *freenode = noderef(nodebase->freetop);
lua_assert(freenode >= nodebase && freenode <= nodebase+t->hmask+1);
do {
if (freenode == nodebase) { /* No free node found? */
rehashtab(L, t, key); /* Rehash table. */
return lj_tab_set(L, t, key); /* Retry key insertion. */
}
} while (!tvisnil(&(--freenode)->key));
setmref(nodebase->freetop, freenode);
lua_assert(freenode != &G(L)->nilnode);
collide = hashkey(t, &n->key);
if (collide != n) { /* Colliding node not the main node? */
while (noderef(collide->next) != n) /* Find predecessor. */
collide = nextnode(collide);
setmref(collide->next, freenode); /* Relink chain. */
/* Copy colliding node into free node and free main node. */
freenode->val = n->val;
freenode->key = n->key;
freenode->next = n->next;
setmref(n->next, NULL);
setnilV(&n->val);
/* Rechain pseudo-resurrected string keys with colliding hashes. */
while (nextnode(freenode)) {
Node *nn = nextnode(freenode);
if (tvisstr(&nn->key) && !tvisnil(&nn->val) &&
hashstr(t, strV(&nn->key)) == n) {
freenode->next = nn->next;
nn->next = n->next;
setmref(n->next, nn);
} else {
freenode = nn;
}
}
} else { /* Otherwise use free node. */
setmrefr(freenode->next, n->next); /* Insert into chain. */
setmref(n->next, freenode);
n = freenode;
}
}
n->key.u64 = key->u64;
if (LJ_UNLIKELY(tvismzero(&n->key)))
n->key.u64 = 0;
lj_gc_anybarriert(L, t);
lua_assert(tvisnil(&n->val));
return &n->val;
}
TValue *lj_tab_setinth(lua_State *L, GCtab *t, int32_t key)
{
TValue k;
Node *n;
k.n = (lua_Number)key;
n = hashnum(t, &k);
do {
if (tvisnum(&n->key) && n->key.n == k.n)
return &n->val;
} while ((n = nextnode(n)));
return lj_tab_newkey(L, t, &k);
}
TValue *lj_tab_setstr(lua_State *L, GCtab *t, GCstr *key)
{
TValue k;
Node *n = hashstr(t, key);
do {
if (tvisstr(&n->key) && strV(&n->key) == key)
return &n->val;
} while ((n = nextnode(n)));
setstrV(L, &k, key);
return lj_tab_newkey(L, t, &k);
}
TValue *lj_tab_set(lua_State *L, GCtab *t, cTValue *key)
{
Node *n;
t->nomm = 0; /* Invalidate negative metamethod cache. */
if (tvisstr(key)) {
return lj_tab_setstr(L, t, strV(key));
} else if (tvisint(key)) {
return lj_tab_setint(L, t, intV(key));
} else if (tvisnum(key)) {
lua_Number nk = numV(key);
int32_t k = lj_num2int(nk);
if (nk == (lua_Number)k)
return lj_tab_setint(L, t, k);
if (tvisnan(key))
lj_err_msg(L, LJ_ERR_NANIDX);
/* Else use the generic lookup. */
} else if (tvisnil(key)) {
lj_err_msg(L, LJ_ERR_NILIDX);
}
n = hashkey(t, key);
do {
if (lj_obj_equal(&n->key, key))
return &n->val;
} while ((n = nextnode(n)));
return lj_tab_newkey(L, t, key);
}
/* -- Table traversal ----------------------------------------------------- */
/* Get the traversal index of a key. */
static uint32_t keyindex(lua_State *L, GCtab *t, cTValue *key)
{
TValue tmp;
if (tvisint(key)) {
int32_t k = intV(key);
if ((uint32_t)k < t->asize)
return (uint32_t)k; /* Array key indexes: [0..t->asize-1] */
setnumV(&tmp, (lua_Number)k);
key = &tmp;
} else if (tvisnum(key)) {
lua_Number nk = numV(key);
int32_t k = lj_num2int(nk);
if ((uint32_t)k < t->asize && nk == (lua_Number)k)
return (uint32_t)k; /* Array key indexes: [0..t->asize-1] */
}
if (!tvisnil(key)) {
Node *n = hashkey(t, key);
do {
if (lj_obj_equal(&n->key, key))
return t->asize + (uint32_t)(n - noderef(t->node));
/* Hash key indexes: [t->asize..t->asize+t->nmask] */
} while ((n = nextnode(n)));
if (key->u32.hi == 0xfffe7fff) /* ITERN was despecialized while running. */
return key->u32.lo - 1;
lj_err_msg(L, LJ_ERR_NEXTIDX);
return 0; /* unreachable */
}
return ~0u; /* A nil key starts the traversal. */
}
/* Advance to the next step in a table traversal. */
int lj_tab_next(lua_State *L, GCtab *t, TValue *key)
{
uint32_t i = keyindex(L, t, key); /* Find predecessor key index. */
for (i++; i < t->asize; i++) /* First traverse the array keys. */
if (!tvisnil(arrayslot(t, i))) {
setintV(key, i);
copyTV(L, key+1, arrayslot(t, i));
return 1;
}
for (i -= t->asize; i <= t->hmask; i++) { /* Then traverse the hash keys. */
Node *n = &noderef(t->node)[i];
if (!tvisnil(&n->val)) {
copyTV(L, key, &n->key);
copyTV(L, key+1, &n->val);
return 1;
}
}
return 0; /* End of traversal. */
}
/* -- Table length calculation -------------------------------------------- */
static MSize unbound_search(GCtab *t, MSize j)
{
cTValue *tv;
MSize i = j; /* i is zero or a present index */
j++;
/* find `i' and `j' such that i is present and j is not */
while ((tv = lj_tab_getint(t, (int32_t)j)) && !tvisnil(tv)) {
i = j;
j *= 2;
if (j > (MSize)(INT_MAX-2)) { /* overflow? */
/* table was built with bad purposes: resort to linear search */
i = 1;
while ((tv = lj_tab_getint(t, (int32_t)i)) && !tvisnil(tv)) i++;
return i - 1;
}
}
/* now do a binary search between them */
while (j - i > 1) {
MSize m = (i+j)/2;
cTValue *tvb = lj_tab_getint(t, (int32_t)m);
if (tvb && !tvisnil(tvb)) i = m; else j = m;
}
return i;
}
/*
** Try to find a boundary in table `t'. A `boundary' is an integer index
** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
*/
MSize LJ_FASTCALL lj_tab_len(GCtab *t)
{
MSize j = (MSize)t->asize;
if (j > 1 && tvisnil(arrayslot(t, j-1))) {
MSize i = 1;
while (j - i > 1) {
MSize m = (i+j)/2;
if (tvisnil(arrayslot(t, m-1))) j = m; else i = m;
}
return i-1;
}
if (j) j--;
if (t->hmask <= 0)
return j;
return unbound_search(t, j);
}
-67
View File
@@ -1,67 +0,0 @@
/*
** Table handling.
** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_TAB_H
#define _LJ_TAB_H
#include "lj_obj.h"
/* Hash constants. Tuned using a brute force search. */
#define HASH_BIAS (-0x04c11db7)
#define HASH_ROT1 14
#define HASH_ROT2 5
#define HASH_ROT3 13
/* Scramble the bits of numbers and pointers. */
static LJ_AINLINE uint32_t hashrot(uint32_t lo, uint32_t hi)
{
#if LJ_TARGET_X86ORX64
/* Prefer variant that compiles well for a 2-operand CPU. */
lo ^= hi; hi = lj_rol(hi, HASH_ROT1);
lo -= hi; hi = lj_rol(hi, HASH_ROT2);
hi ^= lo; hi -= lj_rol(lo, HASH_ROT3);
#else
lo ^= hi;
lo = lo - lj_rol(hi, HASH_ROT1);
hi = lo ^ lj_rol(hi, HASH_ROT1 + HASH_ROT2);
hi = hi - lj_rol(lo, HASH_ROT3);
#endif
return hi;
}
#define hsize2hbits(s) ((s) ? ((s)==1 ? 1 : 1+lj_fls((uint32_t)((s)-1))) : 0)
LJ_FUNCA GCtab *lj_tab_new(lua_State *L, uint32_t asize, uint32_t hbits);
#if LJ_HASJIT
LJ_FUNC GCtab * LJ_FASTCALL lj_tab_new1(lua_State *L, uint32_t ahsize);
#endif
LJ_FUNCA GCtab * LJ_FASTCALL lj_tab_dup(lua_State *L, const GCtab *kt);
LJ_FUNC void LJ_FASTCALL lj_tab_free(global_State *g, GCtab *t);
LJ_FUNCA void lj_tab_reasize(lua_State *L, GCtab *t, uint32_t nasize);
/* Caveat: all getters except lj_tab_get() can return NULL! */
LJ_FUNCA cTValue * LJ_FASTCALL lj_tab_getinth(GCtab *t, int32_t key);
LJ_FUNC cTValue *lj_tab_getstr(GCtab *t, GCstr *key);
LJ_FUNCA cTValue *lj_tab_get(lua_State *L, GCtab *t, cTValue *key);
/* Caveat: all setters require a write barrier for the stored value. */
LJ_FUNCA TValue *lj_tab_newkey(lua_State *L, GCtab *t, cTValue *key);
LJ_FUNC TValue *lj_tab_setinth(lua_State *L, GCtab *t, int32_t key);
LJ_FUNC TValue *lj_tab_setstr(lua_State *L, GCtab *t, GCstr *key);
LJ_FUNC TValue *lj_tab_set(lua_State *L, GCtab *t, cTValue *key);
#define inarray(t, key) ((MSize)(key) < (MSize)(t)->asize)
#define arrayslot(t, i) (&tvref((t)->array)[(i)])
#define lj_tab_getint(t, key) \
(inarray((t), (key)) ? arrayslot((t), (key)) : lj_tab_getinth((t), (key)))
#define lj_tab_setint(L, t, key) \
(inarray((t), (key)) ? arrayslot((t), (key)) : lj_tab_setinth(L, (t), (key)))
LJ_FUNCA int lj_tab_next(lua_State *L, GCtab *t, TValue *key);
LJ_FUNCA MSize LJ_FASTCALL lj_tab_len(GCtab *t);
#endif

Some files were not shown because too many files have changed in this diff Show More