Skip to content

An image builds and answers - #8

Merged
tamnd merged 2 commits into
mainfrom
graalvm
Aug 20, 2026
Merged

tamnd merged 2 commits into
mainfrom
graalvm

Conversation

@tamnd

@tamnd tamnd commented Aug 20, 2026

Copy link
Copy Markdown
Owner

A native image has no linker in it. Every downcall stub is machine code written while the image is being built, and the builder can only write the ones it was told about, because a FunctionDescriptor here is assembled out of ordinary objects at run time and there is nothing in the bytecode to read it off. Told nothing, the image builds clean and dies on the first query.

Both artifacts carry their own reachability metadata now. zudb-ffm lists every signature it binds, and zudb-native registers the libraries so that a platform's library ends up inside the image rather than being looked for on a machine that has never had one installed. A classifier is the right dependency for an image, since the platform-complete jar would put seven libraries in it and use one.

The list is not maintained, it is derived. Forty-odd entries nobody reads with one of them stale is exactly the failure this is meant to prevent, so Shapes remembers every shape as it is bound, ReachabilityTest writes out what that comes to, and the build fails if the file in the repository says something else, with the file that would have been right sitting in target/ and the assertion message saying so. Adding a function to the C ABI therefore either changes nothing here, because its shape is one of the forty already listed, or fails loudly with the answer attached.

Sorted rather than in binding order, so the file is the same file however Abi's constructor is rearranged and a diff on it is about what changed rather than about what moved. The two critical bindings get their own entries, because a stub for a critical call is not the same machine code as a stub for an ordinary one even where the signature is identical.

That test can only say the file matches the binding. Whether it is the file the image builder actually wanted is a thing only an image can answer, so CI builds one on Linux and macOS and makes it run a query, with no property, no environment variable, and the library coming out of the image. The metadata schema is the one place here I could not check locally, since there is no GraalVM on this machine, which is exactly why that job exists.

tamnd added 2 commits August 20, 2026 09:43
A native image has no linker in it. Every downcall stub is machine code
written while the image is being built, and the builder can only write
the ones it was told about, because a function descriptor here is
assembled out of ordinary objects at run time and there is nothing in
the bytecode to read it off. Told nothing, an image builds clean and
dies on the first query.

So both artifacts carry their own metadata. zudb-ffm lists every
signature it binds and zudb-native registers the libraries, so that a
platform's library ends up inside the image rather than being looked for
on a machine that has never had one installed.

The list is not maintained, it is derived. Forty-odd entries nobody
reads, one of them stale, is exactly the failure this is supposed to
prevent, so every binding registers its shape as it is made, a test
writes out what that comes to, and the build fails if the file in the
repository says something else, with the file that would have been right
sitting in target/. Adding a function to the C ABI therefore either
changes nothing here, because its shape is one of the forty already
listed, or fails loudly with the answer attached.

That test can only say the file matches the binding. Whether it is the
file the image builder wanted is a thing only an image can answer, so CI
builds one on Linux and macOS and makes it run a query, with no
property, no environment variable and the library coming out of the
image.
The image builder reads canonical layouts, the ones Linker.canonicalLayouts
answers to, so a pointer is void* and not pointer. It said so, on the
first native image anyone has built of this.

long long rather than long for a 64-bit integer, and that is not
pedantry: C's long is four bytes on Windows and eight everywhere else,
and this file is written once and read on all of them.
@tamnd
tamnd merged commit 34cc6b9 into main Aug 20, 2026
13 checks passed
@tamnd
tamnd deleted the graalvm branch August 20, 2026 03:03
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.

1 participant