Redline maven plugin - #131
Conversation
b659f62 to
7b5388f
Compare
|
on hold, not having jffi requires too much Java versions contorsionism. |
Architecture: - Bridge module uses exec:java with Generator.main() instead of the Maven plugin, breaking the circular dependency (plugin → redline → bridge → plugin) - New redline/build-time-compiler module with RedlineGenerator that handles native code generation and extends generated sources with builder()/safeBuilder()/loadNativeCode() methods - Maven plugin calls RedlineGenerator when <redlineTargets> is configured Config extended with: - redlineTargets: list of target triples for cross-compilation - targetResourceFolder: where .native files are written Generated module class gains (when redlineTargets configured): - loadNativeCode(): loads platform-specific native code from resources - builder(): automatic backend selection (native if platform + Java 25 supported, bytecode otherwise) - safeBuilder(): always uses bytecode compiler NativeMachineFactory.Builder gains toInstanceBuilder() to return a configured Instance.Builder for the generated builder() method. RedlineTarget gains fromTriple() for target triple lookup.
- Add <redline>true</redline> shortcut to compile for all supported platforms (instead of listing 6 target triples) - Add redline/it module with Maven Invoker integration test: - Compiles add.wat.wasm with native code for all platforms - Tests builder() (native), safeBuilder() (bytecode), loadNativeCode() - Verifies native and bytecode produce identical results - Add logging when redline native compilation runs
7b5388f to
66ffb2e
Compare
- Add Rust toolchain + cranelift_bridge.wasm build to ci.yaml - Remove -Predline from release.yaml and redline.yaml - Plugin depends directly on redline-build-time-compiler (no reflection) - Bridge uses exec:java with GeneratorMain to break the cycle - Generated code uses NativeMachineFactoryProvider SPI (no Panama import) - Remove redundant targetResourceFolder from Config - Validate target triples before compilation in RedlineGenerator - E2E tests: JFFI (all JDKs) + Panama (JDK 25+ only) - Restore javadoc comments on Mojo fields
401e2a6 to
f58545f
Compare
| } | ||
|
|
||
| @Test | ||
| public void nativeCodeIsAvailable() { |
There was a problem hiding this comment.
this is machine dependent
| "var host = RedlineTarget.detectHost().orElse(null);")); | ||
|
|
||
| initBody.addStatement( | ||
| StaticJavaParser.parseStatement( |
There was a problem hiding this comment.
no parseStatement + string interpolation, we should use plain JavaParser to build the desired code, is more maintainable in the longer run
| <dependencies> | ||
| <dependency> | ||
| <groupId>com.github.javaparser</groupId> | ||
| <artifactId>javaparser-core</artifactId> |
There was a problem hiding this comment.
javaparser as a dependency of the build time compiler looks a little strange, but maybe worth if it keeps complexity low.
| </dependency> | ||
| <dependency> | ||
| <groupId>run.endive</groupId> | ||
| <artifactId>runtime</artifactId> |
There was a problem hiding this comment.
isn't runtime a transitive dependency of redline?
| <dependencies> | ||
| <dependency> | ||
| <groupId>run.endive</groupId> | ||
| <artifactId>redline-api-experimental</artifactId> |
There was a problem hiding this comment.
do we need to explicitly add the api module? isn't it transitive from runner?
| <configuration> | ||
| <name>endive.test.AddModule</name> | ||
| <wasmFile>src/test/resources/add.wat.wasm</wasmFile> | ||
| <interpreterFallback>WARN</interpreterFallback> |
| } | ||
|
|
||
| @Test | ||
| public void nativeCodeIsAvailable() { |
There was a problem hiding this comment.
this is machine dependent
| <version>0.0-SNAPSHOT</version> | ||
| <packaging>jar</packaging> | ||
|
|
||
| <dependencies> |
There was a problem hiding this comment.
same comments as above for the transitive deps
Replace Rust toolchain + make all in CI with inlay-maven-plugin fetching the pre-built wasm from ghcr.io/bytecodealliance/endive-cranelift-bridge. No Rust needed in any CI workflow except the new wasm-publish.yaml. - Bridge POM: inlay:fetch before exec:java GeneratorMain - Root POM: add inlay-maven-plugin to pluginManagement - CI/redline/release workflows: remove Rust toolchain steps - New wasm-publish.yaml: build + publish wasm to GHCR on wasm-build changes - wkg.lock: pins wasm digest for reproducible builds
The it module is unconditional (builds on all JDKs) but redline-runner-experimental requires JDK 25+. The Panama E2E test project declares its own dependency via @project.version@.
The it module is unconditional but redline-runner-experimental requires JDK 25+. Move it to a java25 profile so it only resolves on JDK 25+ where the Panama E2E test actually runs.
Matches the redlineExperimental flag naming — both are user-facing plugin parameters for the experimental redline feature.
Replace parseStatement + string concatenation with direct AST node construction, matching the idiom already used by build-time-compiler's Generator (which has zero parse calls in its codegen). Each generator method now carries a comment showing the code it emits. Generated output is unchanged.
- Drop redline-api and runtime from the E2E POMs; both come transitively from the runner, leaving a single consumer dependency - Drop interpreterFallback=WARN; the trivial add module never needs it and FAIL (the default) is the stricter check - Guard nativeCodeIsAvailable with an assumption on detectHost(), so it skips rather than fails on platforms Redline does not target
Two bugs that would have made the publish automation a no-op or produced an unpullable artifact: - It pushed :latest while the bridge POM consumes :999.0.0-SNAPSHOT, so republishing would never update what the build actually reads. The tag now lives in one env var, noted as needing to match the POM. - It pushed from the repo root, so the image title annotation became "redline/cranelift_bridge.wasm" and the OCI client tried to write into a directory that does not exist on pull. Push from redline/ instead. Also emit the wkg.lock refresh command in the job summary, since a publish invalidates the pinned digest until the lock file is updated.
Removing " -Predline" also consumed the following newline in three places, concatenating commands: "versions:set ... git add ." would run git as a Maven lifecycle phase, and "clean deploy" stopped being its own command. One -Predline also survived, referencing a profile this PR deletes. The release workflow could not have succeeded.
detectHost() used isAarch64 as its only discriminator, so every other architecture fell through to the x86_64 variant. On Linux/riscv64 (or ppc64le, s390x, 32-bit ARM) it returned LINUX_X86_64, the .x86_64-linux.native resource loaded, and the runner handed x86-64 machine code to the CPU — a JVM crash rather than a fallback to the build-time compiler. Recognise x86_64/amd64/x64 explicitly and return empty otherwise, which routes those platforms to the compiled-bytecode path. Adds the first tests for RedlineTarget, using the endive.redline.os.* overrides.
Correctness: - discover() caught ServiceConfigurationError around the loop body, but ServiceLoader raises it from the iterator, so a for-each let it escape. Wrap next() instead, and also catch LinkageError: the Panama runner is compiled for 25 and fails to link on older JDKs, which is exactly the case the catch was meant to tolerate. - NativeCodeSerializer allocated byte[count][] straight from the file, so a corrupt count became OutOfMemoryError before truncation could be detected. Reject negative counts and lengths and collect incrementally. - A corrupt blob threw UncheckedIOException from a static initializer, which bricks the class for the life of the JVM. Load into a local and leave CODE null instead, so builder() degrades to compiled bytecode. DX: - Generate nativeProvider(), non-empty exactly when builder() takes the native path, and have builder() use it as the single source of truth. This makes the choice observable, and gives modules with imported memories the provider they must create those imports with. - Assert in both E2Es that the native path actually engages. Every other assertion there passes when it silently does not, because the fallback produces identical results. Cleanup: drop the unused Cli.execute overload, put expected before actual in the E2E assertEquals calls, and rename the generator's interpreterBuilder helper to compiledBuilder, which is what it emits.
Since redline builds unconditionally and no longer needs -Predline or a Rust toolchain, ci.yaml runs the identical command on a superset of the platforms: it covers ubuntu-latest/25 and macos-latest/25 (exactly the redline matrix), pins the same testsuite ref and sets the same MAVEN_OPTS. Note this leaves redline covered only by jobs with continue-on-error, so redline failures no longer turn the build red on their own.
No description provided.