Skip to content

Migration to Foreign Function & Memory API (Draft)#101

Open
PRIESt512 wants to merge 2 commits intoodnoklassniki:masterfrom
PRIESt512:refuse_unsafe_preview
Open

Migration to Foreign Function & Memory API (Draft)#101
PRIESt512 wants to merge 2 commits intoodnoklassniki:masterfrom
PRIESt512:refuse_unsafe_preview

Conversation

@PRIESt512
Copy link
Copy Markdown

Migration to Foreign Function & Memory API

Summary

Investigate the feasibility of migrating a library from Unsafe to the new and safer Foreign Function & Memory API. This will enable the library to function in future Java versions after the removal of Unsafe functionality critical to the library.
This is a draft version of adapting the project to new Java conditions.

Goals

  • Evaluate the use of Foreign Function & Memory API, specifically MemorySegment, for partial replacement of Unsafe. The evaluation is based solely on the one.nio.serial component.
  • Assess performance degradation with the new approach.
  • Identify entry points for modernizing the project to adapt to newer Java versions.

Non-goals

  • Modify the entire library; the focus at this stage is on one part of the project without ensuring compatibility with other project APIs.
  • Ensure all tests pass; only the one.nio.serial component is of interest.

Description

For this modification, I did not consider the entire project functionality that relies on serialization. Since my focus is on modernizing serialization at this stage, I intentionally commented out or skipped code sections that are not relevant.
This branch does not support backward compatibility with Java 8; the minimum build version is set to Java 22 due to the use of Foreign Function & Memory API and operates only within Java versions 22 to 23.
A particular interest is the performance impact after moving away from Unsafe. Initial simple performance tests indicate that abandoning Unsafe results in up to a 20% performance drop.

With Unsafe (serialization and deserialization of a POJO object):

Benchmark                           Mode  Cnt      Score      Error   Units
BenchmarkRunner.testSerialization  thrpt    5  75657.000 ± 5323.225  ops/ms

With MemorySegment (serialization and deserialization of a POJO object):

Benchmark                           Mode  Cnt      Score       Error   Units
BenchmarkRunner.testSerialization  thrpt    5  61702.604 ± 735.608  ops/ms

This branch passes all tests for the one.nio.serial component.

@PRIESt512 PRIESt512 marked this pull request as ready for review June 13, 2025 17:15
@PRIESt512 PRIESt512 changed the title Migration to Foreign Function & Memory API Migration to Foreign Function & Memory API (Draft) Jun 13, 2025
@lehvolk
Copy link
Copy Markdown
Collaborator

lehvolk commented Sep 1, 2025

@PRIESt512 should this PR be treated as review ready?

@lehvolk lehvolk requested review from lamtev and lehvolk September 1, 2025 12:55
@lehvolk
Copy link
Copy Markdown
Collaborator

lehvolk commented Sep 1, 2025

@PRIESt512 could you please merge the upstream? And keep in mind #104

@PRIESt512
Copy link
Copy Markdown
Author

@lehvolk Not yet, this is a raw version - just a draft. I would appreciate help from the developers of this library. I have a few questions. Questions - is it worth switching to FFM API strictly from Java 22. Or should I make the switch as soon as Unsafe support is removed? Java developers themselves admit that FFM API does not provide full speed parity vs Unsafe - FFM vs. Unsafe. Safety (Sometimes) Has a Cost. Potential performance loss - wouldn't this be a "backwards compatibility break" for all users of the library? When migrating to a new version of Java and a new version of the library - this can be documented and users can be explicitly warned of the possible regression. But as part of an intermediate update of the library of old versions of Java, this may be unexpected. Plus, the current version only takes into account the improvements for the serialization module. But when I studied the library in more detail, it is still necessary to solve the processing of raw pointers to memory, which in the current version is based on Unsafe. This is necessary so that other library modules can correctly use serialization

@max-kammerer
Copy link
Copy Markdown
Collaborator

@PRIESt512 I think it's worth to add a flag allowing switching from Unsafe to New FFMA implementation. So user can explicitly choose appropriate behavior and we can benchmark both variants on same JVMs. With one of the next major releases (e.g. 3.0), the default behaviour could be switched to FFMA with explicit clarification for users.

But when I studied the library in more detail, it is still necessary to solve the processing of raw pointers to memory, which in the current version is based on Unsafe. This is necessary so that other library modules can correctly use serialization

Do you mean the case when Unsafe would be totally removed? If smth else, please provide more details for clarifications.

Another usefult tips: I've just merged build changes, that enable building multi-release jar and configuring jdk specific tests and sources: Java 16 Tests with records and Java 9 source set for serialization changes in upcoming PRs. You can use similar changes for establishing infrastructure for FFMA

@PRIESt512
Copy link
Copy Markdown
Author

@max-kammerer Add flag - yes, looks good. By handling raw pointers, I meant that the serialization package is used inside the library by other components. For example, SharedMemoryMap, MappedFile, Rpc, etc. And there they use off-heap memory allocation using Unsafe. The address of the allocated memory is passed, among other things, to classes for serialization.

Since replacing Unsafe for a library at once is quite a big job, you can first remove the use of Unsafe in the serialization module. Then it turns out that at some point in time the library will have a mixture of Unsafe and FFM API. The following construct is suitable for using a raw pointer in the FFM API:

MemorySegment memSegment = MemorySegment.ofAddress(rawPointer).reinterpret(size);

It is necessary to check the correct operation of all blocks in the library in such a mixed mode, so as not to break everything.
Yes, your latest PR with multi-release support makes it easier to integrate code for specific Java versions - thanks 💯

P.S. In general, it would be possible to use varhandle instead of FFM API, but varhandle has a maximum off-heap size that it can work with - 2 GB. But then the interface between the serialization module and the rest of the library will break. (I have a working version on varhandle instead of Unsafe, but only the serialization module works correctly there).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants