Skip to content

Python support: transpiled Python on every target, Python servers, Pillow and font-from-data - #6128

Merged
shai-almog merged 146 commits into
masterfrom
python-support
Nov 5, 2026
Merged

shai-almog merged 146 commits into
masterfrom
python-support

Conversation

@shai-almog

Copy link
Copy Markdown
Collaborator

Python support for Codename One: Python sources are transpiled to Java and run on every target, client and server.

What is in it

  • maven/python-transpiler and maven/python-runtime: the transpiler, the runtime and the bundled stdlib and site packages, with ~125 conformance programs whose expected output is real CPython output.
  • Build integration in build-engine (Maven goal, Gradle task, project importer, PyPI resolution, C-extension stubs) and the python.virtualThreadStack build hint / @VirtualThreadStack.
  • Python servers on the backend: FastAPI/Starlette/Flask, WebSockets and streaming responses, BackgroundTasks after the response, SQLAlchemy on SQLite, PostgreSQL and MySQL (CI runs it against both), a GIL that cooperates with virtual threads.
  • Pillow: on servers over a new backend image API (com.codename1.backend.image: raster, JPEG/PNG, TrueType text); on clients over Codename One's Image/ImageIO.
  • Core: Font.createTrueTypeFontFromData / isTrueTypeStreamSupported on JavaSE, Android, iOS/Mac, JavaScript, Windows and Linux; Database column types.
  • Backend: MySQL/PostgreSQL sslmode=verify-ca with a CA file (plus the MySQL spellings).
  • Fix: the core inflater (io/gzip/InfCodes) rejected valid deflate streams whose last code ended a few bits into the final byte (about half of all gzip files, depending on the header mtime). Fuzzed against java.util.zip with 160k streams fed in chunks.
  • Developer guide chapters for all of the above.

Verification

  • python-transpiler/python-runtime tests (145), core-unittests, backend tests; SpotBugs/PMD/Checkstyle clean on the touched modules; cast-semantics, native-signature, C++ linkage, control-character and build-hint gates.
  • End-to-end server runs on the JVM and native, and SQLAlchemy against PostgreSQL 16 and MySQL 8.4.
  • Not verified locally: the JavaScript font path in a browser (TrueTypeFontFromDataTest in the JS suite covers it here), the Windows/Linux C font changes (no toolchain locally) and the iOS private-API scan.

🤖 Generated with Claude Code

shai-almog and others added 30 commits October 27, 2026 17:01
Python 3 sources transpile to Java 17 (maven/python-transpiler) and run on
maven/python-runtime on every Codename One target. Generators, async,
match, dataclasses, the builtins and a stdlib wave are covered by a
conformance suite diffed against CPython on the JVM and natively through
ParparVM. Constructs a translated program cannot run (eval, exec,
compile, __import__, frame hooks) are build errors naming file and line.

ParparVM: a frameless method returning a value after several try blocks
that end on one label ran a single END_TRY and left the other blocks on
the thread's try stack, so a later throw longjmp'd into a returned frame.
The folded return paths now unwind the stack (FramelessTryReturnIntegrationTest).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
from java.<package> import <Class> resolves at build time against the
compile class path; a generated JavaInterop bridge dispatches with
instanceof and direct calls (no reflection), converts values both ways,
adapts Python callables to functional interfaces and exposes Java
collections to len/in/iteration/indexing.

cn1:import-python-project and cn1:transpile-python (Maven), the
transpilePython task (Gradle), and the archetype's python profile build
src/main/python. runMain returns the exit status, honouring SystemExit.

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

from java.java.* resolves against the class path's own class library
(java-runtime, JavaAPI) when it carries one, so an API the device lacks is
a build error rather than a bridge that fails to link.

python-project-test.sh imports scripts/python-samples/hello-ui (a
Codename One UI written in Python), builds it with Maven and Gradle and
stages every target; python-project.yml runs it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PyHttp is the client the packages are written over: ConnectionRequest in
an application, installable like PyFileSystem. requests (verbs, Session,
auth, params/json/form bodies, cookies, exceptions) and httpx (verbs,
Client, AsyncClient, URL, Headers, HTTPStatusError) are our own Python
over it; http_requests and http_httpx match the real packages' output
against the same test server.

BaseException.__new__ ignores keyword arguments, as CPython's does, so an
exception subclass whose __init__ takes keywords can be raised.

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

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

The HTTP client is installed by the generated registry only when the
program bundles requests or httpx, so other programs do not link the
network stack.

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

Fixes found while porting attrs and pydantic: an annotation built by a call
(Annotated[int, Field(gt=0)], conint(ge=2)) was stored as None; a class
__delattr__ was bypassed by del; classes had no __hash__ attribute; and
type(name, bases, ns) gave __module__ 'builtins'.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
_cn1server.serve(dispatch, host, port) bridges a Python dispatch callable
to the backend HttpServer when the backend is on the transpile class path;
scripts/python-backend/build.sh builds such an app as a native binary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Clean-room site packages flask, werkzeug.exceptions, fastapi, starlette
(responses, requests, testclient, status) and uvicorn. Every app exposes
dispatch(method, path, query, headers, body) -> (status, headers, body);
app.run / uvicorn.run hand it to _cn1server.serve.

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

inspect.isgeneratorfunction/iscoroutinefunction/isasyncgenfunction now
answer from __code__ as CPython's do; FastAPI's yield dependencies use it.

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

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

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

CommonWorkloads ported to Python (scripts/python-bench/common) with a
Java hot-spot variant, and a comparison across CPython, PyPy, GraalPy and
Codename One with peak RSS per workload.

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

The developer guide's Python chapter compares CPython, PyPy, GraalPy and
Codename One on startup, kernels, Flask and the CommonWorkloads suite, with
peak memory in every table, two charts, and a section on moving a measured
hot spot into Java.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
IntRanges runs interval analysis over each typed function: loop counters
are bounded by their range, accumulators by trip count times their
per-pass growth, and masked values by the mask. A local whose every
value fits in 64 bits becomes a Java long, and an int expression whose
result fits is computed with wrapping long arithmetic, which equals the
exact result however large the intermediates are. Expression helpers
such as i32/i64 are inlined, module int constants are folded, and >> of
a value masked into [0, 2^64) becomes >>>.

Builtins without a typed lowering (print, sorted, ...) are now called
generically from typed code instead of leaving the whole function
untyped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd //, lowered loop tests

Locals that only ever hold a freshly constructed object whose __init__
copies its arguments into fields, and are only read through fields or
getters, become one local per field. while tests lower their arithmetic
and compares like any statement. for c in str walks code points, with
ord(c) the code point itself. l.extend([v] * n) fills in place. Lone
surrogates index and repr as CPython does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ped builtins over BOT, dict clear/len intrinsics

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… int results held bare, taken in the slow path

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t stores per instance, try-free dict key hashing

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-top arithmetic over impure calls

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ct clear; direct dict len

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… box the list

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
shai-almog and others added 11 commits October 31, 2026 10:09
The semantic analyzer's merge compared values with SimdAllocaValue.equals,
which refuses ASM's own BasicValue constants, so a long pushed by LCONST_1
meeting the checker's long at a join fell to BasicInterpreter.merge and became
a one-slot UNINITIALIZED_VALUE; the next DUP2 failed "Illegal use of DUP2" on
generated Python that ASM's plain analyzer accepts. Merge now compares types.

The typed float path for ** emitted Math.pow, which CLDC lacks; more stdlib
functions are typed now, and the demos' compliance check caught 30 such calls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pinning the GC

JFR on the JVM build of the Flask sample (escape analysis off) put the
request path at 17.7 KB allocated per request; it is now 12.7 KB on the
JVM, and the native binary's peak RSS under ab -c 8 fell from 765-816 MB
to 219-220 MB with no GC tuning.

- Flask shim: Headers keeps folded names beside the pairs; routing skips a
  rule whose literal prefix does not match before running its regex, and
  makes the 405 set only when needed; prebuilt JSON encoders; lazy flask.g;
  no copies of the header list or the blueprint chain per request.
- json: unescaped strings quote without a char list; sort_keys sorts pairs
  without a lambda; the circular check is an identity stack, not an id()
  dict.
- runtime: regex scratch (text, registers, stacks) reused per program via
  an atomic hand-off; str.startswith/endswith intrinsics and in-place
  affix; str < str compares without wrapping; str iteration and indexing
  share Latin-1 one-char strings; dict literals presized, first growth 4.
- backend: a connection's deferred-JSON sink and target memo table are
  made on first need, so a one-request connection allocates neither.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…66% survival

The collector sat at its peak footprint for 30 seconds after load stopped, because
only allocation or the long idle starts a cycle. The first quiet pass after a busy
one now idles 1s, so a quiet cycle runs the major sweep, page trim and malloc relief.

The backend build grows the trigger only at 66% survival instead of 25%, so the heap
settles near 1.5x the live set rather than 4x. Flask sample, 3 interleaved runs:
footprint after load 137-191MB -> 75-98MB, 5s later 101-139MB -> 68-70MB, at
27.7-29.2k -> 25.7-25.9k req/s.

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

A fixed 66% cost the Flask server 9% of its throughput. The threshold now moves
from CN1_BIBOP_TIGHT_SURVIVAL_PERCENT (backend: 66) when the collector is idle for
90% of wall time or more, to the VM's 25% when it is busy 40% or more. Default
builds set both equal and are unchanged. Full speed: 29.1-29.7k req/s vs
29.6-30.1k default and 26.0-26.9k fixed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cales with a small budget

Under a per-process budget the survival threshold is the tight one regardless of
the collector's duty cycle. The 64MB admission margin becomes a quarter of the
budget below 256MB: under 128MB the Flask server went from 478 to 16.3k req/s at
a 75MB footprint. Budgets of 256MB or more are admitted as before.

compare.py runs every server for the same 30s, reports physical footprint after
load, 5s later and at peak, and runs Codename One both unconstrained and under a
--budget-mb budget (default 128). render_charts.py adds the throughput-against-
memory chart.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd under a budget

The comparison now runs every Codename One binary twice: as shipped, where the
adaptive collector spends spare memory for throughput, and under a 128 MB
per-process budget, where it keeps the heap tight. Memory is physical footprint
for every runtime; Flask gets 30 s of load and a settle read. Adds the
throughput-vs-footprint chart.

Also routes the transpiler's float pow through Py.powd (Math.pow): MathUtil.pow
had made nbody 4x slower.

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Per-thread pacing claims lived in __thread storage, and a virtual thread
waiting for budget can resume on another host, so claims leaked until no
allocation was admitted and a budgeted server crawled. The claim is now one
global value stamped with the GC epoch, expiring after two cycles. Retired
virtual-thread stacks are released under a budget.

The comparison runs the 128 MB budget only: Flask under 64 MB cannot hold
the cap, since its unpaced virtual-thread stacks and malloc swing past it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	docs/developer-guide/languagetool-accept.txt
@shai-almog

shai-almog commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 193 screenshots: 193 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

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

Build and Run Timing

Metric Duration
Simulator Boot 55000 ms
Simulator Boot (Run) 1000 ms
App Install 17000 ms
App Launch 2000 ms
Test Execution 463000 ms

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 337ms / native 4ms = 84.2x speedup
SIMD float-mul (64K x300) java 300ms / native 3ms = 100.0x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 97.000 ms
Base64 CN1 decode 68.000 ms
Base64 native encode 1321.000 ms
Base64 encode ratio (CN1/native) 0.073x (92.7% faster)
Base64 native decode 1141.000 ms
Base64 decode ratio (CN1/native) 0.060x (94.0% faster)
Base64 SIMD encode 61.000 ms
Base64 encode ratio (SIMD/CN1) 0.629x (37.1% faster)
Base64 SIMD decode 60.000 ms
Base64 decode ratio (SIMD/CN1) 0.882x (11.8% faster)
Base64 encode ratio (SIMD/native) 0.046x (95.4% faster)
Base64 decode ratio (SIMD/native) 0.053x (94.7% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 7.000 ms
Image createMask (SIMD on) 3.000 ms
Image createMask ratio (SIMD on/off) 0.429x (57.1% faster)
Image applyMask (SIMD off) 367.000 ms
Image applyMask (SIMD on) 38.000 ms
Image applyMask ratio (SIMD on/off) 0.104x (89.6% faster)
Image modifyAlpha (SIMD off) 312.000 ms
Image modifyAlpha (SIMD on) 57.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.183x (81.7% faster)
Image modifyAlpha removeColor (SIMD off) 55.000 ms
Image modifyAlpha removeColor (SIMD on) 46.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.836x (16.4% faster)

shai-almog and others added 12 commits November 2, 2026 10:06
…docs: Vale

test_virtual_thread.c links cn1_virtual_thread.c without cn1_globals.m, so
the new cn1ProcessHasMemoryBudget() reference failed the link.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
viewSafeAreaInsetsDidChange calls it on Mac Catalyst and tvOS too, but it was
defined only in the iPhone layout branch, so the Metal Catalyst build failed
with -Wobjc-method-access.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	Ports/iOSPort/nativeSources/CodenameOne_GLViewController.m
#	scripts/developer-guide/check-guide-api-names.py
…e fairly

CPython and PyPy served the same ~690 requests a second under app.run()
although PyPy runs Flask twice as fast: Werkzeug's development server drains
the socket for 10 ms after every response, and ab counts a request done when
the socket closes. The guide keeps that chart, marks it as suspicious, tells
how the cause was found, and adds the fair comparison: compare.py now also
serves each interpreter behind gunicorn with 8 workers, footprint summed over
every process. flask_cost.py times Flask alone, without a server.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ide's accept list

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The base row is a single run; the branch's VM runtime measures identical to
master's on the self-hosted translator (interleaved A/B, reason in the file).

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

The multi-window default scenario was captured before its first paint (skin
and form solid black) because the menu bar alone passes the flat-image check;
single-window mode already waits that out, multi mode had no equivalent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The iOS accessibility thread contract (on IOSNative.m changes) and the
Xcode leg of the Gradle/Maven parity check queued on hosted macos-15 for
every matching pull request, and were dropped unrun when that pool was
short. Both now run nightly, plus on a pull request touching their own tree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shai-almog

shai-almog commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 193 screenshots: 193 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

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

Build and Run Timing

Metric Duration
Simulator Boot 97000 ms
Simulator Boot (Run) 1000 ms
App Install 14000 ms
App Launch 6000 ms
Test Execution 449000 ms

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 66ms / native 3ms = 22.0x speedup
SIMD float-mul (64K x300) java 65ms / native 4ms = 16.2x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 521.000 ms
Base64 CN1 decode 158.000 ms
Base64 native encode 859.000 ms
Base64 encode ratio (CN1/native) 0.607x (39.3% faster)
Base64 native decode 941.000 ms
Base64 decode ratio (CN1/native) 0.168x (83.2% faster)
Base64 SIMD encode 244.000 ms
Base64 encode ratio (SIMD/CN1) 0.468x (53.2% faster)
Base64 SIMD decode 111.000 ms
Base64 decode ratio (SIMD/CN1) 0.703x (29.7% faster)
Base64 encode ratio (SIMD/native) 0.284x (71.6% faster)
Base64 decode ratio (SIMD/native) 0.118x (88.2% faster)
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) 237.000 ms
Image applyMask (SIMD on) 57.000 ms
Image applyMask ratio (SIMD on/off) 0.241x (75.9% faster)
Image modifyAlpha (SIMD off) 50.000 ms
Image modifyAlpha (SIMD on) 54.000 ms
Image modifyAlpha ratio (SIMD on/off) 1.080x (8.0% slower)
Image modifyAlpha removeColor (SIMD off) 138.000 ms
Image modifyAlpha removeColor (SIMD on) 254.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 1.841x (84.1% slower)

…nutes

The x64 suite allocated a fixed 12G swap file and died 'No space left on
device' two minutes into the C build on a runner with little free disk; the
swap now leaves 40G for the build. build-ios-tv measured 15-22 min of build
plus 28-33 min of tests and was cancelled at its 60 minute limit mid-run on
this and other branches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shai-almog
shai-almog merged commit 5f96a6b into master Nov 5, 2026
@shai-almog
shai-almog deleted the python-support branch November 5, 2026 06:22
shai-almog added a commit that referenced this pull request Nov 7, 2026
* Fix the three nightly failures in #6160

dash: GameSocketTest slept out the countdown and then sent the host's
jump. Two runners who never jump are both out 6.4 s into Neon Causeway,
the race ends, and a later jump is dropped, so the jump had about 6 s
to land; a stalled CI container missed that and the guest waited for
the server's 300 s idle close (reproduced by delaying the jump). The
jump is now sent during the countdown, which the server stamps for tick
INPUT_DELAY, a read timeout fails a missing frame in 30 s, and the race
ending first is reported by name. OnlineRaceTest now holds the stamping
of a mid-race jump on a driven clock, which the socket test no longer
exercises. RaceRoom.intent's doc no longer says a countdown input is
dropped. The Initializr template is regenerated.

flutter-bench: the JavaScript code size moved +17.5% with #6163, whose
emitter reads instance fields as o.name instead of through the o[_qN]
alias table (valueEscape 20% faster). The gallery's wire bytes in the
same run moved +0.03%. Rebaselined with that reason.

nightly-watchdog: ios-accessibility-thread joined the nightly in #6128,
merged after that night's slot, and was reported as a schedule that
stopped firing. A suite with no scheduled run at all whose file reached
master inside the window is now listed as awaiting its first run, which
keeps the issue open; one that ran before and went quiet is still a
problem.

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

* Fix the Flutter gallery transpile #6154 broke, and gate it on every transpiler PR

#6154 merged a transpiler under which the Flutter gallery (the Flutter
benchmark's application) no longer compiled, and nothing on its PR ran it:
flutter-bench.yml runs on a PR only when its own tree changes. Every
benchmark leg of every PR since then failed in javac.

Fixed, each where it went wrong:
- a library-private class's static tear-off (`_DialogDemoState::_route`) was
  taken for a bound one and handed the class name as a receiver;
- a function-type witness nested in another reused its lambda parameter;
- an explicit `<num>` on a call whose parameter is `Comparable<T>` was written
  as `<Number>`, which no Long or Double satisfies;
- named arguments did not bind a generic function's type parameters, so
  `ease(begin: radius, end: 0)` emitted `0` as a long;
- List<E>.generate's generator had no E-typed return context;
- `double + (c ? x : 0)` took the Number arms of a num slot;
- the restorablePush stubs declared their route builder Object, and
  ScrollNotification's depth getter did not follow its siblings' naming.

flutter-gallery-compile.yml runs the benchmark's own path up to javac
(prepare.sh, then the generated project's compile) on every change to the
transpiler, the runtimes or the Flutter build steps.

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

* Rebaseline the JavaScript gallery's sizes for #6154's code generation

The gallery compiles again with this PR, so this is its first measurement
under #6154's transpiler: code and install grow 1,208,552 bytes while
wire_bytes moves +0.22%.

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

* Stop the Dart runtime calling String.split, which ParparVM lacks

#6154's FunctionType and TypeWitness split type-variable lists with
String.split, which is in neither vm/JavaAPI nor Ports/CLDC11: the JVM
legs pass and the native Linux and Windows translations fail to compile
an undeclared java_lang_String_split. DartUri and ContentType had the
same call. All four now split on a literal by hand.

Also rebaselines the Android gallery's dex size for #6154's code
generation; the APK itself moved +0.21%.

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

* Rebaseline the Linux and Windows gallery sizes for #6154's code generation

Both native galleries build again now that the Dart runtime no longer
calls String.split; code grows about 11% on each while the gallery's
wire size moves under 1%.

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

* Give the Flutter benchmark's Maven build a 4 GB heap

The gallery now transpiles and compiles inside Maven's JVM under #6154's
larger output, and the macOS runner's default quarter of 7 GB ran out in
jar packaging on the iOS leg.

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

* Rebaseline the iOS and macOS gallery sizes for #6154's code generation

Both now build with the 4 GB heap; code grows about 11% on each while
wire size moves under 1.5%.

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

* Dash e2e: one bot steers a whole stretch, never a loop of short windows

CityRunTest, PartyTest, PromoVideoTest and driveToBusy called driveFor
in a loop of 100-200 ms windows. Each call removed the bot's hook when
it returned, so the game ticked unsteered between calls, and on a slow
CI runner the city run crashed in one of those gaps before its first
landmark ("still running at the landmark"). driveUntil keeps one bot
on the controls until the condition holds, the run ends or time is up.

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

* Emit only the closure-signature members the generated code calls

#6154 gave the Flutter gallery 340 new classes, 320 of them in DartFnSigs:
a bridge class and a static factory for every signed SAM whether or not a
call site used it (105 bridges, 18 used), and an interface per signature
even where one SAM was its only carrier. Each is a class in the native
executable, which put Linux's code behind Flutter's. Only the members a
generated file names are emitted now, and a signature with a single carrier
is written into that SAM. Subclass const keys share ConstCanon.join instead
of inlining the concatenation into every keyed class.

Gallery: 904 -> 715 generated classes, 3.70 -> 3.45 MB of class files.

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

* Cut the native code #6154's transpiler output added to the gallery

Measured on the gallery's Linux executable, built in a container with the
same toolchain on both sides: 15.30 MB before #6154, 17.00 MB after it,
16.40 MB with this change.

- A statically typed num.clamp went through Dyn.call, which made every
  builtin's dynamic dispatch reachable (178 KB for four clamps). It calls
  Dyn.numClamp directly, and invoking a callable object takes a path that
  reaches only transpiled objects (Dyn.objectCall), not List/Map/String.
- Each class of a library with renamed private names registered the whole
  library's spellings from a static initializer of its own. They are
  registered once, from FlutterRegistry.invokeMain, one packed literal per
  library; the behavior harness enters through invokeMain as an app does.
- An enum builds its Dart-name table only when a value was renamed for Java.
- $constKey() is kept only for classes constructed as constants and their
  superclasses (64 of 278 in the gallery).

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

* Lower lambdas to shared carriers instead of a class per lambda

A lambda becomes an instance of a carrier -- one class per functional
interface and capture shape -- holding a function address and its captures.
Brought over from the python-hero-ports work; on the Flutter gallery it cuts
268 KB of native code.

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

* Let a lambda factory be frameless

The frameless path rejected any custom instruction, and FunctionAddress --
a constant push -- is the one every lambda factory has, so all 2,080 of the
Flutter gallery's factories got a full frame. -103 KB.

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

* Allocate out of line at NEW sites, keeping only the init guard inline

CN1_FAST_NEW expanded the always_inline bump allocator at all 9,951 NEW sites
of the Flutter gallery: 894 KB of a 16.0 MB executable. cn1BibopFastNew is
the same path behind one direct call. Interleaved vm/benchmarks A/B against
-DCN1_INLINE_ALLOC_SITES: geomean 1.004, objectAllocation 1.009, checksums
identical.

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

* Rebaseline the Windows arm64 hello perf row for the lambda carriers

Lowering lambdas to shared carriers made translating HelloCodenameOne
cheaper on both runtimes; ParparVM got faster, JDK 25 faster still, so the
ratio moved without a VM regression. Measurements are in the row's reason.

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

* Count a referenced SVG's syndication PNG as used in the guide image check

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

* Rebaseline the Linux gallery's cold-start ratio for #6154's code generation

Every run since the gallery compiles again measured 0.76-0.85 (still faster
than Flutter); the commits here do not move start-up. Evidence in the row.

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

* Make the game e2e waits and the site search test immune to runner load

The Dash and Skirmish online tests asserted wall-clock totals (360 ticks in
30 s, 100 server ticks in 30 s), so a runner shared with a dozen other jobs
failed them while the game was still ticking. They now fail only when the
ticks stop for 10 s, which is the stall they were written to catch.

The site search test ran against wrangler pages dev, whose workerd exits when
Chromium resets a connection on navigation; settling first (#6092) did not
stop it. Search is static files only, so it now runs against a plain file
server; the redirect checks keep the Pages runtime.

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

---------

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.

2 participants