Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
ae6ff90
Add pure-logic Java class library additions to JavaAPI and CLDC11
shai-almog Oct 17, 2026
9cd755f
Install the narrow JdkHost from the ParparVM ports
shai-almog Oct 17, 2026
153d67b
Translator runtime support and bulk conformance tests for the class l…
shai-almog Oct 17, 2026
2f94e2d
Rewrite every String regex member onto com.codename1.util.regex
shai-almog Oct 17, 2026
3f52e19
Java API additions: review fixes and CI root causes
shai-almog Oct 17, 2026
00c8053
Merge remote-tracking branch 'origin/master' into java-api-additions
shai-almog Oct 17, 2026
cb506da
Java API additions: second round of review fixes
shai-almog Oct 17, 2026
9dda99e
Java API additions: third round of review fixes and baselines
shai-almog Oct 17, 2026
5a90adf
Java API additions: fourth round of review fixes and baselines
shai-almog Oct 17, 2026
c371bd8
Java API additions: fifth round of review fixes
shai-almog Oct 18, 2026
52bacda
Java API additions: sixth round of review fixes
shai-almog Oct 18, 2026
a21e000
Java API additions: seventh round of review fixes
shai-almog Oct 18, 2026
2987440
Java API review fixes: URI query split, null arguments, ill-formed lo…
shai-almog Oct 18, 2026
603a022
Java API review fixes: FutureTask run-once, ranges, overflow, reentra…
shai-almog Oct 18, 2026
89cdf11
Java API review fixes: ISO offsets, negative zero year, addAllAbsent …
shai-almog Oct 18, 2026
128c3f9
Java API review fixes: zero multiplier parse, null buffers, variants,…
shai-almog Oct 18, 2026
4ad7d97
Java API review fixes: List/Set spliterator characteristics, chunked …
shai-almog Oct 18, 2026
e7cc77a
Java API review fixes: scheduled cancel race, runAndReset, allOf, edg…
shai-almog Oct 18, 2026
a396c3c
Java API review fixes: adapter characteristics, CharSequence.compare,…
shai-almog Oct 19, 2026
6379cb5
Java API review fixes: backtracking \R, continued property keys, clos…
shai-almog Oct 19, 2026
7d07a14
Java API review fixes: URI relative references, sorted spliterators, …
shai-almog Oct 19, 2026
dbde2ca
Java API review fixes: concat null checks, fixed-rate deadlines, remo…
shai-almog Oct 19, 2026
4f87a8b
Java API review fixes: null checks, invokeAll validation, immutable s…
shai-almog Oct 19, 2026
36016d1
Java API review fixes: close suppression, removeIf check order, subLi…
shai-almog Oct 19, 2026
b851af7
Java API review fixes: failures skip the executor, X- charsets, unord…
shai-almog Oct 19, 2026
8c578a5
Java API review fixes: variant tags, date literals, stream and regex …
shai-almog Oct 19, 2026
e79fd8c
Java API review fixes: allOf/anyOf null checks, runner release, chara…
shai-almog Oct 19, 2026
e8da7e5
Java API review fixes: prefixed zone syntax, yield interrupt, CLDC pa…
shai-almog Oct 19, 2026
994c81c
Java API review fixes: authority-only resolve, runAndReset release, C…
shai-almog Oct 20, 2026
791e9a4
Merge remote-tracking branch 'origin/master' into java-api-additions
shai-almog Oct 20, 2026
d7d8d7c
Java API review fixes: URI scheme grammar, ZZZZ parse, weak-map lookup
shai-almog Oct 20, 2026
a13c5c3
Java API review fixes: full localized offset, stats toString, done st…
shai-almog Oct 20, 2026
9cfc0c4
Java API review fixes: extreme instants, aggregate time conflicts, Mo…
shai-almog Oct 20, 2026
e30f5ee
Java API review fixes: day-of-year conflicts, bound spliterators, ato…
shai-almog Oct 20, 2026
c746b11
Merge remote-tracking branch 'origin/master' into java-api-additions
shai-almog Oct 20, 2026
00fe527
Java API review fixes: extlang subtags, CHM entry-set add, racy block…
shai-almog Oct 20, 2026
aa8cd48
Merge remote-tracking branch 'origin/master' into java-api-additions
shai-almog Oct 20, 2026
0112423
Java API review fixes: custom temporal units, parse past the end, sni…
shai-almog Oct 20, 2026
f1c38cb
Unmodifiable lists reject every mutation, stack traces print suppress…
shai-almog Oct 20, 2026
1fc02a9
Merge remote-tracking branch 'origin/master' into java-api-additions
shai-almog Oct 20, 2026
28c4d51
Map.of views reject clear, initializr build test prints the end of a …
shai-almog Oct 21, 2026
d466589
Merge remote-tracking branch 'origin/master' into java-api-additions
shai-almog Oct 21, 2026
59c57ac
Offset-only parses, MessageFormat clones its subformats, async stages…
shai-almog Oct 21, 2026
c7e7819
usePattern keeps zero-width advancement, reversed views snapshot alia…
shai-almog Oct 21, 2026
da29033
Merge remote-tracking branch 'origin/master' into java-api-additions
shai-almog Oct 21, 2026
da39d68
Merge remote-tracking branch 'origin/master' into java-api-additions
shai-almog Oct 21, 2026
1f95697
Zero offsets print as zero, ISO instants need offset minutes, U+180E …
shai-almog Oct 21, 2026
be12291
A continuation can join a nested dependent, CHM view removeIf keeps r…
shai-almog Oct 21, 2026
5fdb1e6
Merge master into java-api-additions
shai-almog Oct 21, 2026
bab334b
Regex by code point with Unicode tables; randomUUID needs a secure so…
shai-almog Oct 21, 2026
9ffec27
Merge remote-tracking branch 'origin/master' into java-api-additions
shai-almog Oct 21, 2026
f2f8bcf
PMD fixes in the regex engine; rebaseline Flutter size for the Unicod…
shai-almog Oct 21, 2026
cdde74b
Merge remote-tracking branch 'origin/master' into java-api-additions
shai-almog Oct 21, 2026
e403686
Recalibrate linux x64 translator and objectAllocation perf rows
shai-almog Oct 21, 2026
9f0db9d
Merge remote-tracking branch 'origin/master' into java-api-additions
shai-almog Oct 21, 2026
9ee6b84
Regex review: pairs in escapes and quotes, JDK search rule, tables fo…
shai-almog Oct 22, 2026
f82e9bf
Regex review 2: properties skip pair halves, caseless back references…
shai-almog Oct 22, 2026
093c43d
Regex review 3: unbounded single-atom lookbehind, quantified \R keeps…
shai-almog Oct 22, 2026
296cd7c
Regex review 4 (fuzzing): escaped pairs, COMMENTS before a suffix, fo…
shai-almog Oct 22, 2026
8acb87f
Merge remote-tracking branch 'origin/master' into java-api-additions
shai-almog Oct 22, 2026
a54015f
Rebaseline Flutter linux size for the regex code-point work
shai-almog Oct 22, 2026
fd5e147
Merge remote-tracking branch 'origin/master' into java-api-additions
shai-almog Oct 22, 2026
43a6fe5
Rebase the size and perf overlays onto master's #6059
shai-almog Oct 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
10 changes: 10 additions & 0 deletions .github/codeql/codeql-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ paths-ignore:
# casts -- so every program there must compile and behave exactly as javac's
# output does; "fixing" what CodeQL flags would remove the case under test.
- 'vm/JavaCompiler/tests/**'
# The device class library's own java.security.SecureRandom. CodeQL runs
# without a build here (build-mode: none), so it resolves `SecureRandom`
# everywhere -- the JDK-compiled backend included -- to this source file
# rather than to the JDK's class, sees `extends java.util.Random`, and
# reports every key the backend draws from the JDK's SecureRandom as
# "insecure randomness". The class itself delegates every byte to the
# platform's secure generator (JdkHost.randomBytes) and is not what the
# backend runs.
- 'vm/JavaAPI/src/java/security/SecureRandom.java'
- 'Ports/CLDC11/src/java/security/SecureRandom.java'
# The JavaScript target's numeric differential fixture, for the same reason:
# it compares narrowing compound assignments, saturating casts and overflow
# against the JVM, and writing the casts out would change the bytecode shape
Expand Down
3 changes: 2 additions & 1 deletion .github/scripts/build_javadocs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@ java/util/concurrent/TimeoutException.java"
python3 "$ROOT_DIR/scripts/check-backend-jdk-surface.py"
{
find "$BACKEND_STAGE" -name "*.java" | grep -v '/com/codename1/impl/'
find "$ROOT_DIR/Ports/CLDC11/src" -name "*.java"
# The class library's internal com.codename1.impl.JdkHost lives there too.
find "$ROOT_DIR/Ports/CLDC11/src" -name "*.java" | grep -v '/com/codename1/impl/'
echo "$BACKEND_PROMOTED_JDK" | while IFS= read -r promoted; do
echo "$ROOT_DIR/vm/JavaAPI/src/$promoted"
done
Expand Down
171 changes: 171 additions & 0 deletions CodenameOne/src/com/codename1/impl/CoreJdkHost.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/*
* Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Codename One designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Codename One through http://www.codenameone.com/ if you
* need additional information or have any questions.
*/
package com.codename1.impl;

import com.codename1.io.Log;
import com.codename1.l10n.L10NManager;
import com.codename1.security.Hash;
import com.codename1.ui.Display;

/// The [JdkHost] of a Codename One application: the class library's event
/// thread waits, log, secure random bytes, digests and locale symbols, served
/// by `Display`, `Log`, `SecureRandom`, `Hash` and `L10NManager`.
///
/// Internal. The ParparVM ports (iOS and macOS, Windows, Linux, JavaScript)
/// install it from their `init` through [CoreJdkHostInstaller]. On Java SE and
/// Android the real JDK runs and nothing installs it. `JdkHost` itself is part
/// of the class library, not of the core: the core compiles against it, and
/// the Java SE and Android ports carry a copy so this class always has its
/// superclass. Nothing here runs before the display is initialized except
/// what checks for it.
public class CoreJdkHost extends JdkHost {

/// The levels of [JdkHost] are those of `Log`.
@Override
public void log(int level, String message, Throwable thrown) {
if (message != null) {
Log.p(message, Math.max(Log.DEBUG, Math.min(Log.ERROR, level)));
}
if (thrown != null) {
Log.e(thrown);
}
}

@Override
public boolean isUiThread() {
return Display.isInitialized() && Display.getInstance().isEdt();
}

/// On the event dispatch thread the task runs through `invokeAndBlock`,
/// so the UI keeps serving events while it blocks.
@Override
public void blockUi(Runnable task) {
if (isUiThread()) {
Display.getInstance().invokeAndBlock(task);
} else {
task.run();
}
}

/// Derived from what `L10NManager` formats, since it exposes the
/// separators only through formatting.
@Override
public String[] localeNumberSymbols() {
if (!Display.isInitialized()) {
return null;
}
L10NManager l10n = L10NManager.getInstance();
char decimal = firstSeparator(l10n.format(1.5, 1));
char grouping = firstSeparator(l10n.format(1234567.0, 0));
return new String[] {
decimal == 0 ? null : String.valueOf(decimal),
grouping == 0 || grouping == decimal ? null : String.valueOf(grouping),
emptyToNull(l10n.getCurrencySymbol())
};
}

/// `null` for a null or empty string. A port's `L10NManager` may answer
/// either when it knows no currency symbol.
private static String emptyToNull(String s) {
return s == null || s.length() == 0 ? null : s;
}

/// The first character of `text` that sits between two digits, or 0.
/// Digits are any script's decimal digits, not only ASCII: a locale such
/// as Arabic or Hindi formats `1.5` with its own digits, and stopping at
/// the first non-ASCII character would report no separator at all.
/// Signs, currency and spacing before the number are skipped.
private static char firstSeparator(String text) {
if (text == null) {
return 0;
}
for (int i = 1; i + 1 < text.length(); i++) {
char c = text.charAt(i);
if (!isDecimalDigit(c) && isDecimalDigit(text.charAt(i - 1))
&& isDecimalDigit(text.charAt(i + 1))) {
return c;
}
}
return 0;
}

/// Whether `c` is a decimal digit in a script `L10NManager` may format
/// with: ASCII, Arabic-Indic, extended Arabic-Indic, Devanagari, Bengali,
/// Thai and fullwidth.
private static boolean isDecimalDigit(char c) {
return c >= '0' && c <= '9'
|| c >= 0x660 && c <= 0x669 || c >= 0x6f0 && c <= 0x6f9
|| c >= 0x966 && c <= 0x96f || c >= 0x9e6 && c <= 0x9ef
|| c >= 0xe50 && c <= 0xe59 || c >= 0xff10 && c <= 0xff19;
}

@Override
public void randomBytes(byte[] out) {
com.codename1.security.SecureRandom.fill(out);
}

@Override
public Digest digest(String algorithm) {
if (!Hash.MD5.equalsIgnoreCase(algorithm) && !Hash.SHA1.equalsIgnoreCase(algorithm)
&& !Hash.SHA224.equalsIgnoreCase(algorithm) && !Hash.SHA256.equalsIgnoreCase(algorithm)
&& !Hash.SHA384.equalsIgnoreCase(algorithm) && !Hash.SHA512.equalsIgnoreCase(algorithm)) {
return null;
}
try {
return new HashDigest(Hash.create(algorithm));
} catch (com.codename1.security.CryptoException e) {
// A port without this digest; the class library reports the
// algorithm as unavailable.
return null;
}
}

/// A core `Hash` as a [JdkHost.Digest].
private static final class HashDigest implements Digest {
private final Hash hash;

HashDigest(Hash hash) {
this.hash = hash;
}

@Override
public void update(byte[] data, int offset, int length) {
hash.update(data, offset, length);
}

@Override
public byte[] digest() {
return hash.digest();
}

@Override
public void reset() {
hash.reset();
}

@Override
public int length() {
return hash.digestLength();
}
}
}
40 changes: 40 additions & 0 deletions CodenameOne/src/com/codename1/impl/CoreJdkHostInstaller.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Codename One designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Codename One through http://www.codenameone.com/ if you
* need additional information or have any questions.
*/
package com.codename1.impl;

/// Installs [CoreJdkHost] as the class library's [JdkHost].
///
/// Internal. The ParparVM ports call [#install] first thing in their `init`.
/// It is a class of its own so that a port names neither `JdkHost` nor
/// `CoreJdkHost`: compiling a call to a static method of `CoreJdkHost` would
/// need its superclass on the port's class path, and the Java SE based tools
/// that load `Display` or the implementation class never load either.
public final class CoreJdkHostInstaller {
private CoreJdkHostInstaller() {
}

/// Makes [CoreJdkHost] the host the class library uses.
public static void install() {
JdkHost.install(new CoreJdkHost());
}
}
89 changes: 11 additions & 78 deletions CodenameOne/src/com/codename1/impl/JdkApiRewriteHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@
*/
package com.codename1.impl;

import com.codename1.util.regex.RE;
import com.codename1.util.regex.RESyntaxException;
import com.codename1.util.regex.StringRegex;

/// Bridge methods used by bytecode rewrite rules for JDK APIs that are risky/unsupported on some targets.
public final class JdkApiRewriteHelper {
Expand Down Expand Up @@ -80,91 +79,25 @@ public static int compare(byte x, byte y) {
return x - y;
}

// The String regex members delegate to StringRegex, the one engine every
// build rewrites String's regex members to (BytecodeCompliance's
// INVOCATION_REWRITE_RULES). They stay because a class rewritten by an
// older build names them; they must never grow an engine of their own
// again -- two engines made the same call answer differently by target.

public static String replaceAll(String source, String regex, String replacement) {
if (source == null) {
throw new NullPointerException("source is null");
}
if (regex == null) {
throw new NullPointerException("regex is null");
}
if (replacement == null) {
throw new NullPointerException("replacement is null");
}
try {
return new RE(regex).subst(source, replacement, RE.REPLACE_ALL | RE.REPLACE_BACKREFERENCES);
} catch (RESyntaxException ex) {
return com.codename1.util.StringUtil.replaceAll(source, regex, replacement);
}
return StringRegex.replaceAll(source, regex, replacement);
}

public static String replaceFirst(String source, String regex, String replacement) {
if (source == null) {
throw new NullPointerException("source is null");
}
if (regex == null) {
throw new NullPointerException("regex is null");
}
if (replacement == null) {
throw new NullPointerException("replacement is null");
}
try {
return new RE(regex).subst(source, replacement, RE.REPLACE_FIRSTONLY | RE.REPLACE_BACKREFERENCES);
} catch (RESyntaxException ex) {
int idx = source.indexOf(regex);
if (idx < 0) {
return source;
}
return source.substring(0, idx) + replacement + source.substring(idx + regex.length());
}
return StringRegex.replaceFirst(source, regex, replacement);
}

public static String[] split(String source, String regex) {
return split(source, regex, 0);
return StringRegex.split(source, regex);
}

public static String[] split(String source, String regex, int limit) {
if (source == null) {
throw new NullPointerException("source is null");
}
if (regex == null) {
throw new NullPointerException("regex is null");
}
if (regex.length() == 0) {
return new String[]{source};
}
try {
String[] split = new RE(regex).split(source);
if (limit > 0 && split.length > limit) {
String[] limited = new String[limit];
for (int i = 0; i < limit - 1; i++) {
limited[i] = split[i];
}
StringBuilder remainder = new StringBuilder();
for (int i = limit - 1; i < split.length; i++) {
if (i > limit - 1) {
remainder.append(regex);
}
remainder.append(split[i]);
}
limited[limit - 1] = remainder.toString();
return limited;
}
if (limit == 0) {
int end = split.length;
while (end > 0 && split[end - 1].length() == 0) {
end--;
}
if (end == split.length) {
return split;
}
String[] trimmed = new String[end];
System.arraycopy(split, 0, trimmed, 0, end);
return trimmed;
}
return split;
} catch (RESyntaxException ex) {
java.util.List<String> fallback = com.codename1.util.StringUtil.tokenize(source, regex);
return fallback.toArray(new String[fallback.size()]);
}
return StringRegex.split(source, regex, limit);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Codename One and/or its affiliates. All rights reserved.
* Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
Expand All @@ -20,14 +20,22 @@
* Please contact Codename One through http://www.codenameone.com/ if you
* need additional information or have any questions.
*/
package java.util.regex;
package com.codename1.util.regex;

/// What one match found: the same shape as `java.util.regex.MatchResult`.
public interface MatchResult {
public int end();
public int end(int group);
public String group();
public String group(int group);
public int groupCount();
public int start();
public int start(int group);

int start();

int start(int group);

int end();

int end(int group);

String group();

String group(int group);

int groupCount();
}
Loading
Loading