Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
be08d90
Fix the three nightly failures in #6160
shai-almog Nov 5, 2026
24249a1
Merge remote-tracking branch 'origin/master' into fix-nightly-6160
shai-almog Nov 5, 2026
38e1a9e
Fix the Flutter gallery transpile #6154 broke, and gate it on every t…
shai-almog Nov 5, 2026
24acda3
Rebaseline the JavaScript gallery's sizes for #6154's code generation
shai-almog Nov 5, 2026
adfab90
Stop the Dart runtime calling String.split, which ParparVM lacks
shai-almog Nov 5, 2026
c7e173f
Rebaseline the Linux and Windows gallery sizes for #6154's code gener…
shai-almog Nov 5, 2026
ff206d5
Give the Flutter benchmark's Maven build a 4 GB heap
shai-almog Nov 5, 2026
38e2762
Rebaseline the iOS and macOS gallery sizes for #6154's code generation
shai-almog Nov 5, 2026
b9f4fc6
Dash e2e: one bot steers a whole stretch, never a loop of short windows
shai-almog Nov 5, 2026
d9d0c63
Emit only the closure-signature members the generated code calls
shai-almog Nov 6, 2026
de844b3
Cut the native code #6154's transpiler output added to the gallery
shai-almog Nov 6, 2026
e3e05a1
Lower lambdas to shared carriers instead of a class per lambda
shai-almog Nov 6, 2026
446219e
Let a lambda factory be frameless
shai-almog Nov 6, 2026
6fe0379
Allocate out of line at NEW sites, keeping only the init guard inline
shai-almog Nov 6, 2026
ce338e7
Rebaseline the Windows arm64 hello perf row for the lambda carriers
shai-almog Nov 7, 2026
55e01af
Count a referenced SVG's syndication PNG as used in the guide image c…
shai-almog Nov 7, 2026
cce5418
Merge remote-tracking branch 'origin/master' into fix-nightly-6160
shai-almog Nov 7, 2026
736b575
Rebaseline the Linux gallery's cold-start ratio for #6154's code gene…
shai-almog Nov 7, 2026
3971a39
Make the game e2e waits and the site search test immune to runner load
shai-almog Nov 7, 2026
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
140 changes: 140 additions & 0 deletions .github/workflows/flutter-gallery-compile.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
name: Flutter gallery compiles

# Transpiles the Flutter gallery -- the Flutter benchmark's application, and
# the largest real Dart program the transpiler sees -- and compiles the result,
# on every change to the transpiler, the runtimes or the Flutter build steps.
#
# The benchmark (flutter-bench.yml) does this too, but runs on a pull request
# only when its own tree changes. #6154 therefore merged a transpiler that
# turned the gallery into Java javac rejects (a private class's static
# tear-off, nested function-type witnesses, named-argument inference, numeric
# conditionals) with nothing on its pull request having looked, and the
# nightly and every later benchmark pull request were red. This job is the
# benchmark's own path up to javac -- prepare.sh, then the generated
# project's compile -- on one runner, measuring nothing.
#
# The unit and behavior tests (dart-flutter-tests.yml) check constructs one at
# a time and the acceptance apps (flutter-acceptance.yml) are small; neither
# reaches what this does.

on:
pull_request:
paths:
- 'maven/dart-transpiler/**'
- 'maven/dart-runtime/**'
- 'maven/flutter-runtime/**'
- 'maven/build-engine/src/main/java/com/codename1/maven/FlutterProjectBuilder.java'
- 'maven/build-engine/src/main/java/com/codename1/maven/FlutterProjectImporter.java'
- 'maven/build-engine/src/main/java/com/codename1/maven/DartLineMapper.java'
- 'maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/*Flutter*.java'
- 'scripts/flutter-bench/app/prepare.sh'
- 'scripts/flutter-bench/app/cn1/**'
- '.github/workflows/flutter-gallery-compile.yml'
push:
branches:
- master
paths:
- 'maven/dart-transpiler/**'
- 'maven/dart-runtime/**'
- 'maven/flutter-runtime/**'
- 'maven/build-engine/src/main/java/com/codename1/maven/FlutterProjectBuilder.java'
- 'maven/build-engine/src/main/java/com/codename1/maven/FlutterProjectImporter.java'
- 'maven/build-engine/src/main/java/com/codename1/maven/DartLineMapper.java'
- 'maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/*Flutter*.java'
- 'scripts/flutter-bench/app/prepare.sh'
- 'scripts/flutter-bench/app/cn1/**'
- '.github/workflows/flutter-gallery-compile.yml'
workflow_dispatch:

env:
# The benchmark's own pin (flutter-bench.yml): the gallery and the lockfile
# that holds its dependencies come from this SDK. Move the two together.
FLUTTER_REF: '3.35.4'

permissions:
contents: read
packages: read

concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
gallery:
runs-on: ubuntu-24.04
container: ghcr.io/codenameone/codenameone/pr-ci-container:latest
timeout-minutes: 60
defaults:
run:
shell: bash
env:
LANG: C.UTF-8
LC_ALL: C.UTF-8
steps:
- uses: actions/checkout@v6

- name: Link cn1-binaries
run: ln -s /opt/cn1-binaries ../cn1-binaries

- name: Check the container's JDKs
run: |
for var in JAVA_HOME_8 JAVA_HOME_17; do
eval "path=\${$var:-}"
if [ -z "$path" ] || [ ! -x "$path/bin/javac" ]; then
echo "$var is unset or has no javac: '${path:-<unset>}'" >&2
exit 1
fi
done

# The same two passes as flutter-bench.yml's framework job: what prepare.sh
# generates is a project from the shipping archetype, so it resolves the
# plugin, the archetype and core from this repository, and the runtimes,
# which build only on JDK 17.
- name: Build the framework on JDK 8
env:
RETRY_ONLY_MATCHING: transient
run: |
cd maven
JAVA_HOME="$JAVA_HOME_8" bash ../scripts/ci/retry.sh mvn -B -q install -DskipTests \
-Dmaven.javadoc.skip=true -Dmaven.source.skip=true \
-Plocal-dev-javase \
-Dmaven.repo.local="$GITHUB_WORKSPACE/m2" \
-pl core,dart-transpiler,codenameone-maven-plugin,cn1app-archetype -am

- name: Build the Flutter runtime on JDK 17
env:
RETRY_ONLY_MATCHING: transient
run: |
cd maven
JAVA_HOME="$JAVA_HOME_17" bash ../scripts/ci/retry.sh mvn -B -q install -DskipTests \
-Dmaven.javadoc.skip=true -Dmaven.source.skip=true \
-Plocal-dev-javase \
-Dmaven.repo.local="$GITHUB_WORKSPACE/m2" \
-pl dart-runtime,flutter-runtime

# A checkout, not a release archive: the gallery is dev/integration_tests,
# which the release archives leave out.
- name: Check out the Flutter SDK
run: |
git clone --depth 1 --branch "$FLUTTER_REF" \
https://github.com/flutter/flutter.git "$RUNNER_TEMP/flutter"
echo "$RUNNER_TEMP/flutter/bin" >> "$GITHUB_PATH"
echo "FLUTTER_ROOT=$RUNNER_TEMP/flutter" >> "$GITHUB_ENV"

- name: Prepare the gallery
run: |
flutter --version
JAVA_HOME="$JAVA_HOME_17" scripts/flutter-bench/app/prepare.sh \
--work "$RUNNER_TEMP/fbench" \
--maven-repo "$GITHUB_WORKSPACE/m2"

# compile, not package: the transpile and javac are what this guards, and
# neither needs a platform build or a display.
- name: Transpile and compile the gallery
env:
RETRY_ONLY_MATCHING: transient
run: |
cd "$RUNNER_TEMP/fbench/cn1"
JAVA_HOME="$JAVA_HOME_17" bash "$GITHUB_WORKSPACE/scripts/ci/retry.sh" mvn -B compile \
-Dmaven.repo.local="$GITHUB_WORKSPACE/m2" \
-DskipTests -DskipComplianceCheck=true -pl common -am
39 changes: 34 additions & 5 deletions .github/workflows/nightly-watchdog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ name: Nightly watchdog
# nightly is one cron line, with no list here to keep in sync. It then finds
# the newest scheduled run of each on master and keeps ONE issue open,
# assigned to NIGHTLY_ALERT_ASSIGNEE, listing every suite that failed or has
# not run in the last 30 hours. A run still going when checked is judged by
# not run in the last 30 hours -- except one that has never had a scheduled
# run and reached master inside that window, which is awaiting its first night.
# A run still going when checked is judged by
# the previous completed one, so a suite that fails after this job has looked
# is reported the next morning; and the issue closes only when every suite has
# finished green, never on one still running.
Expand Down Expand Up @@ -72,6 +74,7 @@ jobs:
const GREEN = ['success', 'skipped', 'neutral'];
const problems = [];
const running = [];
const awaiting = [];
const cancelled = [];
for (const file of nightly) {
let runs;
Expand All @@ -86,6 +89,31 @@ jobs:
}
const newest = runs[0];
if (!newest || Date.now() - new Date(newest.created_at).getTime() > STALE_MS) {
// A suite that has never had a scheduled run, and whose file
// reached master inside the window, joined the nightly after
// the night's slot: it is awaiting its first run, not broken.
// Only a suite with NO scheduled run at all qualifies -- one
// that ran before and then went quiet is a schedule that
// stopped, however recently its file was edited -- and only
// for the window after its file's latest master commit, so a
// cron that never fires is reported once the file has gone a
// day unedited. It keeps the issue open like a running
// suite, under its own heading.
if (!newest) {
let changed = null;
try {
const { data: commits } = await github.rest.repos.listCommits({
owner, repo, sha: 'master', path: `${dir}/${file}`, per_page: 1,
});
changed = commits.length ? new Date(commits[0].commit.committer.date).getTime() : null;
} catch (e) {
changed = null;
}
if (changed !== null && Date.now() - changed <= STALE_MS) {
awaiting.push(`- \`${file}\`: no scheduled run yet; it reached master at ${new Date(changed).toISOString()}`);
continue;
}
}
problems.push(`- \`${file}\`: no scheduled run in the last 30 hours (workflow disabled, or the schedule did not fire)`);
continue;
}
Expand All @@ -111,13 +139,13 @@ jobs:

await core.summary
.addHeading('Nightly watchdog')
.addRaw(`${nightly.length} nightly workflows, ${problems.length} failing, ${running.length} still running.\n\n`)
.addRaw([...problems, ...running].join('\n') || 'All green.')
.addRaw(`${nightly.length} nightly workflows, ${problems.length} failing, ${running.length} still running, ${awaiting.length} awaiting a first run.\n\n`)
.addRaw([...problems, ...running, ...awaiting].join('\n') || 'All green.')
.write();

if (problems.length === 0) {
// Close only on a night where everything finished green.
if (issue && running.length === 0) {
if (issue && running.length === 0 && awaiting.length === 0) {
await github.rest.issues.createComment({ owner, repo, issue_number: issue.number,
body: `Recovered: every nightly workflow passed on the run checked at ${now}.` });
await github.rest.issues.update({ owner, repo, issue_number: issue.number,
Expand All @@ -126,7 +154,7 @@ jobs:
// Nothing failing any more, but not every suite has finished:
// keep the issue open and stop it listing failures that are gone.
await github.rest.issues.update({ owner, repo, issue_number: issue.number, body: [
marker, `No failures as of ${now}; the issue closes once these finish green:`, '', ...running,
marker, `No failures as of ${now}; the issue closes once these finish green:`, '', ...running, ...awaiting,
].join('\n') });
}
return;
Expand All @@ -138,6 +166,7 @@ jobs:
'',
...problems,
...(running.length ? ['', 'Still running when checked (judged by their previous completed run):', '', ...running] : []),
...(awaiting.length ? ['', 'Awaiting their first scheduled run (new to the nightly):', '', ...awaiting] : []),
...(cancelled.length ? ['', 'Cancelled (not counted as failures):', '', ...cancelled] : []),
'',
'They run on a pull request only when their own tree changes, so a change to shared code (core, ports, builders, backend) first meets them here. This issue closes itself after a fully green night.',
Expand Down
17 changes: 16 additions & 1 deletion .github/workflows/website-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,22 @@ jobs:
--base-url "${PAGES_DEV_URL}" \
--redirects-file docs/website/public/_redirects \
--skip-auto-cases
node scripts/website/test_search.mjs "${PAGES_DEV_URL}"
# Search is static files only (prebuilt lunr indexes), so it runs
# against a plain file server: workerd exits when Chromium resets a
# connection mid-write on navigation ("::write ... Connection reset
# by peer"), which no settling before navigate prevented (#6092).
# The redirects above are what needs the Pages runtime.
SEARCH_PORT="$(pages_dev_free_port)"
python3 -m http.server "${SEARCH_PORT}" --bind 127.0.0.1 \
--directory docs/website/public >/tmp/search-static.log 2>&1 &
SEARCH_PID=$!
for _ in $(seq 1 30); do
curl -fsS -o /dev/null --max-time 2 "http://127.0.0.1:${SEARCH_PORT}/" && break
sleep 1
done
node scripts/website/test_search.mjs "http://127.0.0.1:${SEARCH_PORT}" \
|| { kill "${SEARCH_PID}"; exit 1; }
kill "${SEARCH_PID}"

- name: Validate internal links and images
uses: lycheeverse/lychee-action@v2
Expand Down
22 changes: 20 additions & 2 deletions maven/dart-runtime/src/main/java/dart/core/DartUri.java
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,7 @@ public DartList<String> pathSegments() {
p = p.substring(1);
}
if (!p.isEmpty()) {
for (String seg : p.split("/", -1)) {
for (String seg : splitLiteral(p, "/")) {
out.add(decodeComponent(seg));
}
}
Expand All @@ -934,7 +934,7 @@ public DartMap<String, String> queryParameters() {
public static DartMap<String, String> splitQueryString(String query) {
DartMap<String, String> out = new DartMap<>();
if (!query.isEmpty()) {
for (String pair : query.split("&", -1)) {
for (String pair : splitLiteral(query, "&")) {
if (pair.isEmpty()) {
continue;
}
Expand Down Expand Up @@ -1424,4 +1424,22 @@ private static char[] foldRange(String t, char[] out, int from, int to) {
}
return out;
}

/// `s` split at every `sep`, keeping empty pieces (Java's `split(sep, -1)` for a
/// literal). `String.split` is not in ParparVM's class library (`vm/JavaAPI`) nor
/// in `Ports/CLDC11`: it compiles and runs on the JVM, and the native translation
/// then fails to compile on an undeclared `java_lang_String_split`.
private static String[] splitLiteral(String s, String sep) {
java.util.ArrayList<String> out = new java.util.ArrayList<>();
int start = 0;
int at = s.indexOf(sep);
while (at >= 0) {
out.add(s.substring(start, at));
start = at + sep.length();
at = s.indexOf(sep, start);
}
out.add(s.substring(start));
return out.toArray(new String[out.size()]);
}

}
13 changes: 13 additions & 0 deletions maven/dart-runtime/src/main/java/dart/core/Symbol.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,19 @@ public static Object spell(String... pairs) {
return null;
}

/// Registers the pairs of {@link #spell} packed into one string, every name followed
/// by a newline (no Dart identifier contains one). One literal instead of an array
/// of them: built natively, each string constant costs code of its own.
public static void spellPacked(String pairs) {
int at = 0;
while (at < pairs.length()) {
int a = pairs.indexOf('\n', at);
int b = pairs.indexOf('\n', a + 1);
SPELLINGS.put(pairs.substring(at, a), pairs.substring(a + 1, b));
at = b + 1;
}
}

/// The name as Dart spells it: the one given with it, or the one registered for a
/// renamed private name. The renamed name stays in {@link #name} as the library
/// identity, so {@code #_x} of one library is not equal to {@code #_x} of another.
Expand Down
20 changes: 19 additions & 1 deletion maven/dart-runtime/src/main/java/dart/io/ContentType.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public java.util.Map<String, String> parameters() {

/** Dart's {@code ContentType.parse}: {@code type/subtype; charset=x}. */
public static ContentType parse(String value) {
String[] parts = value.split(";");
String[] parts = splitLiteral(value, ";");
String mime = parts[0].trim();
int slash = mime.indexOf('/');
String cs = null;
Expand Down Expand Up @@ -120,4 +120,22 @@ public String toString() {
}
return sb.toString();
}

/// `s` split at every `sep`, keeping empty pieces (Java's `split(sep, -1)` for a
/// literal). `String.split` is not in ParparVM's class library (`vm/JavaAPI`) nor
/// in `Ports/CLDC11`: it compiles and runs on the JVM, and the native translation
/// then fails to compile on an undeclared `java_lang_String_split`.
private static String[] splitLiteral(String s, String sep) {
java.util.ArrayList<String> out = new java.util.ArrayList<>();
int start = 0;
int at = s.indexOf(sep);
while (at >= 0) {
out.add(s.substring(start, at));
start = at + sep.length();
at = s.indexOf(sep, start);
}
out.add(s.substring(start));
return out.toArray(new String[out.size()]);
}

}
9 changes: 9 additions & 0 deletions maven/dart-runtime/src/main/java/dart/runtime/ConstCanon.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ public interface Keyed {
Object[] $constKey();
}

/// A subclass's key: its superclass's, then its own fields. One shared method
/// rather than the concatenation inlined into every keyed class's `$constKey()`.
public static Object[] join(Object[] inherited, Object[] own) {
Object[] r = new Object[inherited.length + own.length];
System.arraycopy(inherited, 0, r, 0, inherited.length);
System.arraycopy(own, 0, r, inherited.length, own.length);
return r;
}

public static <T> T object(T v) {
if (!(v instanceof Keyed)) {
return v;
Expand Down
Loading