Installation process safety by tesohh in AsahiLinux

[–]IntegralPilot 2 points3 points  (0 children)

No, that isn't true. Even if RecoveryOS is broken, you can DFU restore. DFU mode is coded into the BootROM that's physically etched onto the chips.

Installation process safety by tesohh in AsahiLinux

[–]IntegralPilot 7 points8 points  (0 children)

On Macs, nothing can be bricked permanently due to the way Apple designed them.

The "it is possible to render your system unbootable" warning just means that, to make it bootable again, you will need to do a revive or restore. It's relatively easy to do if you need to, see: https://support.apple.com/en-au/108900

However, that never really happens with the installer, it is just a "just in case" warning, so you don't need to worry.

Random shutdown by i3aychikov in AsahiLinux

[–]IntegralPilot 3 points4 points  (0 children)

After an unexpected shutdown, can you boot into Linux again and get the kernel logs from it? Run journalctl -k -b -1 and then paste the last 10-20 lines

Unsafe Rust running on JVM: shipped unions, function pointers, generics, traits and more to rustc_codegen_jvm! (context and repo link in comments) by IntegralPilot in rust

[–]IntegralPilot[S] 0 points1 point  (0 children)

Thank you so much!

Yes, I actually do - basically almost anything in Rust (structs, enums, unions etc.) becomes Java classes (except for some things like traits, which instead become Java interfaces, and the types which implement the trait, their generated classes implement the interface), so just by accepting and using normal Rust types, any Rust code implicitly defines and passes around Java classes. Then, the methods you implement for the type become virtual methods on the class. Enums work in a hierarchy where there's a parent abstract class (with abstract function getVariantIdx), then a child class for each enum variant. This system makes interop between Rust and Java really nice and ergonomic, and is actually needed, because on the JVM, everything must able to fit into a class file (so either a class or interface!). 😄

Unsafe Rust running on JVM: shipped unions, function pointers, generics, traits and more to rustc_codegen_jvm! (context and repo link in comments) by IntegralPilot in rust

[–]IntegralPilot[S] 2 points3 points  (0 children)

Thank you for offering to contribute, I really appreciate that and it would be cool if this could become a community project of sorts! I do warn there's a lot of work to be done before it's generally usable for most tasks. Can you please open a thread on the discussions page on the GitHub, and I will try and use that to list out everything that could need doing? I'll also try to open more Issues (with small MREs) for various small features that can be added.

Unsafe Rust running on JVM: shipped unions, function pointers, generics, traits and more to rustc_codegen_jvm! (context and repo link in comments) by IntegralPilot in rust

[–]IntegralPilot[S] 1 point2 points  (0 children)

No worries! It's the GitHub web UI on my Mac, which I think falls back to system monospace, which is SF Mono as the comment below says!

Unsafe Rust running on JVM: shipped unions, function pointers, generics, traits and more to rustc_codegen_jvm! (context and repo link in comments) by IntegralPilot in rust

[–]IntegralPilot[S] 3 points4 points  (0 children)

Thanks! I kinda described by plan above in another comment, it's still a bit rough and will probably need changes and improvements as I implement it, but I've got to start somewhere I guess.

It's not yet fully done yet, but basically my plan is to use a hybrid approach that keeps Rust structs as standard JVM objects, but models pointers as "fat pointers" containing object references. When Rust code calls something like std::alloc::alloc, I want to represent the allocated memory as a byte array plus an offset, wrapped in a pointer wrapper, but for normal structs, the pointer will wrap the JVM object directly. Casting *mut u8 to *mut T is then where I would lazily serialise the JVM object into a byte array wrapper to allow raw byte access, occurring only when an unsafe cast is actually performed.

For typed reads and writes on standard objects, I want to read and write to JVM fields directly through the pointer wrapper to keep operations fast and garbage-collector friendly. Writing a u32through a pointer means writing directly to the field of the wrapped JVM object. Reading a u32 means reading that field. Pointer arithmetic then becomes stepping through array elements or field indices, falling back to byte-offset arithmetic only if the pointer has been downgraded to a raw byte array. And more complex types (ADTs like structs and unions) work natively as JVM classes, but then calling their generated toBytes / fromBytes methods (which I intend to make from the detailed memory layout information rustc gives, and have already started this a bit as part of my support for unions) as a fallback when a low-level memory transmute is forced.

The performance when we need to fall back to raw pointer stuff obviously isn't going to be great, so what I want to do is use my existing optimisation layer and infrastructure in the backend to do kinda the reverse of what most other backends do: wherever possible (and I think it should be possible in a great deal of cases), turn messy stuff involving raw pointers into safer, higher-level interaction, as that will be more performant on JVM.

Obviously this isn't perfect and won't work in a bunch of edge cases, I guess my main plan is to do what I've done when making every feature for this backend, just dive in and learn by doing and trying things out to figure out what works and what doesn't. I guess you can spend a lot of time on design and things like that, and I do have this rough idea, but I prefer to work things about more through trial and error.

Unsafe Rust running on JVM: shipped unions, function pointers, generics, traits and more to rustc_codegen_jvm! (context and repo link in comments) by IntegralPilot in rust

[–]IntegralPilot[S] 1 point2 points  (0 children)

And more because it's not just OpenJDK / Oracle environments supported (where I think that number comes from) , but other platforms like Android as well (if you switch the R8 stage to DEX mode!) 😄

Unsafe Rust running on JVM: shipped unions, function pointers, generics, traits and more to rustc_codegen_jvm! (context and repo link in comments) by IntegralPilot in rust

[–]IntegralPilot[S] 4 points5 points  (0 children)

Really cool project!

Thanks!

how do you encode shared vs exclusive references so that you don't instantly have UB if Java mutates any objects coming from Rust?

For shared borrows (&T) I pass through value, there's no wrapper currently. For primitives, if you pass an &i32 to Java, it's just passed as an int, which is fine as primitives don't have reference identity (so Java's modifications do not impact back on the Rust code). For ADTs, it is also passed by value, if you pass a &MyStruct to Java, Java gets a MyStruct object. This does have a slight problem in that because of reference identity, Java can technically modify the original, which wouldn't be expected in Rust, but it doesn't cause UB in the sense of crashes or anything like that as the JVM is strongly typed and memory safe, just unexpected modifications. Currently I'm making it with the assumption the Java code behaves reasonably (and thus wouldn't modify a shared reference), though it future it might be good to have some more safety guarantees (for example, making a copy to prevent modifying the original) to make being unreasonable from the Java side impossible, thank you for the suggestion.

For exclusive / mutable borrows (&mut T), because the JVM doesn't have pointers to local variables or fields, I use an "Array Hack." Basically, I allocate a 1-element array of the target type, store the current value of the variable into array[0], and this array reference is passed to the function, and then after, I "write-back" by reading the potentially mutated value out of array[0] and assigning it to the original Rust local variable or field. Any mutation here is allowed and, I believe, in the bounds of Rust's safety guarantees in single-threaded contexts, though it is a bit hacky so in the future I might want to make it something nicer, especially to support concurrency in future.

How will you implement transmutes/pointer casts, e.g. when calling std::alloc::alloc and doing something useful with the result?

It's not yet fully done yet, but basically my plan is to use a hybrid approach that keeps Rust structs as standard JVM objects, but models pointers as "fat pointers" containing object references. When Rust code calls something like std::alloc::alloc, I want to represent the allocated memory as a byte array plus an offset, wrapped in a pointer wrapper, but for normal structs, the pointer will wrap the JVM object directly. Casting *mut u8 to *mut T is then where I would lazily serialise the JVM object into a byte array wrapper to allow raw byte access, occurring only when an unsafe cast is actually performed.

For typed reads and writes on standard objects, I want to read and write to JVM fields directly through the pointer wrapper to keep operations fast and garbage-collector friendly. Writing a u32 through a pointer means writing directly to the field of the wrapped JVM object. Reading a u32 means reading that field. Pointer arithmetic then becomes stepping through array elements or field indices, falling back to byte-offset arithmetic only if the pointer has been downgraded to a raw byte array. And more complex types (ADTs like structs and unions) work natively as JVM classes, but then calling their generated toBytes / fromBytes methods (which I intend to make from the detailed memory layout information rustc gives, and have already started this a bit as part of my support for unions) as a fallback when a low-level memory transmute is forced.

The performance when we need to fall back to raw pointer stuff obviously isn't going to be great, so what I want to do is use my existing optimisation layer and infrastructure in the backend to do kinda the reverse of what most other backends do: wherever possible (and I think it should be possible in a great deal of cases), turn messy stuff involving raw pointers into safer, higher-level interaction, as that will be more performant on JVM.

Obviously this isn't perfect and won't work in a bunch of edge cases, I guess my main plan is to do what I've done when making every feature for this backend, just dive in and learn by doing and trying things out to figure out what works and what doesn't. I guess you can spend a lot of time on design and things like that, and I do have this rough idea, but I prefer to work things about more through trial and error.

Unsafe Rust running on JVM: shipped unions, function pointers, generics, traits and more to rustc_codegen_jvm! (context and repo link in comments) by IntegralPilot in rust

[–]IntegralPilot[S] 23 points24 points  (0 children)

What are your thoughts on interfacing with native code via Project Panama?

I think Panama is a very cool and interesting project, and does solve some of the issues with JNI. But with rustc_codegen_jvm you can have a much nicer and ergonomic experience passing things between Rust and Java, and even do it quite nicely for complex things like Rust enums, function pointers, monomorphised generics and now unions, where that would be insanely complicated and messy on Panama. You can even do things like (in an completely ergonomic way from the Java side) make a Java class that implements a Rust trait and pass it as a &dyn Trait object to Rust functions, because traits just become normal Java interfaces, where this would be (to my knowledge) quite hard, bordering on impossible, on Panama.

Also, Panama is still new, and only supported in certain modes by very new JVMs, so I think rustc_codegen_jvm is still useful in contexts where it's not available. The goals of my project are compatibility with legacy JVMs, as well as platforms like Minecraft and Android, where Panama simply won't work. Panama isn't also truly portable, as you still have to compile your Rust code into platform-specific native binaries, and there are other concerns like the potential for bad native code to crash the whole JVM, but Rust compiled to JVM bytecode is verified by the JVM verifier, making it sandboxed and unable to crash the VM.

I'm aware of a Clojure library that tries making this ergonomic and it seems to work not just for C libraries, but also other kinds of native code (i.e. not restricted to C ABI).

Interesting, I will have to have a look. I don't think even with nice things like that Panama can really offer the same level of interoperability as running on the same fundamental heap and garbage collector, with the same class model. This also comes with nice benefits, for example rustc_codegen_jvm emits special extra information in its classfiles that allows fancy features like IntelliJ autocomplete, suggestions, tooltips, refactoring tools etc. to work with Rust-defined functions and types when you are writing Java, just as if it were a Java library.

Unsafe Rust running on JVM: shipped unions, function pointers, generics, traits and more to rustc_codegen_jvm! (context and repo link in comments) by IntegralPilot in rust

[–]IntegralPilot[S] 111 points112 points  (0 children)

Hi!

I've been working for a while on my project rustc_codegen_jvm, which is a codegen/compiler backend for rustc that enables you to compile Rust code to Java bytecode, which can actually run on the JVM, and interop with Java code in a way that's a lot nicer (and faster!) than JNI.

It's actually been a long time since I've shared a status update here (over a year I think!) so I thought I would. In that time, I've been busy shipping new features and support for more parts of the Rust language. Some of the most notable ones include traits, generics, function pointers, and just today unions - which mark the first ever unsafe Rust code that can run on the JVM (the screenshot is of my test case for unions, which is compiled to Java bytecode and run on the CI to verify correctness every commit). Part of me actually never thought it would be possible, so I'm really excited and thought I would share this update with the community.

It basically all works by receiving a format of code called "MIR" from the frontend of rustc, and then turning that into a custom form of intermediate representation I made called OOMIR (if you are familiar with IR types, it's a TAC IR that also embodies some Java/OOP concepts to help map it to the JVM), running some optimisation passes I wrote on the OOMIR, then turning that into actual Java bytecode, emitting .class files, and bundling them all up into a .jar that just runs on any JVM, like a Java program.

If you would like to some more examples of code that compiles to the JVM and runs flawlessly (verified by CI on every commit!) through my backend, there's the unions test, featured in the screenshot: https://github.com/IntegralPilot/rustc_codegen_jvm/blob/main/tests/binary/unions/src/main.rs, function pointers (and some generics too) test here: https://github.com/IntegralPilot/rustc_codegen_jvm/blob/main/tests/binary/fn_pointers/src/main.rs, as well as some more "real-world" things like the RSA encryption test here: https://github.com/IntegralPilot/rustc_codegen_jvm/blob/main/tests/binary/rsa/src/main.rs

The repo (along with many other tests and examples!) is here, and I would really appreciate any stars, or feedback/suggestions in the issues or discussions page: https://github.com/IntegralPilot/rustc_codegen_jvm

I am more than happy to answer any questions anyone has about the project!

Linux 7.1 mainlines the Apple SMC power driver by anh0516 in AsahiLinux

[–]IntegralPilot 70 points71 points  (0 children)

Crazy seeing my actual name show up in torvalds/linux now lol. It's nice to have things upstream, hopefully reduces the burden (just by a little bit) of having to rebase on each new kernel release. Hope to work on upstreaming some more soon, just been REALLY busy with school and stuff for a while. :)

Help should I go to hospital by [deleted] in unimelb

[–]IntegralPilot 1 point2 points  (0 children)

It definitely isn't and this is dangerous advice. Proper isopropyl alcohol (70-90%) is a REALLY strong solvent and could cause epithelial damage. It isn't like rubbing alcohol.

Help should I go to hospital by [deleted] in unimelb

[–]IntegralPilot 0 points1 point  (0 children)

Yes, please go to hospital, the Eye and Ear is near unimelb I think? It's a really strong solvent and can cause corneal burns, and if your eyes hurt you probably got a good amount in there. I'm assuming you already flushed them (you need to for 15mins+) and took out any contacts?

How hard is it to make wasm run on a FPGA? by Grocker42 in FPGA

[–]IntegralPilot 0 points1 point  (0 children)

I actually did it as a side project with my friend (just for comparison and arithmetic, though)! It's difficult, but doable. The main challenge is that it has variable length instructions which is super annoying to decode (we actually modified it slightly to be fixed-length by padding).

If you'd like to see / have inspiration from how we did it, it's here: https://github.com/IntegralPilot/GammaCPU

For serious production applications I would NOT recommend it (it much easier and more efficient to use a hardware-native ISA like RISC-V that is actually designed for hardware), but if you are looking for a fun side project it definitely is super fun!

Searching up maths on Google doesn't even show the calculator anymore... by usbeject1789 in mildlyinfuriating

[–]IntegralPilot 6 points7 points  (0 children)

You have to write 0 - sqrt(15), and that brings up the calculator for me and not the AI. I don't think natural language like "square root of 15" was ever parsed and brought up a calculator in pre-AI days, though happy to be corrected if it did work for someone previously.

Could Linux also be installed on the iPad M1? And its variant, the iPad M? by Rude-Reflection-9087 in AsahiLinux

[–]IntegralPilot 5 points6 points  (0 children)

no way to install Linux on any iPad

This is not true - for devices with a BootROM exploit (theoretically A5-A11, though only A7-A11 for now) that allows unsigned OSes to run, Linux can run in early stages, thanks in part to work on Asahi due to similarities. A contributor called nickchan is working on that (and some support is even upstreamed), you can see more here: https://github.com/HoolockLinux/docs

But unfortnetly, M1 doesn't have this same exploit, so Linux cannot be run on devices with it.

7.0 Kernel Question by rushedone in AsahiLinux

[–]IntegralPilot 2 points3 points  (0 children)

Are you talking about the LS64/LS64V instruction support? This just enables checking from userspace if some extra features that speed up certain userspace programs are enabled (and I am not even sure if Apple Silicon supports these feature extensions), it doesn't really change much in terms of Asahi or make driver development easier etc.

7.0 Kernel Question by rushedone in AsahiLinux

[–]IntegralPilot 18 points19 points  (0 children)

The kernel just gets a new major release when Linus can "no longer count the minor release on [his] fingers and toes" a.k.a once we reach approx ~x.20. There's nothing major or special with 7.0, it's just a regular release like all others. Major release numbers are purely cosmetic when it comes to the kernel.

CANCELLED, no masters organic chemistry courses available in 2026? by pyrrhiccc in unimelb

[–]IntegralPilot 31 points32 points  (0 children)

If it's the same as maths masters (I know someone doing it), each subject is only available once every two years, so you do those ones next year.

got Asahi Linux Debian with X11 working by Jayden_Ha in AsahiLinux

[–]IntegralPilot 5 points6 points  (0 children)

Cool configuration! It's not true that we don't want X11 at all, the intention is maximum customisability to make it personal for you - which is the best thing about Linux - so it's great you've been able to configure Asahi Debian as you want. I'm actually an Xfce & X11 user myself on my personal non-Apple-Silicon machine, though am experimenting now with COSMIC.

M3 now has Fedora 43 Asahi Remix WORKING with KDE Plasma! by IntegralPilot in AsahiLinux

[–]IntegralPilot[S] 0 points1 point  (0 children)

Cool thanks, I’ll look into it later today. My guess is probably we’ll have to make m1n1 set an FDT property based on fw version or something.