Skip to content

Commerce: offerings, paywalls, customer center, more stores, and invites - #6219

Open
shai-almog wants to merge 21 commits into
masterfrom
commerce-parity
Open

shai-almog wants to merge 21 commits into
masterfrom
commerce-parity

Conversation

@shai-almog

Copy link
Copy Markdown
Collaborator

Commerce gets the full subscription product surface on the client: customer info, offerings, paywalls, a customer center, web checkout, and more stores, all tied into Codename One's own analytics and invite-a-friend.

What's in it

  • Customer info and entitlements come from the Commerce service by app user id, so a subscription bought on one platform unlocks on every other. logIn/logOut, attributes, restore, a cached cold start, and a listener for changes.
  • Offerings and paywalls. getOfferings() returns what the console configured, with targeting and experiments. PaywallView renders the console's paywall from native components, with a bundled default when the cloud has none.
  • Customer center: manage, restore, refund request, cancel survey and retention offer.
  • Stores: Apple, Google, native Mac App Store (StoreKit in Ports/MacPort), Amazon Appstore (android.billing.store=amazon), and web checkout through Stripe or Paddle (purchaseOnWeb, fetchManagementUrl). Apple promotional offers are signed by the service.
  • Analytics and invites. Paywall, customer-center and experiment events go to first-party analytics. A purchase by an invited user is credited to the inviter with verified revenue, and referral rewards (an entitlement or currency for inviter and invitee) arrive through CustomerInfo.getReferralRewards() with no app code.
  • Trust. Every cloud answer, purchase validation included, is Ed25519 signed and bound to the request's nonce, user, package and endpoint. Anything unverified is ignored and the app answers from the store directly; cached answers are re-verified at start. Plain http endpoints are accepted only on loopback. The production public key is built in.
  • Build hints commerce.cloud.enabled, commerce.cloud.endpoint, commerce.cloud.publicKey and android.billing.store, declared in the catalog and stamped by every builder.
  • Docs: the Commerce chapter of the developer guide is rewritten around all of the above, with compiled snippets.

Verification

  • core-unittests 8482 tests, build-engine 3064, all passing; SpotBugs, PMD and Checkstyle at zero; cast-semantics, build-hint catalog, Android API-removal and the other script gates pass.
  • iOS: built and run on the simulator; refresh, paywall and customer center ran after a receipt (purchase-e2e now asserts this). The StoreKitTest purchase itself still needs this job's run.
  • Native Mac: builds and links with StoreKit.

Goes with codenameone/BuildCloud and codenameone/BuildDaemon branches commerce-parity.

🤖 Generated with Claude Code

shai-almog and others added 19 commits November 11, 2026 17:55
…ager

refresh() now asks the service for the customer after validating the
device's receipts, even when there are none, and takes that answer as the
entitlement state. The last accepted answer is stored per app user id and
read back on a cold start. Answers of the new endpoints are verified with
Ed25519 over the request nonce when a public key is known.

Adds CustomerInfo and EntitlementInfo, logIn, logOut, restore,
setAttributes, customer listeners, and a refresh after every successful
receipt synchronization. Commerce requests no longer raise the framework's
error dialog on an error status.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
CommerceManager reads commerce.cloud.enabled, commerce.cloud.endpoint and
commerce.cloud.publicKey through Display.getProperty. They were declared in no
catalog and stamped by no builder, so a build accepted them and nothing read
them.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
CommerceManager fetches the offerings of a customer (stored for when the
network fails, with the store's products attached to the packages), buys
a package, and queues paywall events that a background thread sends in
one request. PaywallView builds a paywall document from standard
components with documented UIIDs; CustomerCenter shows the configured
paths over the active subscriptions.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
The StoreKit natives were already shared with the macOS port and compiled
to nothing there: the builder never defined CN1_USE_STOREKIT, the delegate
methods sat inside the UIKit controller's @implementation, which macOS
compiles out, and nothing observed the payment queue.

- The StoreKit delegate moves into a category on
  CodenameOne_GLViewController, so the UIKit controller and the AppKit
  render driver run the same product, transaction and receipt code.
- macOS builds a payment from an SKProduct, as tvOS does; the SDK marks
  paymentWithProductIdentifier: unavailable on both.
- The receipt posted is the app receipt under the same store code.
- MacOSNativeBuilder switches the define on for an application that uses
  com.codename1.payment and declares StoreKit.framework, for the review
  prompt as well, which had been linking through an autolink hint.
- Manage subscriptions opens the https address on macOS.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
The android.billing.store build hint (play, the default, or amazon) picks
the store an in-app-purchase app is built for. An Amazon build depends on
the Amazon Appstore SDK instead of Play Billing, declares the receiver
Amazon's client answers through, and does not request
com.android.vending.BILLING or require android.licenseKey.

AmazonBillingSupport is the port's implementation over the SDK's IAP API.
Like BillingSupport it ships as source: the port's module build excludes
it, and the builder keeps only the source whose library the build carries
and names that class in the generated activity stub.

Receipts carry the new store code Receipt.STORE_CODE_AMAZON, which
CommerceManager sends as store "amazon".

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…c store on the client

A package with no product of the platform's store is sold through a hosted
checkout where the platform has no store, a web subscription is managed in
the billing portal, and a retention offer that names a promotional offer is
bought with a signature from the cloud. Receipts of the Mac App Store are
sent under their own store name.

The commerce build hints are stamped into the Linux, Windows, macOS,
JavaScript and watch stubs as well, and the simulator resolves them from
the project settings.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
… and the service API

Covers entitlements and the stored answer, identity and transfer policies,
offerings and packages, targeting and experiments, paywalls and their
document format, the customer center, attributes and virtual currency, the
stores (Apple, Google Play, Amazon, Stripe and Paddle), webhooks,
integrations, the REST API, export and import, the build hints and the
simulator. Every sample is a compiled snippet.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…e or restore completes

Paywall.show closes its form before the listener hears purchaseCompleted or
restoreCompleted; an embedded PaywallView stays where it is. Also clears the
SpotBugs and PMD findings the gates reported in CommerceManager and PaywallView.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…referral rewards

Every commerce request carries the install's analytics client id when a
provider is registered and consent covers analytics, so the service can join
a customer to that install's analytics and invite records. The paywall and
the customer center report their events through the analytics providers,
with the placement and the experiment variant of the offering, and Purchase's
own purchase events gain that context for a purchase started from a package.
An experiment assignment is reported once as an exposure. An invite
attribution refreshes the customer in the background through an observer on
Analytics that leaves the application's InviteListener alone, and
CustomerInfo lists the referral rewards the service granted.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…he paywall and customer center

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ned envelope, http endpoints only on loopback

With no public key known, no signed-envelope answer is used or cached; the
manager stays degraded and answers from the store. The cold-start cache keeps
the envelope and verifies it again on load. Analytics re-notifies the
attribution observer after attribution was cleared.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…vice endpoints

With a public key the validate request carries a nonce and goes through
postSigned; an unsigned or forged answer applies nothing. Without a key
the request is still sent but its answer is ignored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…referral rewards and Amazon SNS

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…und to another user, package or endpoint are refused

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…h touched

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eForeach)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cloud answers are now verified out of the box. The tests that cover the
no-key path clear a package-private override, since no shipped build can
reach that path any more.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

Developer Guide build artifacts are available for download from this workflow run:

Developer Guide quality checks:

  • AsciiDoc linter: No issues found (report)
  • Vale: No alerts found (report)
  • Paragraph capitalization: No paragraph capitalization issues (report)
  • LanguageTool: No grammar matches (report)
  • Image references: No unused images detected (report)

@shai-almog

shai-almog commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 12 screenshots: 12 matched.
✅ JavaSE simulator integration screenshots matched stored baselines.

@github-actions

github-actions Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ✅ ByteCodeTranslator: 0 findings (no issues)
    • ✅ android: 0 findings (no issues)
    • ✅ android-compat: 0 findings (no issues)
    • ✅ android-res-compiler: 0 findings (no issues)
    • ✅ backend: 0 findings (no issues)
    • ✅ backend-test: 0 findings (no issues)
    • ✅ build-engine: 0 findings (no issues)
    • ✅ build-hint-catalog: 0 findings (no issues)
    • ✅ build-hint-tools: 0 findings (no issues)
    • ✅ codenameone-gradle-plugin: 0 findings (no issues)
    • ✅ codenameone-maven-plugin: 0 findings (no issues)
    • ✅ compose-compat: 0 findings (no issues)
    • ✅ core-unittests: 0 findings (no issues)
    • ✅ desktop-compat-runtime: 0 findings (no issues)
    • ✅ fxml-compiler: 0 findings (no issues)
    • ✅ ios: 0 findings (no issues)
    • ✅ javac: 0 findings (no issues)
    • ✅ javafx-compat: 0 findings (no issues)
    • ✅ project-model: 0 findings (no issues)
    • ✅ python-runtime: 0 findings (no issues)
    • ✅ python-transpiler: 0 findings (no issues)
    • ✅ swing-compat: 0 findings (no issues)
  • ✅ PMD: 0 findings (no issues) [Report archive]
  • ✅ Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@shai-almog

shai-almog commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 195 screenshots: 195 matched.

Native Android coverage

  • 📊 Line coverage: 19.17% (56155/292885 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 18.13% (270509/1492353), branch 12.38% (19670/158943), complexity 10.35% (15842/153017), method 15.73% (11409/72518), class 27.93% (2247/8045)
    • Lowest covered classes
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2396 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.ClassReader – 0.00% (0/1524 lines covered)
      • androidx.compose.runtime.androidx.compose.runtime.LinkComposer – 0.00% (0/1430 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.MethodWriter – 0.00% (0/922 lines covered)
      • kotlinx.coroutines.channels.kotlinx.coroutines.channels.BufferedChannel – 0.00% (0/863 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/744 lines covered)
      • com.google.common.cache.com.google.common.cache.LocalCache$Segment – 0.00% (0/726 lines covered)
      • okio.okio.Buffer – 0.00% (0/687 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/630 lines covered)
      • com.codename1.androidcompat.rt.com.codename1.androidcompat.rt.TextXmlPullParser – 0.00% (0/623 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 19.17% (56155/292885 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 18.13% (270509/1492353), branch 12.38% (19670/158943), complexity 10.35% (15842/153017), method 15.73% (11409/72518), class 27.93% (2247/8045)
    • Lowest covered classes
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2396 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.ClassReader – 0.00% (0/1524 lines covered)
      • androidx.compose.runtime.androidx.compose.runtime.LinkComposer – 0.00% (0/1430 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.MethodWriter – 0.00% (0/922 lines covered)
      • kotlinx.coroutines.channels.kotlinx.coroutines.channels.BufferedChannel – 0.00% (0/863 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/744 lines covered)
      • com.google.common.cache.com.google.common.cache.LocalCache$Segment – 0.00% (0/726 lines covered)
      • okio.okio.Buffer – 0.00% (0/687 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/630 lines covered)
      • com.codename1.androidcompat.rt.com.codename1.androidcompat.rt.TextXmlPullParser – 0.00% (0/623 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend scalar fallback (no native SIMD)
SIMD int-add (64K x300) java 132ms / native 81ms = 1.6x speedup
SIMD float-mul (64K x300) java 159ms / native 103ms = 1.5x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 62.000 ms
Base64 CN1 decode 66.000 ms
Base64 native encode 415.000 ms
Base64 encode ratio (CN1/native) 0.149x (85.1% faster)
Base64 native decode 236.000 ms
Base64 decode ratio (CN1/native) 0.280x (72.0% faster)
Image encode benchmark status skipped (SIMD unsupported)

@shai-almog

shai-almog commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 231 screenshots: 231 matched.
✅ JavaScript-port screenshot tests passed.

@github-actions

Copy link
Copy Markdown
Contributor

✅ ByteCodeTranslator Quality Report

Test & Coverage

  • ✅ Tests: 934 total, 0 failed, 55 skipped

Benchmark Results

  • Execution Time: 9632 ms

  • Hotspots (Top 20 sampled methods):

    • 11.53% java.lang.System.identityHashCode (160 samples)
    • 7.71% java.util.ArrayList.indexOf (107 samples)
    • 5.19% java.lang.Object.hashCode (72 samples)
    • 3.96% java.lang.StringBuilder.append (55 samples)
    • 2.74% com.codename1.tools.translator.BytecodeMethod.equals (38 samples)
    • 2.31% com.codename1.tools.translator.BytecodeMethod.updateInlinableFieldDependencies (32 samples)
    • 2.16% java.util.AbstractCollection.containsAll (30 samples)
    • 1.95% com.codename1.tools.translator.JavascriptReachability.enqueueResolved (27 samples)
    • 1.51% java.util.HashMap.putVal (21 samples)
    • 1.51% java.lang.String.equals (21 samples)
    • 1.44% java.io.FileOutputStream.writeBytes (20 samples)
    • 1.37% com.codename1.tools.translator.ByteCodeClass.hasDeclaredMethod (19 samples)
    • 1.30% java.util.HashMap.hash (18 samples)
    • 1.30% com.codename1.tools.translator.bytecodes.Invoke.findMethodUp (18 samples)
    • 1.22% com.codename1.tools.translator.Parser.cullMethods (17 samples)
    • 1.08% com.codename1.tools.translator.bytecodes.Invoke.resolveDirectTarget (15 samples)
    • 1.08% com.codename1.tools.translator.BytecodeMethod.isFramelessEligibleImpl (15 samples)
    • 1.01% com.codename1.tools.translator.ByteCodeClass.fillVirtualMethodTable (14 samples)
    • 1.01% com.codename1.tools.translator.classfile.analysis.Analyzer.analyze (14 samples)
    • 0.94% com.codename1.tools.translator.classfile.analysis.Frame.execute (13 samples)
  • ⚠️ Coverage report not generated.

Static Analysis

  • ✅ SpotBugs: no findings (report was not generated by the build).
  • ⚠️ PMD report not generated.
  • ⚠️ Checkstyle report not generated.

Generated automatically by the PR CI workflow.

@shai-almog

shai-almog commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 210 screenshots: 210 matched.
Native Windows port (x64 / Intel-AMD): full hellocodenameone screenshot suite rendered offscreen with Direct2D/DirectWrite, plus the real benchmarks (base64 native/CN1/SIMD, image createMask/applyMask/modifyAlpha/PNG/JPEG, SSE2 SIMD kernels). Compared against the in-repo baseline in scripts/windows/screenshots.

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 54ms / native 11ms = 4.9x speedup
SIMD float-mul (64K x300) java 55ms / native 3ms = 18.3x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 native bridge unavailable (CN1 + SIMD + image benchmarks only)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 72.000 ms
Base64 CN1 decode 95.000 ms
Base64 SIMD encode 106.000 ms
Base64 encode ratio (SIMD/CN1) 1.472x (47.2% slower)
Base64 SIMD decode 94.000 ms
Base64 decode ratio (SIMD/CN1) 0.989x (1.1% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 10.000 ms
Image createMask (SIMD on) 6.000 ms
Image createMask ratio (SIMD on/off) 0.600x (40.0% faster)
Image applyMask (SIMD off) 45.000 ms
Image applyMask (SIMD on) 46.000 ms
Image applyMask ratio (SIMD on/off) 1.022x (2.2% slower)
Image modifyAlpha (SIMD off) 37.000 ms
Image modifyAlpha (SIMD on) 22.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.595x (40.5% faster)
Image modifyAlpha removeColor (SIMD off) 52.000 ms
Image modifyAlpha removeColor (SIMD on) 27.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.519x (48.1% faster)

ParparVM vs HotSpot (JDK 25): Windows x64

Runner CPU: Intel64 Family 6 Model 106 Stepping 6, GenuineIntel (baseline windows-x64@intel64-family-6-model-106-genuineintel)

Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in vm/selfhost/perf-baseline/ is a regression and fails; one that far below is an improvement, reported but not failed (a row whose calibration runs were noisier carries a wider tolerance), and for RAM the change must also exceed 0.05x in absolute terms. Both run unpinned on all of the runner's CPUs, with their own default thread counts.

Benchmark Cores Time RAM Status
hello (WinHelloMain) 4 1.75x (base 1.21x, +44.4%) 0.68x (base 0.76x, -10.3%) ok
translator (self) 4 0.77x (base 0.76x, +1.7%) 0.51x (base 0.54x, -4.8%) ok
intArithmetic 4 1.03x (base 1.03x, +0.2%) 0.06x (base 0.06x, +4.5%) ok
longArithmetic 4 1.00x (base 1.00x, -0.2%) 0.06x (base 0.05x, +3.1%) ok
mathTranscendental 4 0.81x (base 0.81x, +0.2%) 0.06x (base 0.06x, +3.1%) ok
arraySequential 4 1.51x (base 1.43x, +6.0%) 0.38x (base 0.38x, +0.1%) ok
arrayRandom 4 1.00x (base 1.00x, +0.1%) 0.23x (base 0.23x, +0.7%) ok
objectAllocation 4 1.20x (base 1.21x, -1.3%) 0.36x (base 0.32x, +11.6%) ok
valueEscape 4 0.13x (base 0.17x, -24.3%) 0.05x (base 0.04x, +5.8%) ok
hashMapChurn 4 1.17x (base 1.21x, -3.9%) 0.09x (base 0.10x, -11.8%) ok
stringBuilding 4 1.48x (base 1.44x, +3.0%) 0.27x (base 0.27x, -0.8%) ok
recursion 4 1.19x (base 1.26x, -5.9%) 0.06x (base 0.06x, +3.3%) ok
quicksort 4 1.06x (base 1.11x, -3.9%) 0.12x (base 0.12x, +1.7%) ok

Result: no regression

@shai-almog

shai-almog commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 210 screenshots: 210 matched.
Native Windows port (arm64 / Apple Silicon - Arm): full hellocodenameone screenshot suite rendered offscreen with Direct2D/DirectWrite, plus the real benchmarks (base64 native/CN1/SIMD, image createMask/applyMask/modifyAlpha/PNG/JPEG, NEON SIMD kernels). Compared against the in-repo baseline in scripts/windows/screenshots.

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 50ms / native 3ms = 16.6x speedup
SIMD float-mul (64K x300) java 52ms / native 3ms = 17.3x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 native bridge unavailable (CN1 + SIMD + image benchmarks only)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 63.000 ms
Base64 CN1 decode 69.000 ms
Base64 SIMD encode 77.000 ms
Base64 encode ratio (SIMD/CN1) 1.222x (22.2% slower)
Base64 SIMD decode 68.000 ms
Base64 decode ratio (SIMD/CN1) 0.986x (1.4% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 6.000 ms
Image createMask (SIMD on) 1.000 ms
Image createMask ratio (SIMD on/off) 0.167x (83.3% faster)
Image applyMask (SIMD off) 16.000 ms
Image applyMask (SIMD on) 16.000 ms
Image applyMask ratio (SIMD on/off) 1.000x (0.0% slower)
Image modifyAlpha (SIMD off) 19.000 ms
Image modifyAlpha (SIMD on) 9.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.474x (52.6% faster)
Image modifyAlpha removeColor (SIMD off) 21.000 ms
Image modifyAlpha removeColor (SIMD on) 13.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.619x (38.1% faster)

ParparVM vs HotSpot (JDK 25): Windows arm64

Runner CPU: ARMv8 (64-bit) Family 8 Model D49 Revision 0, MICROSOFT CORPORATION (baseline windows-arm64@armv8-64-bit-family-8-model-d49-microsoft-corporation)

Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in vm/selfhost/perf-baseline/ is a regression and fails; one that far below is an improvement, reported but not failed (a row whose calibration runs were noisier carries a wider tolerance), and for RAM the change must also exceed 0.05x in absolute terms. Both run unpinned on all of the runner's CPUs, with their own default thread counts.

Benchmark Cores Time RAM Status
hello (WinHelloMain) 4 1.41x (base 1.45x, -2.3%) 0.77x (base 0.75x, +2.1%) ok
translator (self) 4 0.88x (base 0.84x, +4.5%) 0.50x (base 0.51x, -1.1%) ok
intArithmetic 4 1.04x (base 1.04x, -0.1%) 0.06x (base 0.06x, +3.2%) ok
longArithmetic 4 0.80x (base 0.80x, +0.0%) 0.06x (base 0.06x, +3.5%) ok
mathTranscendental 4 0.73x (base 0.72x, +1.7%) 0.07x (base 0.06x, +1.7%) ok
arraySequential 4 0.38x (base 0.46x, -16.2%) 0.39x (base 0.39x, +0.0%) ok
arrayRandom 4 0.93x (base 0.94x, -0.5%) 0.23x (base 0.23x, +0.3%) ok
objectAllocation 4 1.83x (base 1.82x, +0.7%) 0.41x (base 0.43x, -5.8%) ok
valueEscape 4 0.76x (base 0.76x, +0.1%) 0.05x (base 0.05x, +3.9%) ok
hashMapChurn 4 0.99x (base 0.98x, +0.6%) 0.12x (base 0.12x, -2.0%) ok
stringBuilding 4 1.55x (base 1.43x, +8.3%) 0.27x (base 0.27x, -0.2%) ok
recursion 4 1.42x (base 1.46x, -3.1%) 0.07x (base 0.07x, +1.3%) ok
quicksort 4 1.01x (base 1.00x, +0.6%) 0.12x (base 0.12x, +0.7%) ok

Result: no regression

@shai-almog

shai-almog commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 210 screenshots: 210 matched.
Native Linux port (x64), GTK3/Cairo/Pango, ParparVM bytecode-to-C (no JVM): the hellocodenameone screenshot suite rendered by a native ELF built + run on the GitHub x64 runner. Baseline: scripts/linux/screenshots.

ParparVM vs HotSpot (JDK 25): Linux x64

Runner CPU: AMD EPYC 9V74 80-Core Processor (baseline linux-x64@amd-epyc-9v74-80-core-processor)

Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in vm/selfhost/perf-baseline/ is a regression and fails; one that far below is an improvement, reported but not failed (a row whose calibration runs were noisier carries a wider tolerance), and for RAM the change must also exceed 0.05x in absolute terms. Both run unpinned on all of the runner's CPUs, with their own default thread counts.

Benchmark Cores Time RAM Status
hello (LinuxHelloMain) 4 1.14x (base 0.90x, +27.3%) 0.81x (base 0.96x, -15.2%) ok
translator (self) 4 0.68x (base 0.63x, +8.5%) 0.48x (base 0.46x, +3.5%) ok
intArithmetic 4 1.10x (base 1.10x, -0.0%) 0.04x (base 0.06x, -32.2%) ok
longArithmetic 4 1.08x (base 1.08x, -0.0%) 0.04x (base 0.06x, -29.6%) ok
mathTranscendental 4 1.10x (base 1.09x, +0.3%) 0.04x (base 0.07x, -38.8%) ok
arraySequential 4 2.88x (base 2.81x, +2.5%) 0.36x (base 0.35x, +1.1%) ok
arrayRandom 4 1.02x (base 1.02x, +0.1%) 0.20x (base 0.21x, -4.6%) ok
objectAllocation 4 1.30x (base 1.21x, +7.9%) 0.36x (base 0.39x, -7.4%) ok
valueEscape 4 0.10x (base 0.10x, -0.0%) 0.03x (base 0.06x, -43.1%) ok
hashMapChurn 4 1.09x (base 1.10x, -0.1%) 0.11x (base 0.10x, +9.5%) ok
stringBuilding 4 1.37x (base 1.49x, -7.7%) 0.31x (base 0.26x, +20.3%) ok
recursion 4 1.33x (base 1.24x, +7.3%) 0.04x (base 0.06x, -28.8%) ok
quicksort 4 1.08x (base 1.07x, +1.2%) 0.10x (base 0.11x, -11.4%) ok

Result: no regression

@shai-almog

shai-almog commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 210 screenshots: 210 matched.
Native Linux port (arm64), GTK3/Cairo/Pango, ParparVM bytecode-to-C (no JVM): the hellocodenameone screenshot suite rendered by a native ELF built + run on the GitHub arm64 runner. Baseline: scripts/linux/screenshots-arm.

ParparVM vs HotSpot (JDK 25): Linux arm64

Runner CPU: Neoverse-N2 (baseline linux-arm64@neoverse-n2)

Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in vm/selfhost/perf-baseline/ is a regression and fails; one that far below is an improvement, reported but not failed (a row whose calibration runs were noisier carries a wider tolerance), and for RAM the change must also exceed 0.05x in absolute terms. Both run unpinned on all of the runner's CPUs, with their own default thread counts.

Benchmark Cores Time RAM Status
hello (LinuxHelloMain) 4 1.13x (base 1.02x, +10.8%) 0.78x (base 0.66x, +18.1%) ok
translator (self) 4 0.79x (base 0.70x, +12.5%) 0.44x (base 0.43x, +1.6%) ok
intArithmetic 4 1.04x (base 1.04x, -0.0%) 0.03x (base 0.03x, +4.8%) ok
longArithmetic 4 0.79x (base 0.79x, -0.3%) 0.03x (base 0.03x, +5.2%) ok
mathTranscendental 4 1.09x (base 1.10x, -0.3%) 0.04x (base 0.03x, +10.0%) ok
arraySequential 4 0.35x (base 0.36x, -2.9%) 0.37x (base 0.37x, +0.6%) ok
arrayRandom 4 0.94x (base 0.94x, -0.0%) 0.20x (base 0.20x, +0.6%) ok
objectAllocation 4 1.97x (base 1.77x, +11.3%) 0.37x (base 0.37x, -0.8%) ok
valueEscape 4 0.51x (base 0.51x, -0.1%) 0.03x (base 0.03x, +6.2%) ok
hashMapChurn 4 0.86x (base 0.84x, +2.1%) 0.11x (base 0.12x, -6.6%) ok
stringBuilding 4 1.40x (base 1.57x, -10.8%) 0.26x (base 0.26x, -0.1%) ok
recursion 4 1.56x (base 1.43x, +8.6%) 0.04x (base 0.04x, +3.3%) ok
quicksort 4 1.00x (base 0.99x, +0.3%) 0.10x (base 0.09x, +2.7%) ok

Result: no regression

@shai-almog

shai-almog commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 196 screenshots: 196 matched.
✅ Native Mac screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 682 seconds

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 60ms / native 3ms = 20.0x speedup
SIMD float-mul (64K x300) java 53ms / native 2ms = 26.5x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 native bridge unavailable (CN1 + SIMD + image benchmarks only)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 48.000 ms
Base64 CN1 decode 53.000 ms
Image encode benchmark iterations 100
Image createMask (SIMD off) 7.000 ms
Image createMask (SIMD on) 2.000 ms
Image createMask ratio (SIMD on/off) 0.286x (71.4% faster)
Image applyMask (SIMD off) 98.000 ms
Image applyMask (SIMD on) 64.000 ms
Image applyMask ratio (SIMD on/off) 0.653x (34.7% faster)
Image modifyAlpha (SIMD off) 72.000 ms
Image modifyAlpha (SIMD on) 65.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.903x (9.7% faster)
Image modifyAlpha removeColor (SIMD off) 62.000 ms
Image modifyAlpha removeColor (SIMD on) 55.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.887x (11.3% faster)

ParparVM vs HotSpot (JDK 25): macOS arm64

Runner CPU: Apple M1 (Virtual) (baseline macos-arm64)

Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in vm/selfhost/perf-baseline/ is a regression and fails; one that far below is an improvement, reported but not failed (a row whose calibration runs were noisier carries a wider tolerance), and for RAM the change must also exceed 0.05x in absolute terms. Both run unpinned on all of the runner's CPUs, with their own default thread counts.

Benchmark Cores Time RAM Status
hello (HelloCodenameOne) 3 1.19x (base 0.96x, +24.6%) 0.87x (base 0.93x, -6.1%) ok
translator (self) 3 0.74x (base 0.62x, +18.5%) 0.74x (base 0.78x, -5.6%) ok
intArithmetic 3 1.07x (base 1.03x, +3.4%) 0.12x (base 0.12x, +1.0%) ok
longArithmetic 3 1.00x (base 1.03x, -2.8%) 0.12x (base 0.07x, +66.9%) ok
mathTranscendental 3 0.93x (base 1.01x, -7.2%) 0.12x (base 0.12x, +1.0%) ok
arraySequential 3 0.44x (base 0.42x, +4.5%) 0.53x (base 0.53x, +0.1%) ok
arrayRandom 3 0.98x (base 0.99x, -1.0%) 0.33x (base 0.32x, +0.4%) ok
objectAllocation 3 1.04x (base 1.11x, -6.1%) 0.91x (base 0.72x, +25.4%) ok
valueEscape 3 0.51x (base 0.51x, +0.1%) 0.08x (base 0.09x, -10.0%) ok
hashMapChurn 3 1.03x (base 1.18x, -12.6%) 0.06x (base 0.07x, -5.3%) ok
stringBuilding 3 0.93x (base 0.84x, +10.3%) 0.47x (base 0.46x, +0.8%) ok
recursion 3 1.22x (base 1.24x, -1.2%) 0.12x (base 0.12x, -1.2%) ok
quicksort 3 0.97x (base 1.01x, -4.0%) 0.11x (base 0.11x, +0.9%) ok

Result: no regression

…builds

The port's exclusion list lives in three files and only the Maven copy had
the Amazon billing class, so the Ant build failed on the missing Appstore SDK.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Cloudflare Preview

… hint

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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