Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ dependencies {
implementation libs.asm.util // ASM utilities
implementation libs.icu4j // Unicode support
implementation libs.jsoup // HTML5 parsing for HTML::Content::Extractor
implementation libs.jing // RELAX NG validation for XML::LibXML
implementation libs.snakeyaml.engine // YAML processing
implementation libs.tomlj // TOML processing
implementation libs.commons.csv // CSV processing
Expand All @@ -226,6 +227,8 @@ dependencies {
implementation libs.sqlite.jdbc // SQLite JDBC driver
implementation libs.bcprov // Bouncy Castle crypto (SHA-3, Keccak, etc.)
implementation libs.bcpkix // Bouncy Castle PEM/PKCS parsing
implementation libs.snappy.java // Official Sereal Java codec compression
implementation libs.zstd.jni // Official Sereal Java codec compression
implementation 'org.jruby.joni:joni:2.2.7' // Stack-safe recursive regex backend
implementation 'io.netty:netty-codec-http:4.1.115.Final' // Netty HTTP codec for PSGI server

Expand Down
76 changes: 76 additions & 0 deletions dev/design/jcpan-compiler-tooling-followup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# jcpan compiler and tooling follow-up

## Goal

Remove shared PerlOnJava compiler/runtime/tooling blockers encountered while testing Data::Checks, POE::Component::MessageQueue, Net::Server::POP3::Skeleton, Mail::BIMI, Imager::Album, Test::Mimic::Recorder, Fuse::Filesys::Virtual, and their dependencies. Distribution preferences are deliberately avoided.

## Implementation

### Compiler and runtime semantics

- Tied `@ISA` values are fetched through the tie interface during method resolution.
- Constant subroutines preserve their scalar-reference stash proxy without losing the callable CODE slot.
- `use open` defaults are read from lexical `%^H` call-site snapshots instead of leaking through a process-global `${^OPEN}` value.

### Bundled module tooling

- `DynaLoader::dl_load_flags` is available to XS-style loaders.
- HTTP::Tiny installs each convenience verb once and returns its standard status-599 response for transport failures.
- Time::HiRes provides the requested `ualarm` export.
- XML::LibXML::RelaxNG uses Jing for schema compilation and validation.
- Sereal::Encoder and Sereal::Decoder use the official Booking.com Java codec with Snappy and Zstandard support.
- Cache::FastMmap has a JVM-backed compatibility implementation and preserves the distribution's Perl serialization, expiry, and callback layer. Its map is process-local; the share file is created for API compatibility.
- Crypt::OpenSSL::X509 and Crypt::OpenSSL::Verify use the existing Bouncy Castle/JCA stack rather than adding another crypto implementation.

The imported Sereal Java sources are based on upstream commit `9ad81cf3023ccc456c2accd83bea2c2803a82e16`.

## System-Perl exclusions

The following are not treated as PerlOnJava regressions because their current distributions or tests fail under the available system Perl or require unavailable platform facilities:

- Data::Checks: its fresh system-Perl dependency set lacks `builtin.pm`.
- Net::Server::POP3::Skeleton: the release metadata points `VERSION_FROM` at a nonexistent `lib/Tk/Carp.pm`.
- Imager::Album: its system-Perl dependency closure lacks Imager and relies on the legacy Gtk/display stack.
- Test::Mimic::Recorder: its own test fails on system Perl with a hard-coded reference-history assumption.
- Fuse::Filesys::Virtual: Fuse 0.16 refuses to configure on Darwin without OSXFUSE.
- POE::Component::MessageQueue: its remaining bind test cannot run in this sandbox; a minimal system-Perl bind fails with the same platform restriction.

## Progress Tracking

### Current Status: implementation complete; PR ready for review

### Completed Phases

- [x] Phase 1: classify upstream/system failures (2026-08-15)
- Reproduced each exclusion with system Perl or the relevant platform configuration step.
- [x] Phase 2: compiler/runtime fixes (2026-08-15)
- Fixed tied inheritance, constant stash proxies, and lexical open-layer handling.
- [x] Phase 3: reusable Java module bridges (2026-08-15)
- Added Sereal, cache, OpenSSL/X509, and RelaxNG support using existing or upstream Java libraries.
- [x] Phase 4: regression coverage (2026-08-15)
- Added focused unit tests and validated new Perl semantics with system Perl before PerlOnJava.
- [x] Phase 5: final verification (2026-08-15)
- Full `make` passed.
- Mail::BIMI passed all 31 test programs and 82 assertions; network- and author-only tests skipped as expected.
- Preserved the platform-default I/O layer when no lexical `open` pragma is
active, including Windows `:crlf`, without consulting the leaked
process-global `${^OPEN}` value.
- [x] Phase 6: pull request and CI (2026-08-15)
- Opened PR #962 from `fix/jcpan-compiler-tooling-followup`.
- GitHub Actions passed on Ubuntu and Windows; the Windows run specifically
confirmed the platform-default newline fix in `pipe_jperl_shebang.t`.

### Next Steps

1. Review PR #962.
2. Merge after approval.

### Open Questions

- A future Cache::FastMmap implementation could provide true cross-process mmap sharing; current requested tests only require same-process behavior.

## References

- [Sereal](https://github.com/Sereal/Sereal)
- [Jing and Trang](https://github.com/relaxng/jing-trang)
- Skills: `debug-perlonjava`, `port-cpan-module`, `port-native-module`
6 changes: 6 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ commons-csv = "1.14.1"
commonmark = "0.29.0"
icu4j = "78.3"
jsoup = "1.23.1"
jing = "20241231"
junit-jupiter = "6.1.3"
snakeyaml-engine = "3.1.1"
snappy-java = "1.1.10.8"
sqlite-jdbc = "3.53.2.1"
tomlj = "1.1.1"
zstd-jni = "1.5.7-8"

[libraries]
asm = { module = "org.ow2.asm:asm", version.ref = "asm" }
Expand All @@ -25,12 +28,15 @@ commonmark-tables = { module = "org.commonmark:commonmark-ext-gfm-tables", versi
commonmark-task-list = { module = "org.commonmark:commonmark-ext-task-list-items", version.ref = "commonmark" }
icu4j = { module = "com.ibm.icu:icu4j", version.ref = "icu4j" }
jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" }
jing = { module = "org.relaxng:jing", version.ref = "jing" }
junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit-jupiter" }
junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit-jupiter" }
junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit-jupiter" }
snakeyaml-engine = { module = "org.snakeyaml:snakeyaml-engine", version.ref = "snakeyaml-engine" }
snappy-java = { module = "org.xerial.snappy:snappy-java", version.ref = "snappy-java" }
sqlite-jdbc = { module = "org.xerial:sqlite-jdbc", version.ref = "sqlite-jdbc" }
tomlj = { module = "org.tomlj:tomlj", version.ref = "tomlj" }
zstd-jni = { module = "com.github.luben:zstd-jni", version.ref = "zstd-jni" }

[plugins]
cyclonedx = "org.cyclonedx.bom:2.3.0"
Expand Down
32 changes: 32 additions & 0 deletions src/main/java/com/booking/sereal/ByteArray.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.booking.sereal;

import java.nio.ByteBuffer;
import java.util.Arrays;

public class ByteArray {
public byte[] array;
public int start;
public int length;

public ByteArray(byte[] array) {
this(array, 0, array.length);
}

public ByteArray(byte[] array, int length) {
this(array, 0, length);
}

public ByteArray(byte[] array, int start, int length) {
this.array = array;
this.start = start;
this.length = length;
}

public ByteArray(ByteBuffer buffer) {
this(buffer.array(), buffer.limit());
}

public void ensure(int size) {
if (size > array.length) array = Arrays.copyOf(array, size * 3 / 2);
}
}
26 changes: 26 additions & 0 deletions src/main/java/com/booking/sereal/DeSereal.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.booking.sereal;

import java.io.File;
import java.io.IOException;

public class DeSereal {
/**
* @param args command arguments
* @throws IOException Indicated file cannot accessed.
* @throws SerealException Sereal data cannot be processed.
*/
public static void main(String[] args) throws IOException, SerealException {
if (args.length == 0) {
throw new UnsupportedOperationException("Usage: DeSereal test_data");
}

DecoderOptions decoder_options =
new DecoderOptions().perlReferences(true).perlAliases(true).preferLatin1(true);

Decoder dec = new Decoder(decoder_options);
final File target = new File(args[0]).getCanonicalFile(); // to absorb ".." in paths
// dec.log.setLevel( Level.FINE );
Object data = Utils.decodeFile(dec, target);
System.out.println(Utils.dump(data));
}
}
Loading
Loading