luau-rs
HVM
luau-rs | HVM | |
---|---|---|
2 | 112 | |
16 | 10,165 | |
- | 29.6% | |
7.5 | 8.9 | |
over 2 years ago | 3 days ago | |
Rust | Cuda | |
GNU General Public License v3.0 only | Apache License 2.0 |
Stars - the number of stars that a project has on GitHub. Growth - month over month growth in stars.
Activity is a relative number indicating how actively a project is being developed. Recent commits have higher weight than older ones.
For example, an activity of 9.0 indicates that a project is amongst the top 10% of the most actively developed projects that we are tracking.
luau-rs
-
Principles are products of practice, not the reverse
> - Do not repeat yourself.
I recently ran into a case where this was practically a necessity, because the alternative (of simply repeating myself) would not only have been prone to copy/paste errors during authorship, but also have resulted in code with an incredibly low signal to noise ratio (which also would have made authorship quite tedious).
For a bit of backstory, I'm currently toying with writing some Luau bindings for Rust, but Luau (by default) throws C++ exceptions instead of using longjmp. These exceptions can be thrown by almost any Luau function, and I need to prevent them from unwinding across FFI boundaries to avoid triggering Undefined Behavior, because in Rust, it is UB for a "C"-ABI function to unwind into its caller.
Here are some things that can throw C++ exceptions in Luau:
- OOM when allocating new garbage-collectible objects in an existing VM. Creating the VM itself is (most traditionally) done through luaL_newstate, which returns NULL on allocation failure, but once you have a VM, attempting to instantiate a collectible object within it will throw an exception if allocation fails. This can happen indirectly through any other operation that internally creates collectible objects.
- Attempting to modify a readonly table. Luau implements a readonly bit for tables that controls a guard against modification of that table, even by native code. It does this by throwing an exception when any such modification is attempted. However, just like collectible objects, table modification is an implementation detail of all sorts of things. While I don't expect anyone to be able to readonly the Luau registry, it is still a thing that you can do to arbitrary other tables (assuming that the host side doesn't omit or remove the `table.freeze` function from the standard library). Technically, you could defensively check the readonly bit from Rust before attempting those operations, but that would cause it to be checked twice on each operation, and this workaround doesn't generalize to other sources of exceptions, nor does it work through indirections (random other functions that happen to write to tables internally).
- Arbitrary function calls, if an interrupt callback is set. Luau supports an "interrupt" callback that is periodically called by the VM at "checkpoints" such as function calls. The interrupt callback is allowed to throw an exception, as this is the officially supported method of eventually terminating functions that contain infinite loops or other code that blocks the thread for too long. AFAIK, it can also be triggered in the middle of C closures if you perform certain operations like making a Luau function call. Although Luau function calls themselves may error, the interrupt callback can cause any Luau function call to error, even if it normally should not.
Luau probably expects those kinds of operations to be performed primarily by C++ functions executing under the VM ("C closures"), where any exceptions will be automatically caught and a status code returned to whoever called the VM. Generally, it is quite a reasonable assumption to make that a library will be used from the same language that it is written in.
However, Rust can't currently express "C closures" that are capable of unwinding, because unwinding out of a "C"-ABI function is Undefined Behavior (Rust wouldn't be able to unwind into the VM), and so is a "C"-ABI function unwinding into a Rust stack frame (library functions wouldn't be able to unwind into Rust in the first place).
The "C-unwind" ABI should eventually allow Rust to express and call FFI functions that are capable of unwinding, but it hasn't quite reached stabilization yet.
If Rust had already supported "C-unwind", I could have just defined a C++ wrapper function that catches Luau exceptions and translates them into a tagged union or something representing success or failure. Unfortunately that is not yet the case.
Luckily, Luau has some internal functions that allow you to catch exceptions regardless of whether they are exceptions or longjmps, but they work by executing a callback that you pass to it, and you can only pass a single pointer value through to the callback. Therefore, my first solution was to place the arguments to be passed in a struct, as well as a slot for a return value, and then read that struct by pointer in order to call the function and write its return value into the slot.[0]
This worked, but it was a lot of manual code for each individual function that had to be protected from errors - you had to duplicate the argument list about 4 times (wrapper function signature, struct definition, struct initializer, and wrapped function invocation), which quickly got quite tedious, especially since quite a few functions are going to need this wrapping treatment.
My first DRY implementation was to create a template that can produce a wrapper around any function, that calls it with any number of arguments, of any types. I still needed to manually prepare a list of functions in advance to protect, since you can't instantiate templates over FFI, but this was a lot more painless than the first try.
It's just that the templates are a bit of a mess.
[0]: https://github.com/LoganDark/luau-rs/blob/787eb0c7987c08304c...
[1]: https://github.com/LoganDark/luau-rs/blob/de5abd5420a5311c27...
-
Please, keep in mind there is ZERO FUNDING for my projects.
I've been asked twice to switch away from GPL and the argument is always that it limits who can use my work. Usually the argument goes past that and tries to stress just how seriously, debilitatingly, unusable my library becomes by being GPL-licensed.
HVM
- Bend a Parallel Language
- Bend: A higher order language for the GPU
- Bend: A High-Level GPU Language Powered by HVM2
-
Welcome to the Parallel Future of Computation
Sorry I only just saw this - the URL was changed because you have this in the HTML:
- Bend: A Python-Like Parallel Language for GPUs and Multicore CPUs
-
SaberVM
Reminds me of HVM[0]
[0]https://github.com/HigherOrderCO/HVM
Really interesting to see how new lang concepts and refinements keep popping up this last decade, between Vale, Gleam, Hylo, Austral...
Linear types really opened up lots of ways to improve memory management and compilation improvements.
- GPU Survival Toolkit for the AI age: The bare minimum every developer must know
-
A new F# compiler feature: graph-based type-checking
I have a tangential question that is related to this cool new feature.
Warning: the question I ask comes from a part of my brain that is currently melted due to heavy thinking.
Context: I write a fair amount of Clojure, and in Lisps the code itself is a tree. Just like this F# parallel graph type-checker. In Lisps, one would use Macros to perform compile-time computation to accomplish something like this, I think.
More context: Idris2 allows for first class type-driven development, where the types are passed around and used to formally specify program behavior, even down to the value of a particular definition.
Given that this F# feature enables parallel analysis, wouldn't it make sense to do all of our development in a Lisp-like Trie structure where the types are simply part of the program itself, like in Idris2?
Also related, is this similar to how HVM works with their "Interaction nets"?
https://github.com/HigherOrderCO/HVM
https://www.idris-lang.org/
https://clojure.org/
I'm afraid I don't even understand what the difference between code, data, and types are anymore... it used to make sense, but these new languages have dissolved those boundaries in my mind, and I am not sure how to build it back up again.
-
A History of Functional Hardware
Impressive presentation but I find two things missing in particular:
* GRIN [1] - arguably a breakthrough in FP compilation; there are several implementation based on this
* HVM [2] - parallel optimal reduction. The results are very impressive.
[1] https://link.springer.com/chapter/10.1007/3-540-63237-9_19
[2] https://github.com/HigherOrderCO/HVM
-
Is the abstraction of lazy-functional-purity doomed to leak?
Purity has nothing to do with memoization. Haskell's semantics never "rewrite under a lambda" (unlike, e.g. HVM). Calling (\_ -> e) () twice will (modulo optimizations) always perform the computation in e twice.
What are some alternatives?
rust-lua - Safe Rust bindings to Lua 5.1
Kind - A next-gen functional language [Moved to: https://github.com/Kindelia/Kind2]
openfare - Micropayment funded software.
rust-gpu - 🐉 Making Rust a first-class language and ecosystem for GPU shaders 🚧
SICL - A fresh implementation of Common Lisp
Sharp-Bilinear-Shaders - sharp bilinear shaders for RetroPie, Recalbox and Libretro for sharp pixels without pixel wobble and minimal blurring
fslang-suggestions - The place to make suggestions, discuss and vote on F# language and core library features
atom - A DSL for embedded hard realtime applications.
Vale - Compiler for the Vale programming language - http://vale.dev/
jre-missing - Automatically detects and lists episodes of The Joe Rogan Experience podcast that are currently not available on the Spotify platform. Also detects if episodes have been shortened in duration.
frag - Frag is a 3D first person shooting game written in Haskell, by Mun Hon Cheong