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

Page-agnostic block trampolines #317

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open

Page-agnostic block trampolines #317

wants to merge 6 commits into from

Conversation

hmelder
Copy link
Collaborator

@hmelder hmelder commented Nov 18, 2024

This is a block trampoline implementation which is page-agnostic, instead relying on a fix-up when copied into the RX buffer. It is currently UB to run libobjc2 on platforms with a page size other than 4KiB (except PPC64 which is configured as 64KiB in libobjc2).

There is a also a hard-coded page size inpool.h which I have not addressed yet.

Before rewriting all block trampolines, I want to ensure my approach is sound, so I have only adjusted the AArch64 trampoline for now. Suggestions are welcome.

@hmelder
Copy link
Collaborator Author

hmelder commented Nov 18, 2024

See #271

@hmelder
Copy link
Collaborator Author

hmelder commented Nov 19, 2024

Seems like the cross build for PowerPC was always running on 4KiB pages. Ready for review.

Do not assume a certain page size at compile time, as
it might change during runtime. Android 15 has support for
16 KiB pages and expects an application to support both
4 KiB and 16 KiB pages.
Instead of performing a PC-relative load with PAGE_SIZE as negative
offset, we fix up the trampoline in the `alloc_trampolines` function.
Much like libdispatch project, shim.c implements APIs that are missing
on platforms. Currently, this only affects Windows.
Some block trampolines hard-code their page sizes
for simplicity. Check if we violate that assumption
when building in debug mode.
@hmelder
Copy link
Collaborator Author

hmelder commented Nov 19, 2024

@davidchisnall would it be possible for you to grant me permission to set up a self-hosted aarch64 runner? I’d like to add an Android CI using the Pre-Release 16 KiB Page Size arm64-v8a System Image. Additionally, we should consider consolidating some runners, possibly removing CIs with Clang versions older than 14.

@hmelder
Copy link
Collaborator Author

hmelder commented Nov 19, 2024

Android Test Results

System

I've setup an Android Toolchain and Emulator with the following packages:

system-images;android-35;google_apis_ps16k;arm64-v8a
ndk;28.0.12433566
platforms;android-35
build-tools;35.0.0

It correctly reports a 16 KiB page size:

emu64a16k:/ # getconf PAGESIZE
16384

Test Results

Master (771f7c4)

FAILED (139): BlockImpTest (0s)
FAILED (139): BlockImpTest_optimised (0s)
FAILED (139): BlockImpTest_legacy_optimised (0s)
FAILED (139): BlockImpTest_legacy (0s)

97% Passed. Total: 190, Passed: 182, Skipped: 4, Failed: 4
Finished running tests. Exiting.
Log
hmelder@Hugos-MacBook-Pro libobjc2 % .github/scripts/android_test_main.sh build ${ANDROID_TOOLCHAIN}/sysroot aarch64-linux-android
adbd is already running as root
cp: build/Test/CMakeFiles is a directory (not copied).
/var/folders/jn/wky_dz4j3ll7_49hbtg73hdr0000gn/T/tmp.57PtxFauH1/: 192 files pushed, 0 skipped. 425.5 MB/s (26161935 bytes in 0.059s)
build/../.github/scripts/android_test_driver.sh: 1 file pushed, 0 skipped. 1.9 MB/s (1738 bytes in 0.001s)
SKIPPED: UnexpectedException_legacy_optimised
PASSED (0): MethodArguments_legacy (0s)
PASSED (0): FastARC_legacy (0s)
PASSED (0): alignTest_legacy_optimised (0s)
PASSED (0): FastPathAlloc_optimised (0s)
PASSED (0): BoxedForeignException_legacy_optimised (0s)
PASSED (0): ARCTest_arc_optimised (0s)
PASSED (0): BoxedForeignException_optimised (0s)
PASSED (0): exchange_optimised (0s)
PASSED (0): WeakReferences_arc (1s)
PASSED (0): alignTest_optimised (0s)
PASSED (0): hash_test_legacy_optimised (0s)
PASSED (0): FastRefCount_optimised (0s)
PASSED (0): PropertyIntrospectionTest2_arc (0s)
PASSED (0): alias (0s)
PASSED (0): exchange (0s)
SKIPPED: UnexpectedException
PASSED (0): Category_optimised (0s)
PASSED (0): WeakBlock_arc (0s)
PASSED (0): ResurrectInDealloc_arc_optimised (0s)
PASSED (0): ForeignException_optimised (0s)
PASSED (0): ForeignException_legacy (0s)
PASSED (0): ObjCXXEHInteropTwice_legacy_optimised (0s)
PASSED (0): IVarOverlap (0s)
PASSED (0): WeakImportClass (0s)
PASSED (0): msgInterpose (0s)
PASSED (0): ForeignException (0s)
PASSED (0): NilException (0s)
PASSED (0): Category_legacy (0s)
PASSED (0): category_properties_optimised (0s)
PASSED (0): ObjCXXEHInterop_legacy (0s)
PASSED (0): BlockTest_arc (0s)
PASSED (0): NestedExceptions_legacy_optimised (0s)
PASSED (0): RuntimeTest_legacy_optimised (0s)
PASSED (0): PropertyAttributeTest (0s)
PASSED (0): SuperMethodMissing (0s)
PASSED (0): NilException_optimised (0s)
PASSED (0): PropertyIntrospectionTest_optimised (0s)
PASSED (0): ProtocolCreation (0s)
PASSED (0): FastARCPool_legacy_optimised (0s)
PASSED (0): ConstantString_legacy (0s)
PASSED (0): Category (0s)
PASSED (0): exchange_legacy (0s)
PASSED (0): FastPathAlloc (0s)
PASSED (0): ProtocolCreation_legacy_optimised (0s)
PASSED (0): alignTest (0s)
PASSED (0): RuntimeTest_optimised (0s)
Segmentation fault
FAILED (139): BlockImpTest (0s)
No output written to stdout.
PASSED (0): SuperMethodMissing_legacy_optimised (0s)
PASSED (0): BlockTest_arc_optimised (0s)
PASSED (0): WeakRefLoad (0s)
PASSED (0): alignTest_legacy (0s)
PASSED (0): NestedExceptions (0s)
PASSED (0): DirectMethods_optimised (0s)
PASSED (0): BoxedForeignException (0s)
PASSED (0): Forward_legacy (0s)
PASSED (0): AllocatePair_legacy (0s)
PASSED (0): CXXExceptions (0s)
PASSED (0): DirectMethods (0s)
PASSED (0): AssociatedObject_legacy (0s)
PASSED (0): WeakImportClass_optimised (0s)
PASSED (0): ivar_arc_optimised (0s)
PASSED (0): ivar_atomic (0s)
PASSED (0): Forward_legacy_optimised (0s)
PASSED (0): ForwardDeclareProtocolAccess (0s)
PASSED (0): ObjCXXEHInterop_optimised (0s)
PASSED (0): NestedExceptions_optimised (0s)
PASSED (0): FastARCPool (0s)
PASSED (0): ProtocolExtendedProperties (0s)
Segmentation fault
FAILED (139): BlockImpTest_optimised (0s)
No output written to stdout.
PASSED (0): ExceptionTest_legacy_optimised (0s)
PASSED (0): ProtocolCreation_optimised (0s)
PASSED (0): IVarOverlap_legacy (0s)
PASSED (0): ConstantString_optimised (0s)
PASSED (0): ARCTest_arc (0s)
PASSED (0): SuperMethodMissing_legacy (0s)
PASSED (0): setSuperclass_optimised (0s)
PASSED (0): WeakRefLoad_legacy (0s)
PASSED (0): PropertyIntrospectionTest_legacy_optimised (0s)
PASSED (0): AssociatedObject2_optimised (0s)
PASSED (0): WeakRefLoad_legacy_optimised (0s)
PASSED (0): ObjCXXEHInterop_arc (0s)
PASSED (0): setSuperclass (0s)
PASSED (0): RuntimeTest (0s)
PASSED (0): setSuperclass_legacy_optimised (0s)
PASSED (0): objc_msgSend_legacy (0s)
PASSED (0): hash_table_delete (0s)
PASSED (0): ConstantString_legacy_optimised (0s)
PASSED (0): WeakRefLoad_optimised (0s)
PASSED (0): IVarSuperclassOverlap_optimised (0s)
PASSED (0): ExceptionTest_optimised (0s)
PASSED (0): msgInterpose_optimised (0s)
PASSED (0): alias_legacy (0s)
PASSED (0): hash_test (2s)
SKIPPED: UnexpectedException_optimised
PASSED (0): ManyManySelectors_legacy (1s)
PASSED (0): alias_legacy_optimised (0s)
PASSED (0): FastRefCount (0s)
PASSED (0): FastARC_legacy_optimised (0s)
PASSED (0): ForwardDeclareProtocolAccess_legacy_optimised (0s)
PASSED (0): ivar_atomic_legacy_optimised (0s)
PASSED (0): ManyManySelectors (1s)
PASSED (0): msgInterpose_legacy (0s)
PASSED (0): WeakBlock_arc_optimised (0s)
PASSED (0): exchange_legacy_optimised (0s)
PASSED (0): ExceptionTest (0s)
Segmentation fault
FAILED (139): BlockImpTest_legacy_optimised (0s)
No output written to stdout.
PASSED (0): ProtocolCreation_legacy (0s)
PASSED (0): ExceptionTest_legacy (0s)
PASSED (0): IVarSuperclassOverlap (0s)
PASSED (0): setSuperclass_legacy (0s)
PASSED (0): hash_table_delete_legacy (0s)
PASSED (0): MethodArguments_optimised (0s)
PASSED (0): ForwardDeclareProtocolAccess_optimised (0s)
PASSED (0): msgInterpose_legacy_optimised (0s)
PASSED (0): zeroSizedIVar_legacy_optimised (0s)
PASSED (0): IVarSuperclassOverlap_legacy_optimised (0s)
PASSED (0): ObjCXXEHInteropTwice_optimised (0s)
PASSED (0): ForwardDeclareProtocolAccess_legacy (0s)
PASSED (0): category_properties (0s)
PASSED (0): Forward_optimised (0s)
PASSED (0): AssociatedObject2_legacy_optimised (0s)
PASSED (0): ObjCXXEHInterop (0s)
PASSED (0): FastRefCount_legacy (0s)
PASSED (0): FastRefCount_legacy_optimised (0s)
PASSED (0): ProtocolExtendedProperties_legacy_optimised (0s)
PASSED (0): NilException_legacy (0s)
PASSED (0): ivar_arc (0s)
PASSED (0): PropertyIntrospectionTest (0s)
PASSED (0): PropertyIntrospectionTest_legacy (0s)
PASSED (0): objc_msgSend_legacy_optimised (0s)
PASSED (0): ivar_atomic_legacy (0s)
PASSED (0): Category_legacy_optimised (0s)
PASSED (0): ConstantString (0s)
PASSED (0): ObjCXXEHInteropTwice_legacy (0s)
PASSED (0): WeakReferences_arc_optimised (2s)
PASSED (0): ivar_atomic_optimised (0s)
PASSED (0): AllocatePair_legacy_optimised (0s)
PASSED (0): zeroSizedIVar_optimised (0s)
PASSED (0): FastARCPool_legacy (0s)
PASSED (0): hash_test_optimised (0s)
PASSED (0): AssociatedObject (0s)
PASSED (0): MethodArguments (0s)
PASSED (0): ResurrectInDealloc_arc (0s)
PASSED (0): ForeignException_legacy_optimised (0s)
PASSED (0): AssociatedObject2_legacy (0s)
PASSED (0): NestedExceptions_legacy (0s)
PASSED (0): ObjCXXEHInterop_legacy_optimised (0s)
PASSED (0): CXXExceptions_legacy_optimised (0s)
PASSED (0): FastARC (0s)
PASSED (0): PropertyIntrospectionTest2_arc_optimised (0s)
PASSED (0): hash_table_delete_optimised (0s)
PASSED (0): AssociatedObject_optimised (0s)
PASSED (0): FastARC_optimised (0s)
PASSED (0): zeroSizedIVar (0s)
PASSED (0): hash_table_delete_legacy_optimised (0s)
PASSED (0): objc_msgSend (0s)
PASSED (0): NilException_legacy_optimised (0s)
PASSED (0): AssociatedObject2 (0s)
PASSED (0): PropertyAttributeTest_legacy_optimised (0s)
PASSED (0): IVarOverlap_legacy_optimised (0s)
PASSED (0): WeakImportClass_legacy_optimised (0s)
PASSED (0): CXXExceptions_legacy (0s)
PASSED (0): ProtocolExtendedProperties_legacy (0s)
PASSED (0): BoxedForeignException_legacy (0s)
PASSED (0): ObjCXXEHInterop_arc_optimised (0s)
PASSED (0): SuperMethodMissing_optimised (0s)
PASSED (0): WeakImportClass_legacy (0s)
PASSED (0): ProtocolExtendedProperties_optimised (0s)
PASSED (0): objc_msgSend_optimised (0s)
PASSED (0): PropertyAttributeTest_optimised (0s)
PASSED (0): CXXExceptions_optimised (0s)
PASSED (0): PropertyAttributeTest_legacy (0s)
PASSED (0): AllocatePair (0s)
PASSED (0): AllocatePair_optimised (0s)
PASSED (0): MethodArguments_legacy_optimised (0s)
PASSED (0): hash_test_legacy (2s)
PASSED (0): IVarOverlap_optimised (0s)
Segmentation fault
FAILED (139): BlockImpTest_legacy (0s)
No output written to stdout.
PASSED (0): ObjCXXEHInteropTwice (0s)
PASSED (0): Forward (0s)
PASSED (0): zeroSizedIVar_legacy (0s)
PASSED (0): IVarSuperclassOverlap_legacy (0s)
PASSED (0): ManyManySelectors_optimised (1s)
PASSED (0): AssociatedObject_legacy_optimised (0s)
PASSED (0): RuntimeTest_legacy (0s)
SKIPPED: UnexpectedException_legacy
PASSED (0): alias_optimised (0s)
PASSED (0): FastARCPool_optimised (0s)
PASSED (0): ManyManySelectors_legacy_optimised (1s)
97% Passed. Total: 190, Passed: 182, Skipped: 4, Failed: 4
Finished running tests. Exiting.

This branch

100% Passed. Total: 190, Passed: 186, Skipped: 4, Failed: 0 Finished running tests. Exiting.

Log
hmelder@Hugos-MacBook-Pro libobjc2 % .github/scripts/android_test_main.sh build ${ANDROID_TOOLCHAIN}/sysroot aarch64-linux-android
adbd is already running as root
cp: build/Test/CMakeFiles is a directory (not copied).
/var/folders/jn/wky_dz4j3ll7_49hbtg73hdr0000gn/T/tmp.3x2Ib3A2qQ/: 192 files pushed, 0 skipped. 350.4 MB/s (26161943 bytes in 0.071s)
build/../.github/scripts/android_test_driver.sh: 1 file pushed, 0 skipped. 19.8 MB/s (1738 bytes in 0.000s)
SKIPPED: UnexpectedException_legacy_optimised
PASSED (0): MethodArguments_legacy (0s)
PASSED (0): FastARC_legacy (0s)
PASSED (0): alignTest_legacy_optimised (0s)
PASSED (0): FastPathAlloc_optimised (0s)
PASSED (0): BoxedForeignException_legacy_optimised (0s)
PASSED (0): ARCTest_arc_optimised (0s)
PASSED (0): BoxedForeignException_optimised (0s)
PASSED (0): exchange_optimised (0s)
PASSED (0): WeakReferences_arc (1s)
PASSED (0): alignTest_optimised (0s)
PASSED (0): hash_test_legacy_optimised (1s)
PASSED (0): FastRefCount_optimised (0s)
PASSED (0): PropertyIntrospectionTest2_arc (0s)
PASSED (0): alias (0s)
PASSED (0): exchange (0s)
SKIPPED: UnexpectedException
PASSED (0): Category_optimised (0s)
PASSED (0): WeakBlock_arc (0s)
PASSED (0): ResurrectInDealloc_arc_optimised (0s)
PASSED (0): ForeignException_optimised (0s)
PASSED (0): ForeignException_legacy (0s)
PASSED (0): ObjCXXEHInteropTwice_legacy_optimised (0s)
PASSED (0): IVarOverlap (0s)
PASSED (0): WeakImportClass (0s)
PASSED (0): msgInterpose (0s)
PASSED (0): ForeignException (0s)
PASSED (0): NilException (0s)
PASSED (0): Category_legacy (0s)
PASSED (0): category_properties_optimised (0s)
PASSED (0): ObjCXXEHInterop_legacy (0s)
PASSED (0): BlockTest_arc (0s)
PASSED (0): NestedExceptions_legacy_optimised (0s)
PASSED (0): RuntimeTest_legacy_optimised (0s)
PASSED (0): PropertyAttributeTest (0s)
PASSED (0): SuperMethodMissing (0s)
PASSED (0): NilException_optimised (0s)
PASSED (0): PropertyIntrospectionTest_optimised (0s)
PASSED (0): ProtocolCreation (0s)
PASSED (0): FastARCPool_legacy_optimised (0s)
PASSED (0): ConstantString_legacy (0s)
PASSED (0): Category (0s)
PASSED (0): exchange_legacy (0s)
PASSED (0): FastPathAlloc (0s)
PASSED (0): ProtocolCreation_legacy_optimised (0s)
PASSED (0): alignTest (0s)
PASSED (0): RuntimeTest_optimised (0s)
PASSED (0): BlockImpTest (0s)
PASSED (0): SuperMethodMissing_legacy_optimised (0s)
PASSED (0): BlockTest_arc_optimised (0s)
PASSED (0): WeakRefLoad (0s)
PASSED (0): alignTest_legacy (0s)
PASSED (0): NestedExceptions (0s)
PASSED (0): DirectMethods_optimised (0s)
PASSED (0): BoxedForeignException (0s)
PASSED (0): Forward_legacy (0s)
PASSED (0): AllocatePair_legacy (0s)
PASSED (0): CXXExceptions (0s)
PASSED (0): DirectMethods (0s)
PASSED (0): AssociatedObject_legacy (0s)
PASSED (0): WeakImportClass_optimised (0s)
PASSED (0): ivar_arc_optimised (0s)
PASSED (0): ivar_atomic (0s)
PASSED (0): Forward_legacy_optimised (0s)
PASSED (0): ForwardDeclareProtocolAccess (0s)
PASSED (0): ObjCXXEHInterop_optimised (0s)
PASSED (0): NestedExceptions_optimised (0s)
PASSED (0): FastARCPool (0s)
PASSED (0): ProtocolExtendedProperties (0s)
PASSED (0): BlockImpTest_optimised (0s)
PASSED (0): ExceptionTest_legacy_optimised (0s)
PASSED (0): ProtocolCreation_optimised (0s)
PASSED (0): IVarOverlap_legacy (0s)
PASSED (0): ConstantString_optimised (0s)
PASSED (0): ARCTest_arc (0s)
PASSED (0): SuperMethodMissing_legacy (0s)
PASSED (0): setSuperclass_optimised (0s)
PASSED (0): WeakRefLoad_legacy (0s)
PASSED (0): PropertyIntrospectionTest_legacy_optimised (0s)
PASSED (0): AssociatedObject2_optimised (0s)
PASSED (0): WeakRefLoad_legacy_optimised (0s)
PASSED (0): ObjCXXEHInterop_arc (0s)
PASSED (0): setSuperclass (0s)
PASSED (0): RuntimeTest (0s)
PASSED (0): setSuperclass_legacy_optimised (0s)
PASSED (0): objc_msgSend_legacy (0s)
PASSED (0): hash_table_delete (0s)
PASSED (0): ConstantString_legacy_optimised (0s)
PASSED (0): WeakRefLoad_optimised (0s)
PASSED (0): IVarSuperclassOverlap_optimised (0s)
PASSED (0): ExceptionTest_optimised (0s)
PASSED (0): msgInterpose_optimised (0s)
PASSED (0): alias_legacy (0s)
PASSED (0): hash_test (2s)
SKIPPED: UnexpectedException_optimised
PASSED (0): ManyManySelectors_legacy (1s)
PASSED (0): alias_legacy_optimised (0s)
PASSED (0): FastRefCount (0s)
PASSED (0): FastARC_legacy_optimised (0s)
PASSED (0): ForwardDeclareProtocolAccess_legacy_optimised (0s)
PASSED (0): ivar_atomic_legacy_optimised (0s)
PASSED (0): ManyManySelectors (1s)
PASSED (0): msgInterpose_legacy (0s)
PASSED (0): WeakBlock_arc_optimised (0s)
PASSED (0): exchange_legacy_optimised (0s)
PASSED (0): ExceptionTest (0s)
PASSED (0): BlockImpTest_legacy_optimised (0s)
PASSED (0): ProtocolCreation_legacy (0s)
PASSED (0): ExceptionTest_legacy (0s)
PASSED (0): IVarSuperclassOverlap (0s)
PASSED (0): setSuperclass_legacy (0s)
PASSED (0): hash_table_delete_legacy (0s)
PASSED (0): MethodArguments_optimised (0s)
PASSED (0): ForwardDeclareProtocolAccess_optimised (0s)
PASSED (0): msgInterpose_legacy_optimised (0s)
PASSED (0): zeroSizedIVar_legacy_optimised (0s)
PASSED (0): IVarSuperclassOverlap_legacy_optimised (0s)
PASSED (0): ObjCXXEHInteropTwice_optimised (0s)
PASSED (0): ForwardDeclareProtocolAccess_legacy (0s)
PASSED (0): category_properties (0s)
PASSED (0): Forward_optimised (0s)
PASSED (0): AssociatedObject2_legacy_optimised (0s)
PASSED (0): ObjCXXEHInterop (0s)
PASSED (0): FastRefCount_legacy (0s)
PASSED (0): FastRefCount_legacy_optimised (0s)
PASSED (0): ProtocolExtendedProperties_legacy_optimised (0s)
PASSED (0): NilException_legacy (0s)
PASSED (0): ivar_arc (0s)
PASSED (0): PropertyIntrospectionTest (0s)
PASSED (0): PropertyIntrospectionTest_legacy (0s)
PASSED (0): objc_msgSend_legacy_optimised (0s)
PASSED (0): ivar_atomic_legacy (0s)
PASSED (0): Category_legacy_optimised (0s)
PASSED (0): ConstantString (0s)
PASSED (0): ObjCXXEHInteropTwice_legacy (0s)
PASSED (0): WeakReferences_arc_optimised (2s)
PASSED (0): ivar_atomic_optimised (0s)
PASSED (0): AllocatePair_legacy_optimised (0s)
PASSED (0): zeroSizedIVar_optimised (0s)
PASSED (0): FastARCPool_legacy (0s)
PASSED (0): hash_test_optimised (0s)
PASSED (0): AssociatedObject (0s)
PASSED (0): MethodArguments (0s)
PASSED (0): ResurrectInDealloc_arc (0s)
PASSED (0): ForeignException_legacy_optimised (0s)
PASSED (0): AssociatedObject2_legacy (0s)
PASSED (0): NestedExceptions_legacy (0s)
PASSED (0): ObjCXXEHInterop_legacy_optimised (0s)
PASSED (0): CXXExceptions_legacy_optimised (0s)
PASSED (0): FastARC (0s)
PASSED (0): PropertyIntrospectionTest2_arc_optimised (0s)
PASSED (0): hash_table_delete_optimised (0s)
PASSED (0): AssociatedObject_optimised (0s)
PASSED (0): FastARC_optimised (0s)
PASSED (0): zeroSizedIVar (0s)
PASSED (0): hash_table_delete_legacy_optimised (0s)
PASSED (0): objc_msgSend (0s)
PASSED (0): NilException_legacy_optimised (0s)
PASSED (0): AssociatedObject2 (0s)
PASSED (0): PropertyAttributeTest_legacy_optimised (0s)
PASSED (0): IVarOverlap_legacy_optimised (0s)
PASSED (0): WeakImportClass_legacy_optimised (0s)
PASSED (0): CXXExceptions_legacy (0s)
PASSED (0): ProtocolExtendedProperties_legacy (0s)
PASSED (0): BoxedForeignException_legacy (0s)
PASSED (0): ObjCXXEHInterop_arc_optimised (0s)
PASSED (0): SuperMethodMissing_optimised (0s)
PASSED (0): WeakImportClass_legacy (0s)
PASSED (0): ProtocolExtendedProperties_optimised (0s)
PASSED (0): objc_msgSend_optimised (0s)
PASSED (0): PropertyAttributeTest_optimised (0s)
PASSED (0): CXXExceptions_optimised (0s)
PASSED (0): PropertyAttributeTest_legacy (0s)
PASSED (0): AllocatePair (0s)
PASSED (0): AllocatePair_optimised (0s)
PASSED (0): MethodArguments_legacy_optimised (0s)
PASSED (0): hash_test_legacy (2s)
PASSED (0): IVarOverlap_optimised (0s)
PASSED (0): BlockImpTest_legacy (0s)
PASSED (0): ObjCXXEHInteropTwice (0s)
PASSED (0): Forward (0s)
PASSED (0): zeroSizedIVar_legacy (0s)
PASSED (0): IVarSuperclassOverlap_legacy (0s)
PASSED (0): ManyManySelectors_optimised (1s)
PASSED (0): AssociatedObject_legacy_optimised (0s)
PASSED (0): RuntimeTest_legacy (0s)
SKIPPED: UnexpectedException_legacy
PASSED (0): alias_optimised (0s)
PASSED (0): FastARCPool_optimised (0s)
PASSED (0): ManyManySelectors_legacy_optimised (1s)
100% Passed. Total: 190, Passed: 186, Skipped: 4, Failed: 0
Finished running tests. Exiting.

@hmelder hmelder requested a review from qmfrederik November 26, 2024 09:23
@hmelder
Copy link
Collaborator Author

hmelder commented Dec 2, 2024

ping :)

@davidchisnall
Copy link
Member

Sorry, I've been off ill for a couple of weeks and just catching up.

If I understand correctly, this is now embedding the displacement in the code and loading it. I don't really like that: it increases the code size, and that wastes more space in the data page, for a fairly niche corner case. On 32-bit platforms, we are very unlikely to ever see page sizes that are not 4 KiB. On 64-bit ones, we typically have, at most, two out of 4, 16, and 64 KiB as the smallest granule size. It would be less code to dynamically select between those cases.

Note that the only down side in using larger pages is if we need more instructions to find the address of the data page. This means that, if you need to support both 16 and 64 KiB page, it probably isn't worth supporting 16 KiB, just round up to 64 KiB.

On AArch64, I think we just need an extra adrp instruction. That, unfortunately, pushes the code size up to 20 bytes per trampoline. We currently store both the block pointer and the block invoke pointer in the data page. Given that the block pointer is a fixed offset, you possibly could have one page of block pointers and three pages of code, with the displacement calculated by rounding down the current address and subtracting offsets, if you could fit that in three more instructions. If not, we'll just have to waste some space on platforms with 16 KiB pages.

@hmelder
Copy link
Collaborator Author

hmelder commented Dec 2, 2024

On 32-bit platforms, we are very unlikely to ever see page sizes that are not 4 KiB.
Agreed.

On AArch64 we can probably patch the imm of the ADR op code, thus not increasing the size of the trampoline.
But this is a platform-specific hack. Tedious if we want to support flexible page sizes on other 64-bit ISAs as well.

From https://developer.arm.com/documentation/dui0801/h/A64-General-Instructions/ADR

Its offset from the address of this instruction, in the range ±1MB.

if you need to support both 16 and 64 KiB page, it probably isn't worth supporting 16 KiB, just round up to 64 KiB.

Would this mean that we have to allocate 16 pages when running on a platform with 4KiB pages?

@davidchisnall
Copy link
Member

Would this mean that we have to allocate 16 pages when running on a platform with 4KiB pages?

Yes, but that's still only 128 KiB of total (code + data regions), and then we allocate trampolines from within that. I think these days it's probably fine to waste 120 KiB of memory in a process on a 64-bit system.

For systems with 4 KiB pages, it's better to keep the current code, but if a system supports 16 KiB and 64 KiB page sizes, the effort in supporting 16 KiB probably isn't worth it. The size that we care about is the minimum protection granule: we need to be able to mprotect a range of that size. If we can support 64 KiB with the same trampoline size as 16 KiB, then we're wasting only 96 KiB, which is in the noise for most 64-bit programs.

@hmelder
Copy link
Collaborator Author

hmelder commented Dec 3, 2024

Got it. So you prefer this approach to patching op code immediates?

@davidchisnall
Copy link
Member

If we have to patch immediates, I guess that's okay. Ideally I'd prefer that we have 1-2 versions per arch and we select the appropriate one.

@hmelder
Copy link
Collaborator Author

hmelder commented Dec 3, 2024

Ideally I'd prefer that we have 1-2 versions per arch and we select the appropriate one.

Huh that is actually the simplest thing to do: Just have 4k, 16k, 64k trampolines for AArch64 (and probably RISC-V and PowerPC) and copy the correct trampoline based on getpagesize. No hacky opcode patching involved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants