Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jit: Don't use a second stack #11399

Merged
merged 3 commits into from Mar 3, 2023
Merged

Conversation

JosJuice
Copy link
Member

@JosJuice JosJuice commented Jan 1, 2023

This second stack leads to JNI problems on Android, because ART fetches the address and size of the original stack using pthread functions (see GetThreadStack in art/runtime/thread.cc), and (presumably) treats stack addresses outside of the original stack as invalid. (What I don't understand is why some JNI operations on the CPU thread work fine despite this but others don't.)

Instead of creating a second stack, let's borrow the approach ART uses: Use pthread functions to find out the stack's address and size, then install guard pages at an appropriate location. This lets us get rid of a workaround we had in the MsgAlert function.

By the way, on Windows it was already the case that we didn't create a second stack... But there was a bug in the implementation! The code for protecting the stack has to run on the CPU thread, since it's the CPU thread's stack we want to protect, but it was actually running on EmuThread. This commit fixes that, since now this bug matters on other operating systems too.

An important question that will require some testing is: Is the stack size we get actually big enough on all platforms? On Android I'm getting a size just below 1 MiB. If that's the smallest we're dealing with, I'd be fine simply with dropping the requirement to that (which is what I've done for now), but if there are platforms that give us an even smaller stack, we should probably request a bigger stack in some way.

@JosJuice JosJuice force-pushed the jit-one-stack branch 2 times, most recently from b155dd7 to 1824a57 Compare January 1, 2023 20:09
@TellowKrinkle
Copy link
Contributor

IIRC macOS uses 512k stacks

@dvessel
Copy link
Contributor

dvessel commented Jan 1, 2023

got this:

48:52:950 Core/PowerPC/JitArm64/Jit.cpp:337 E[MASTER]: Warning: Stack size of 536576 bytes is too small for BLR optimization

It still runs but I get that warning before the game starts.

@JosJuice
Copy link
Member Author

JosJuice commented Jan 2, 2023

On IRC, we discussed setting the stack size manually. It is possible to do this using pthreads, but std::thread doesn't let you get a pthread handle until the thread has already started running, so it seems like if we want to do this we would have to forgo using std::thread for the CPU thread.

Instead, I've changed the constants so we now accept macOS's 512 KiB stacks. It's probably fine... Assuming there was no deeper reason for 2 MiB being picked in the past.

@dvessel
Copy link
Contributor

dvessel commented Jan 3, 2023

warning dialog with this now when starting:

Common/MemoryUtil.cpp:197 E[MASTER]: Warning: ReadProtectMemory failed!
mprotect: Invalid argument

Game plays normally like before.

@JosJuice
Copy link
Member Author

JosJuice commented Jan 3, 2023

That's weird... The call to ReadProtectMemory is basically unchanged from before. Or is this some kind of alignment shenanigans? @TellowKrinkle, would you have the ability to debug this on macOS?

@AdmiralCurtiss
Copy link
Contributor

Alignment seems like a good guess, the address argument must be page boundary aligned.

@TellowKrinkle
Copy link
Contributor

(And don't forget that M1 uses 16K pages)

@JosJuice
Copy link
Member Author

JosJuice commented Jan 3, 2023

I find it a bit odd that the stack wouldn't be page aligned, but... Alright, here's an updated version of the code that should ensure that the alignment is correct.

@dvessel
Copy link
Contributor

dvessel commented Jan 3, 2023

Sorry to annoy you with this but it's now pointing to the same line as my first comment. Maybe wait until TellowKrinkle has time to spare. 👾

Core/PowerPC/JitArm64/Jit.cpp:337 E[MASTER]: Warning: Failed to get correct stack base

@JosJuice
Copy link
Member Author

JosJuice commented Jan 3, 2023

So, that the line number is the same is just a coincidence. What's actually happened here is that a check that's done fairly early on (before any of the other checks you've triggered) actually was broken before but is fixed now, and macOS is failing the check. I guess it might be because macOS returns the top of the stack instead of the base of the stack when asked for the stack address. I've uploaded a new version of the commit, if you want to check if that hypothesis was correct.

@dvessel
Copy link
Contributor

dvessel commented Jan 3, 2023

So, that the line number is the same is just a coincidence. What's actually happened here is that a check that's done fairly early on (before any of the other checks you've triggered) actually was broken before but is fixed now, and macOS is failing the check. I guess it might be because macOS returns the top of the stack instead of the base of the stack when asked for the stack address. I've uploaded a new version of the commit, if you want to check if that hypothesis was correct.

Nice! Looks like you were right since it’s no longer complaining.

@JosJuice
Copy link
Member Author

JosJuice commented Jan 3, 2023

This also explains why it seemed like the stack wasn't page aligned before: In fact it was the top of the stack that wasn't page aligned. (Well, not that we know for sure if the bottom is aligned or not, since the current code does handle the case of it not being aligned.)

@JosJuice JosJuice mentioned this pull request Jan 4, 2023
10 tasks
dvessel added a commit to dvessel/dolphin that referenced this pull request Jan 6, 2023
Source/Core/Core/PowerPC/Jit64/Jit.cpp Outdated Show resolved Hide resolved
Source/Core/Core/PowerPC/Jit64/Jit.cpp Outdated Show resolved Hide resolved
Source/Core/Core/PowerPC/Jit64/Jit.cpp Outdated Show resolved Hide resolved
Seems like this was broken all along. The safe zone is at the lower
addresses of the stack, not the higher addresses.
This second stack leads to JNI problems on Android, because ART fetches
the address and size of the original stack using pthread functions
(see GetThreadStack in art/runtime/thread.cc), and (presumably) treats
stack addresses outside of the original stack as invalid. (What I don't
understand is why some JNI operations on the CPU thread work fine
despite this but others don't.)

Instead of creating a second stack, let's borrow the approach ART uses:
Use pthread functions to find out the stack's address and size, then
install guard pages at an appropriate location. This lets us get rid
of a workaround we had in the MsgAlert function.

Because we're no longer choosing the stack size ourselves, I've made some
tweaks to where the put the guard pages. Previously we had a stack of
2 MiB and a safe zone of 512 KiB. We now accept stacks as small as 512 KiB
(used on macOS) and use a safe zone of 256 KiB. I feel like this should
be fine, but haven't done much testing beyond "it seems to work".

By the way, on Windows it was already the case that we didn't create
a second stack... But there was a bug in the implementation!
The code for protecting the stack has to run on the CPU thread, since
it's the CPU thread's stack we want to protect, but it was actually
running on EmuThread. This commit fixes that, since now this bug
matters on other operating systems too.
Deduplication between Jit64 and JitArm64.
dvessel added a commit to dvessel/dolphin that referenced this pull request Mar 3, 2023
@AdmiralCurtiss
Copy link
Contributor

Can this be merged now?

@JosJuice JosJuice merged commit 95ce41a into dolphin-emu:master Mar 3, 2023
14 checks passed
@JosJuice JosJuice deleted the jit-one-stack branch March 3, 2023 21:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
5 participants