Skip to content

Device runtime: run pushed Codename One apps on a phone - #5561

Open
shai-almog wants to merge 48 commits into
masterfrom
device-runtime
Open

Device runtime: run pushed Codename One apps on a phone#5561
shai-almog wants to merge 48 commits into
masterfrom
device-runtime

Conversation

@shai-almog

@shai-almog shai-almog commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

Adds a device runtime: install one app on a phone, then push a project to it
from your IDE and watch it run natively in seconds. A third way to run a
Codename One app, alongside the simulator and a cloud device build.

Pushed classes are interpreted on the device against the framework already
compiled into it. Nothing is built, signed or installed between edits — the
edit-run loop measured 2.8 seconds end to end.

Try it

# install ~/cn1-device-runtime.apk on a phone (11MB, no native libs, any arch)
cd scripts/devruntime-ide-project
mvn -Ppush-lan package

The desktop finds the phone on the local network, shows a six-digit pairing
code you type once, and from then on it is edit-and-run. --device <address>
is there for networks that block a scan.

What is here

CodenameOne/src/com/codename1/interp/ the interpreter
Ports/{Android,iOSPort} per-platform linkers, iOS native bridge
vm/ByteCodeTranslator bundle writer, lambda desugaring, DevicePush tool
scripts/cn1-device-runtime/ the runtime app itself
scripts/devruntime-ide-project/ the project you open in an IDE
scripts/devruntime-probes/ 20 programs that found the defects worth knowing about
docs/developer-guide/Device-Runtime.asciidoc how and why

Decisions worth reviewing

Shims are generated over the whole API, never curated. A hand-maintained
list is a promise that applications only subclass what somebody anticipated, and
its failure mode is not an error message but an override that is silently never
called. The generator fails the build rather than pruning what will not compile
— a compile-and-drop loop once silently ate Interp_ui_Form.

Native-heavy subsystems are excluded from the shim set (ai, ar,
camera, surfaces, car, health, …). A shim is a compiled reference to the
class it extends, which is exactly what the build scans to decide what to link,
so generating the full API pulled 300MB of ML Kit, ARCore and CameraX natives
into an app that calls none of them. Cost: those types cannot be subclassed by
pushed code; calling them degrades to isSupported() == false, which is the
runtime's existing contract for a cn1lib without its native half.

iOS keeps shims rather than runtime vtable synthesis. Synthesis would make
14 more types extensible on iOS only, and Android cannot follow — so the usable
capability, the intersection, does not move. InterpHostVtableSynthesisIntegrationTest
stays for the day that changes.

synchronized uses the real object monitor, not a private lock table, which
is what makes wait/notify work.

Framework fixes that fell out

  • AndroidImplementation.getHostOrIP() returned dummy0's IPv6 link-local
    instead of a usable IPv4 — affects any caller.
  • CodenameOneImplementation.getResourceAsStream gained a local-resource hook,
    so a pushed program's theme.res is found by Resources.openLayered, which
    never passes through Display.

Verification

4798 core · 506 translator · 52 interpreter · SpotBugs 0 · 20-program device
battery green on an Android emulator and the iOS simulator, including a
four-file, three-package app entered through Lifecycle rather than main.

Every probe exists because something plausible turned out not to work; the
README records which defect each was written for.

Review rounds

Eleven findings from codex, all real, all fixed and each answered on its thread.
The two that mattered most:

  • Pairing handed out a bearer token. The peer id travelled in the clear on
    every push and never rotated, so one captured frame authorised arbitrary code
    on that phone forever. v2 is gone rather than deprecated. v3 derives a 256-bit
    secret on both ends from (typed code, peerId, deviceId) — never transmitted —
    and every connection answers a fresh challenge whose MAC covers the bundle.
    Authentication happens before the approval prompt, so nobody can raise dialogs
    on a stranger's phone until they tap Approve to stop them. What it still does
    not defeat is a passive observer of the pairing exchange itself, and the docs
    say so.
  • A failed class initializer left the class looking initialized, so later
    reads returned whatever half of it had been assigned. Four states and an owning
    thread now, per JLS 12.4.2.

Shipping it

.github/workflows/device-runtime-store.yml runs Mondays and on demand,
uploading to Play internal testing and TestFlight. It does not promote to
production and does not submit for review — a weekly automatic release would
put unread builds in front of the public and queue an iOS review every week
whether anything changed or not. Promotion stays one deliberate command.

Without credentials the job names the missing secrets and stops rather than
publishing half a release; none exist yet, so today it is a no-op that says so.

Listing text is in fastlane's layout (scripts/cn1-device-runtime/fastlane/) so
supply and deliver consume it directly, with store/privacy.md for both
stores' data forms and store/README.md for the secrets, the pre-submission
checklist and the review-risk assessment.

The compliance point that matters: this app runs code it did not ship with,
which is Guideline 2.5.2 — permitted for tools that develop or test code, and
only while the source is "completely viewable and editable by the user". The
runtime refuses to load a bundle whose sources it lacks, and shows them under
View source. Removing that screen makes the app unsubmittable, which is why
the code says so where the screen is defined.

Not done

NativeLookup stubbing covers the Java half of a cn1lib; the native half
reports unsupported. Resource push covers theme.res, CSS and images.

Screenshots for both stores, the Play content rating questionnaire, Apple's
privacy manifest and the console listings themselves are human steps, listed in
store/README.md.

🤖 Generated with Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ddc43de0d2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/device-runtime-store.yml Outdated
Comment thread CodenameOne/src/com/codename1/interp/InterpRuntime.java Outdated
Comment thread vm/ByteCodeTranslator/src/com/codename1/tools/translator/InterpBundleWriter.java Outdated
shai-almog and others added 3 commits August 17, 2026 15:49
Codename One apps run two ways today: the JavaSE simulator, which is not a
device, or a cloud device build, which costs minutes per iteration. This adds a
third: install one app on a phone, and from then on push a project to it from an
IDE and watch it run natively in seconds.

The app is not a shell around a compiled build. Pushed classes are interpreted
on the device against the framework already compiled into it, so nothing is
built, signed or installed between edits.

How the pieces fit
------------------

com.codename1.interp is the interpreter: one interpreted frame per real frame,
so Display.invokeAndBlock and every blocking idiom built on it still work. A
per-thread fuel counter bounds runaway code, and the budget is per entry into
the interpreter rather than per session -- measuring it per session kills every
callback that arrives later than the budget, which in an application whose whole
life is callbacks is every button press.

Interpreted classes reach the framework through InterpLinker: invoke thunks on
iOS, reflection on Android. A linker must dispatch on the receiver's class, not
the call site's declared type -- list.add(x) names java.util.List, and resolving
from there finds AbstractList.add, whose body throws.

Extending a framework class needs an object the framework accepts, which neither
platform can define at run time. Generated shims provide it: every public,
non-final, constructible class and every public interface the device exposes,
derived by scanning the framework jar and codenameone-java-runtime rather than
curated. A hand-maintained list is a promise that applications only subclass
what somebody anticipated, and its failure mode is not an error but an override
that is silently never called.

Lambdas and method references are rewritten into real classes when the bundle is
written, since neither target has a runtime invokedynamic. Enums are answered by
the interpreter, java.lang.Enum having no shim and needing none.

Store compliance is built in rather than bolted on: the runtime refuses to load
a bundle whose sources it cannot show, and shows them.

Verified
--------

4798 core tests, 506 translator tests, 43 interpreter tests, SpotBugs at zero,
and a 20-program device battery (scripts/devruntime-probes) passing on both an
Android emulator and the iOS simulator -- including a four-file, three-package
application entered through Lifecycle rather than main.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Listing text in fastlane's layout so supply and deliver can consume it, a
privacy statement for both stores' data forms, and a scheduled workflow.

The weekly job uploads to Play internal testing and TestFlight. It does not
promote to production and does not submit for App Store review, which is a
decision rather than an omission: a weekly automatic release would put unread
builds in front of the public and queue an iOS review every week whether or not
anything changed. Promotion stays one command, taken deliberately.

Without publishing credentials the job reports which secrets are missing and
stops, rather than publishing half a release. None of them exist yet.

The review risk is written down rather than discovered later. This app runs code
it did not ship with, which is squarely Guideline 2.5.2 -- permitted for tools
that develop or test code, and only while the source stays viewable and editable
on the device. That is why the runtime refuses a bundle it cannot show the
source for. 4.7.2 is the sharper edge and the argument to make is that this is
point to point developer tooling rather than a mini-app platform.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ate every push

Three things the review asked for, and two defects found on the way.

The interpreter moves from com.codename1.interp to com.codename1.impl.interp.
It is an implementation detail of one app, not public API, and the impl
hierarchy is what keeps it out of the javadoc. Note the package name is not only
a Java name: ParparVM's dead-code pass recognises the runtime's own classes by
their C-mangled prefix, so Parser.isLoadBearingForInterp moved with it. Missing
that would have stubbed out InterpRuntime.run in an interp-host build, which
fails by succeeding -- every pushed program "runs" instantly and executes
nothing.

The ~1000 generated shims leave git. They are a mechanical function of the
framework jar, so the build generates them: a tools module builds the
generator, exec-maven-plugin runs it into target/generated-sources/shims, and
build-helper adds that as a source root.  scripts/generate-interp-shims.sh
keeps the three properties the build takes on faith -- every shim compiles, the
load-bearing ones exist, generating twice is identical -- and now asserts them
against a scratch tree instead of writing into src.

Pairing no longer hands out a bearer token. v2 authorised a push with a peer id
sent in the clear, so capturing one frame on a LAN meant pushing arbitrary code
to somebody's phone forever. v3 derives a 256-bit secret on both ends from the
typed code, the peer id and the device id -- never transmitted, 20k HMAC
iterations so grinding six digits costs something -- and every connection
answers a fresh challenge whose MAC covers the bundle. Authentication happens
before the approval prompt, so nobody can raise dialogs on a stranger's phone
until they tap Approve to stop them. What this still does not defeat is a
passive observer of the pairing exchange itself, which the docs now say plainly.
There are two implementations of the derivation, since ParparVM has no
javax.crypto; InterpPairingSecretTest runs both and compares.

Also fixed:

- A class initializer that threw left the class marked initialized, so later
  reads returned whatever half of it had been assigned. Four states and an
  owning thread now, per JLS 12.4.2.
- Sources were keyed by file name, so two Util.java in different packages
  collided and the runtime refused the program with "missing the source file
  Util.java" for a file it had been handed. Keyed by package now.
- The iOS release job resolved ExportOptions.plist relative to the generated
  Xcode project, which is not where it lives.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
check-copyright-headers gates every added source file, and the probes and the
IDE sample are ours -- not third-party, so the exclusions file (which is for
provenance, and rejects anything else) is the wrong place for them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

💡 Codex Review


P1 Badge Register the Android linker before checking support

On every Android launch this support check is false because no code installs the newly added InterpAndroidLinker: a repository-wide search finds InterpPlatform.register(...) only in IOSImplementation. Consequently DeviceRuntimeApp.init() returns without starting either transport and the Android runtime app cannot accept any pushed program; register an InterpAndroidLinker during Android port initialization.


final InterpRuntime rt = new InterpRuntime(bundle, InterpPlatform.getLinker(), factory);
factory.attach(rt);
runtime = rt;

P2 Badge Stop the previous program before replacing its runtime

When the normal “Push again … to replace it” workflow loads a second bundle, this assignment discards the service's reference to the previous runtime without requesting cancellation or invoking the previous Lifecycle.stop()/destroy(). Programs that registered global listeners, timers, network callbacks, or worker threads therefore continue executing alongside the replacement, and after this overwrite the service can no longer stop them.


if (!send(payload, port, peerId, false) && rejectedAsUnpaired()) {

P2 Badge Propagate failed LAN pushes as process failures

For an already-paired LAN push, send() returns false when the user denies approval, authentication fails, or the device rejects/runs the bundle unsuccessfully; unless the message contains “not paired,” this condition falls through and main() exits with status 0. The documented Maven push-lan profile therefore reports BUILD SUCCESS for a failed deployment, which also prevents scripts and IDE integrations from detecting the failure.


synchronized (found) {
if (found[0]) {
return;
}
found[0] = true;
foundAt[0] = candidate;
}
handle(is, os, false);

P2 Badge Validate a discovered peer before remembering its address

If any unrelated service happens to accept this port during the subnet sweep, the callback marks it as found before handle() validates the protocol magic. The sweep then persists that address, and subsequent dial attempts likewise treat a successful TCP connection as served even when the peer never sends a runtime frame, so discovery can remain stuck on the wrong machine; only publish found/foundAt after a valid handshake.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

✅ Continuous Quality Report

Test & Coverage

  • Tests: 997 total, 0 failed, 0 skipped
  • ⚠️ 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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3118d715e7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/cn1-push.sh Outdated
Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java Outdated
Comment thread .github/workflows/device-runtime-store.yml Outdated
shai-almog and others added 2 commits August 17, 2026 21:15
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three were real: a SecureRandom built per call (worse and slower than one
seeded once, and what it generates is the pairing code), two Files.createDirectories
calls on a getParent() that SpotBugs cannot prove non-null, and an
ExecutorService.submit whose Future was never going to be read -- execute()
says what the scan actually wants.

The other two are recorded in spotbugs-exclude.xml with their reasons: a
command-line tool exits, and a failure while enumerating this machine's
interfaces must be answered with 'no device found' rather than by killing the
push.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

💡 Codex Review

ShimObjectFactory factory = new ShimObjectFactory();
final InterpRuntime rt = new InterpRuntime(bundle, InterpPlatform.getLinker(), factory);
factory.attach(rt);
runtime = rt;

P1 Badge Tear down the previous runtime before replacing it

When a second bundle is pushed, this assignment only drops the service's reference to the previous runtime; it neither requests cancellation nor invokes any lifecycle cleanup. Peers, background threads, timers, and framework listeners retain references to the old runtime, so the supposedly replaced application can continue executing and mutate the UI or shared resources while the new application runs. Add a runtime deactivation/cleanup path and call it before publishing the replacement.


if ("toString".equals(name) && args.length == 0) {
return io.toString();
}
return NOT_OBJECT_METHOD;

P2 Badge Route Object monitor methods to interpreted-object monitors

For a peerless interpreted object, calls inherited from Object are handled here, but wait, notify, and notifyAll fall through to NOT_OBJECT_METHOD and ultimately raise AbstractMethodError. Consequently ordinary code such as synchronized (lock) { lock.wait(); }, where lock is a pushed POJO, cannot use Java monitor coordination even though MONITORENTER successfully acquired that same InterpObject; dispatch these methods against the monitor used by the interpreter.


for (File f : kids) {
if (f.isDirectory()) {
addSourceTree(f);
} else if (f.getName().endsWith(".java")) {
String text = new String(Files.readAllBytes(f.toPath()), StandardCharsets.UTF_8);
addSource(sourceKey(packageOf(text), f.getName()), text);

P2 Badge Include Kotlin files in pushed source bundles

When compiled output contains Kotlin classes, even explicitly passing a Kotlin source directory to --source cannot produce a valid bundle because this traversal ignores every .kt file. The reader later requires the SourceFile entry (for example Foo.kt) for each carried class and rejects the bundle as missing source, so Kotlin Codename One applications cannot be pushed; collect Kotlin sources and ensure the default project discovery also includes src/main/kotlin.


if ("com/codename1/system/Lifecycle".equals(cn.superName)) {
lifecycle = cn.name;
}

P2 Badge Discover Lifecycle subclasses through the class hierarchy

Entry-point discovery recognizes only classes whose immediate superclass is Lifecycle. If an application class extends a project-defined base lifecycle, this either reports no entry point or selects the base class itself (often abstract) instead of the concrete application, even though InterpRuntime.extendsHost() can execute an indirect subclass once selected. Resolve the collected superclass graph and choose the concrete transitive Lifecycle subclass.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d4d7ad9bda

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread vm/ByteCodeTranslator/src/com/codename1/tools/translator/DevicePush.java Outdated
Comment thread vm/ByteCodeTranslator/src/com/codename1/tools/translator/DevicePush.java Outdated
Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java
Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java Outdated
@github-actions

Copy link
Copy Markdown
Contributor

Cloudflare Preview

Seven findings, all real.

The interpreter:

- A class literal for a pushed type puts an InterpClass on the stack, because
  there is no host class object to hand back -- and then the bytecode goes on
  calling java.lang.Class methods on it, which no linker can serve. The part of
  Class that means anything here (naming, identity, isInterface, isInstance,
  getSuperclass) is answered by the interpreter; anything else is refused by
  name rather than answered wrongly.
- `new Entry[1][]` names its component `[LEntry;`, not `Entry`, so the
  bundle-membership test missed it and asked the host loader for a class only
  the bundle has. It looks through the brackets now, and multianewarray builds
  the nested Object[] itself rather than delegating.
- JLS 12.4.1: initializing a class initializes the superinterfaces that declare
  a default method. Only those -- initializing all of them would run
  initializers Java never runs, which is as wrong as running them late.

The push tool:

- The Lifecycle entry point was chosen by direct superclass only, so a project
  whose app extends its own BaseApp entered BaseApp: an abstract class that was
  never meant to be instantiated. It walks the hierarchy now and takes the
  deepest concrete descendant.
- A subnet scan treated any host that accepted TCP on the port as the device,
  and then failed the push against it while the real device sat unqueried.
  There is a PING frame now; only an answer in our own protocol wins.
- cn1-push.sh still spoke v2, which nothing accepts any more. Its paired mode
  is gone rather than ported: it is a loopback helper, and pushing to a phone
  over Wi-Fi is DevicePush's job. A third copy of the derivation in a shell
  script would only drift from the two that have to agree.

The release workflow now checks every secret the job will consume, not the two
that name the store, so a half-configured store says so in preflight instead of
half an hour later in the signing step.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1356d055bd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java Outdated
Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java
Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java Outdated
Comment thread vm/ByteCodeTranslator/src/com/codename1/tools/translator/DevicePush.java Outdated
Comment thread CodenameOne/src/com/codename1/impl/CodenameOneImplementation.java Fixed
CLDC11 keeps AbstractMethodError's constructors package-private, so the
framework cannot throw one with a message and the Ant leg would not compile.
IncompatibleClassChangeError carries the message, and a message naming the
method is worth more here than the exactly right type.

The three inline source blocks in the device runtime chapter move into
docs/demos and are included by tag, which is what the guide validator asks of
every other chapter.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 47fd057b7e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/impl/interp/InterpObject.java
Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java
Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java Outdated
Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java Outdated
The interpreter's depth cap throws one, and it is the right type: ParparVM's
java.lang has StackOverflowError and so does every JVM the simulator runs on.
It was simply missing from this compile-time stub, so the Ant leg could not
compile the framework while the Maven leg could -- the two disagree because
only the Ant build puts CLDC11 on the bootclasspath.

Reproducing that locally needs the same -bootclasspath; compiling core and
CLDC11 together against a full JDK resolves java.lang from the JDK and reports
nothing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

💡 Codex Review

@Override
public void init(Object m) {
// NOTE: Do not explicitly set the PlayServices instance to anything other than

P1 Badge Register the Android linker during port initialization

On every Android runtime build, DeviceRuntimeService.isSupported() requires InterpPlatform.isAvailable(), but the Android initialization path never calls InterpPlatform.register(new InterpAndroidLinker()); a repository-wide search finds no other construction of InterpAndroidLinker, while IOSImplementation.init() performs the corresponding registration. Consequently startDialer() always returns false on Android with “no interpreter bindings,” so the newly added Android device runtime cannot accept any pushes.


f.pushRef(isInterpretedLeaf(comp)
? new Object[count]
: linker.newArray(comp.startsWith("[") ? comp : "L" + comp + ";", count));

P2 Badge Preserve interpreted array component types

When the leaf type is interpreted, allocating every reference array as a plain Object[] discards its runtime component type. For example, after Sub[] a = new Sub[1]; Base[] b = a;, storing new Base() through b must throw ArrayStoreException, but AASTORE later writes unconditionally into this Object[], so the invalid value is accepted and the array is silently corrupted. Retain component metadata or otherwise validate each store against the allocated array type.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@shai-almog

shai-almog commented Aug 17, 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 Aug 17, 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)

The chapter was written before the rebase brought in the vale gate and had
never been through it: 141 findings, all in this one file. The bulk is the
guide's house style of contractions. The rest is adverbs that carried no
weight, two sentences opening with 'So', and three quotations of literal text
-- a runtime message, a device dialog, Google Play's policy -- where moving the
period inside the quotes would misquote the source, so those carry a vale-skip
naming the reason.

Where an adverb was load-bearing, the sentence says the thing instead: 'which
silently dropped Runnable' is now 'which dropped Runnable with no diagnostic'.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7a54e8f350

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Ports/iOSPort/src/com/codename1/impl/ios/InterpIOSSymbols.java Outdated
Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java Outdated
Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java Outdated
Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java
The rebase reconstruction rewrote the file with LF where master has CRLF, so a
63-line change showed up as a 14,000-line rewrite. That is not only noise:
CodeQL reports alerts for code a PR changed, and a whole-file diff re-reported
twelve alerts that master already has and this branch did not introduce.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f86bfb26ac

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/cn1-push.sh Outdated
Comment thread scripts/cn1-push.sh Outdated
Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java
The chapter used British spellings in a US-English guide -- which the
cross-document coherency rule catches, not just the dictionary -- and a
vocabulary LanguageTool has never heard of. Spellings are now US; the
vocabulary (vtable, clazz, dex, desugar, devirtualize, supertype, cmake,
thebaselab) is in the accept list with a line saying what each one is.

Two sentences were rephrased rather than allowlisted: LanguageTool reads
'An interpreted X has to be an object...' as a typo for 'and' once the code
spans are stripped, and the rule is right that the sentence was hard to parse.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 79950c65f5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java
Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java
Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java
@shai-almog

shai-almog commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 217 screenshots: 217 matched.
✅ Native Apple Watch (watchOS, Core Graphics) screenshot tests passed.

@shai-almog

shai-almog commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator Author

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

Benchmark Results

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

Build and Run Timing

Metric Duration
Simulator Boot 87000 ms
Simulator Boot (Run) 1000 ms
App Install 14000 ms
App Launch 22000 ms
Test Execution 409000 ms

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 94ms / native 5ms = 18.8x speedup
SIMD float-mul (64K x300) java 129ms / native 8ms = 16.1x 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 235.000 ms
Base64 CN1 decode 110.000 ms
Base64 native encode 904.000 ms
Base64 encode ratio (CN1/native) 0.260x (74.0% faster)
Base64 native decode 397.000 ms
Base64 decode ratio (CN1/native) 0.277x (72.3% faster)
Base64 SIMD encode 64.000 ms
Base64 encode ratio (SIMD/CN1) 0.272x (72.8% faster)
Base64 SIMD decode 54.000 ms
Base64 decode ratio (SIMD/CN1) 0.491x (50.9% faster)
Base64 encode ratio (SIMD/native) 0.071x (92.9% faster)
Base64 decode ratio (SIMD/native) 0.136x (86.4% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 11.000 ms
Image createMask (SIMD on) 5.000 ms
Image createMask ratio (SIMD on/off) 0.455x (54.5% faster)
Image applyMask (SIMD off) 63.000 ms
Image applyMask (SIMD on) 39.000 ms
Image applyMask ratio (SIMD on/off) 0.619x (38.1% faster)
Image modifyAlpha (SIMD off) 179.000 ms
Image modifyAlpha (SIMD on) 236.000 ms
Image modifyAlpha ratio (SIMD on/off) 1.318x (31.8% slower)
Image modifyAlpha removeColor (SIMD off) 109.000 ms
Image modifyAlpha removeColor (SIMD on) 196.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 1.798x (79.8% slower)

Seven findings, four of which had been sitting unseen behind a paginated
query that only ever read the first hundred threads.

- The subnet sweep closed every stream when its batch deadline passed,
  including the one that had answered and was waiting for a human to type a
  pairing code. Each connection now carries whether it read the magic; the
  batch waits for those and closes only the silent ones. This is the only way
  in on iOS, where the device cannot listen.
- Class.desiredAssertionStatus() is answered (false, as the device answers
  it). Without it any pushed class containing an `assert` died in <clinit>.
- Time spent inside a host call no longer counts against the EDT budget. The
  check was suppressed for the duration but the entry clock kept running, so
  the first loop after invokeAndBlock or a network read was cancelled for
  time the host had spent.
- An enum that overrides toString now uses the override when host code
  prints it, instead of the constant name.
- A class token is exchanged for a host Class only where the parameter says
  Class. Substituting into an Object parameter stored Object.class, so a
  literal put in a collection no longer equalled itself on the way out.
- Cloning a host reference array keeps its type on iOS: a new native
  allocates from the source array's own clazz, so String[].clone() is still
  a String[] rather than an Object[] that fails the next cast.
- altMetafactory's marker interfaces and bridge signatures are read rather
  than dropped, so an intersection cast such as (A & B) () -> "x" gets a
  class that carries A and a body for A's erasure of the method.

Covered by four differential conformance cases and an EDT-budget test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 44b22f993c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java
Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java
Comment thread Ports/Android/src/com/codename1/impl/android/InterpAndroidLinker.java Outdated
- A host static reached through a *pushed* interface was reported missing.
  `class C implements I` where `I extends HostIface` records the read as
  `C.FIELD`, and the owner walk followed only the superclass chain, so
  HostIface was never among the candidates and a constant that plainly
  exists came back as NoSuchFieldError. The walk now follows interpreted
  interfaces too, bounded by a visited set rather than a depth.
- A reentrant callback no longer leaves its clock behind. A host call that
  dispatches an event into the interpreter is a fresh entry with its own
  budget, and the outer entry's start time was simply overwritten -- so the
  outer one silently got a new budget on every dialog event, and yesterday's
  host-call exclusion was then added to a timestamp belonging to nobody. It
  is saved and restored alongside hostCallDepth, which is the same lifetime.
- The Android linker's interface-initialization walk uses a visited set
  instead of a 16-edge cap. The walk has to terminate because a diamond
  visits an interface twice, not because a hierarchy is deep; the cap
  silently skipped a legal ancestor and left its default methods
  uninitialized.

HostFieldProbe now also reads a host interface's static through a pushed
interface, which is the shape the first item describes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c448acccbe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Ports/iOSPort/src/com/codename1/impl/ios/InterpIOSLinker.java
Comment thread Ports/iOSPort/src/com/codename1/impl/ios/InterpIOSLinker.java Outdated
- altMetafactory's serializable flag is honoured. `(Runnable & Serializable)
  () -> {}` sets it and names no marker at all, so the synthesized class
  carried Runnable alone and an ordinary intersection cast had nothing to
  land on. The interface is added; writeReplace is not, so such a lambda is
  Serializable and would fail to serialize -- which is what it does on the
  device regardless.
- iOS initializes default-bearing host interfaces instead of doing nothing.
  The class row gained an eighth column saying whether an interface declares
  a default method, which is the one thing the symbol table could not
  otherwise answer, and the linker walks the interface graph with a visited
  set and initializes those, superinterfaces first.
- The iOS superclass walk lost its 32-entry array. What a fixed bound
  truncated were the ancestors nearest Object -- the ones most likely to
  carry a static block somebody depends on.
- The dial and sweep callbacks publish through volatile holders rather than
  one-element arrays. The callback runs on its own thread and the dialer only
  polls, so nothing required the poll to observe the write: it could time out
  and close a working exchange, or report a finished push as a failure.
- `started` is set once the frame is identified -- magic, version and, on v3,
  frame type -- not at the magic. Four bytes are cheap to send, and a peer
  that sent them and stalled was waited on forever and exempted from the
  cleanup, which is all it took to stop discovery for good.

ParserTest covers the new column both ways; the intersection-lambda
conformance case now also asserts `instanceof Serializable`, which is the
half a permissive checkcast let through.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6508109036

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java Outdated
`super.play()` on a *final* host method is ordinary Java, and it failed: the
interpreter always looked for a `super_play` bridge, and the shim generator
skips final methods because it can neither override nor bridge them. The
linker gained `hasMethod`, so the interpreter asks first and calls the method
itself when there is no bridge -- which is what the super call means when
nothing overrides it, and cannot recurse.

While in the same files, the two remaining 64-iteration guards in the iOS
symbol table (method lookup and field lookup) became visited sets. The walk
ends because a superclass chain does; a count would stop partway up a deep
hierarchy and report a method the app has as missing.

InterpHostSubclassTest gained a final method on its stand-in framework class
-- deliberately without a bridge, exactly as the generator would leave it --
and a test calling it through `super.`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 20180dabaf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java Outdated
- Stopping a program could raise AbstractMethodError. A stopped program's
  peers stay alive -- a timer, a network response, a listener the framework
  holds -- and the runtime answered a late callback with NOT_OVERRIDDEN,
  which a generated interface shim reads as "the class failed to implement
  this" and throws on. dispatch() now answers DETACHED, a sentinel of its
  own: a shim with something to defer to calls it, and one without quietly
  answers nothing rather than failing the event thread.
- Interface shims now emit a super_ bridge for each default method, so
  `HostInterface.super.method()` from a pushed override reaches the default.
  Without it the fallback called the method itself, and a reflective
  invoke dispatches virtually -- back into the shim's override, back into the
  interpreter, until the stack gave out.

scripts/generate-interp-shims.sh passes: 1110 shims, all compiling, and
generating twice is identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0af4958b57

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread vm/ByteCodeTranslator/src/com/codename1/tools/translator/DevicePush.java Outdated
The entry-point search stopped after 64 superclass edges, so a project whose
application class sits deeper was told it had no entry point -- and because
depthOf() capped at the same number, two deeper candidates tied and which one
won depended on HashMap iteration order. Both walks are bounded by what they
have already seen, a chain being acyclic, and a genuine tie is broken by name
so the same tree pushed twice enters the same class. scripts/cn1-push.sh
carries the same code and got the same fix.

DevicePushEntryPointTest covers all three: an 81-deep hierarchy, the deepest
concrete descendant winning over its own base class, and a tie answering the
same way whichever order the files arrive in.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c260b3a57c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/impl/interp/InterpObject.java
- Installing a bundle is serialized. Every accepted connection is served on a
  thread of its own and the dialer is a third, and installing is several
  steps -- clearing and republishing resources, applying a theme, detaching
  the old runtime, publishing the new one. Interleaved, a program could start
  with the other push's resources, or be detached as it started while its
  push reported success. The lock is held only by threads serving a push:
  installing waits on the event thread, so an event thread that could block
  on it would deadlock, which is why stopping does not take it.
- A peerless interpreted object survives its program being stopped. Its
  toString/equals/hashCode ask the interpreter like a shim does, and after
  yesterday's DETACHED sentinel they cast it to the return type -- so logging
  an object a host collection still held threw ClassCastException. Both
  sentinels now mean "use the default behaviour".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 48fe18a102

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java
- A checked exception an interpreted override declares now reaches its own
  catch clause. The interpreter cannot throw one through its own signature so
  it wraps it, and the shim -- which declares exactly what the framework
  method declares -- now unwraps it again: one instanceof-guarded rethrow per
  declared type, anything else travelling on as it was. Before this, an
  interpreted Row.getString() that threw IOException reached the caller as an
  unexpected runtime exception.
- Recording a pairing is serialized. Each connection is served on its own
  thread and the index is one shared key, so two computers pairing at once
  could leave the later write without the earlier peer -- and "forget all
  paired computers" then never found it, leaving a revoked computer with its
  secret and its Always approval intact.

Covered by InterpHostSubclassTest.checkedExceptionsSurviveTheShimBoundary,
whose hand-written shim mirrors what the generator now emits; the generator
gate passes with 1110 shims compiling and generating identically twice.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dff7808513

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

A pushed subclass of a declared exception was not caught as one. It arrives
as an InterpObject whose peer is the host exception -- the peer being the
object host code was handed, and the only one a catch clause can match -- so
a shim inspecting the InterpObject matched nothing and rethrew the
interpreter's carrier past a catch for the very type the method declares.

InterpThrowable gained hostThrowable(), which answers the peer when there is
one, and the generated rethrow asks for that instead of getThrown().

InterpHostSubclassTest gained a framework exception class to subclass, its
shim, and a test pushing `class Mine extends HostFailure` and catching it as
IOException.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a26a610a52

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java Outdated
Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java
- An initializer that failed with a pushed exception class produced an
  ExceptionInInitializerError with no cause, which is the only thing that
  wrapper carries. The interpreted object is not itself a Throwable but its
  peer is, so the peer is now the cause. The unwrapping is shared with the
  shim rethrow rather than written twice.
- Class.isAssignableFrom answers for pushed tokens. It is the other type test
  Java offers without reflection, the hierarchy was already here, and asking
  raised UnsupportedOperationException. Arrays follow their components; a host
  class is never a subtype of one only the bundle has, so anything that is not
  an interpreted token answers false.

The ClassAssignability conformance case checks all of it differentially
against the JVM; initializerFailuresCarryTheirCause pushes a subclass of an
unchecked framework exception, added to the test's stand-in framework for it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1b5ab70c18

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java
Comment thread vm/ByteCodeTranslator/src/com/codename1/tools/translator/DevicePush.java Outdated
- `Runnable.class.isAssignableFrom(Task.class)` answers truthfully for a
  pushed class implementing a host interface. The token was being exchanged
  for its nearest host ancestor before the host saw the call, so the host was
  asked about Object; the interpreted class's host supertypes are now offered
  to the receiver instead.
- Pairing prompts are serialized and paused between. Nothing has
  authenticated when a pair frame arrives -- that is what pairing is for --
  so on a listening runtime anything on the network could stack modal dialogs
  until the app was unusable. One prompt at a time, a three second pause
  after each, and a refused frame answers with a reason rather than silence.
- Choosing between several `main(String[])` is deterministic. listFiles() has
  no defined order, so a tree with a diagnostic launcher beside its
  application could push one program today and the other tomorrow from the
  same sources. Sorted, and it says when there was a choice. cn1-push.sh
  carries the same finder and got the same fix.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f88e517e1d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java
An interpreted array token records only its component, so the supertype walk
found nothing for one and `Object.class.isAssignableFrom(Base[].class)` --
along with Cloneable and Serializable -- answered false for something every
Java array is. Array tokens now offer the three universal array supertypes,
and the covariant ones: `Base[]` is an `S[]` for every host supertype S of
Base, at whatever rank the token has.

The ClassAssignability conformance case covers all five, including the
negative (`Runnable.class.isAssignableFrom(Base[].class)`).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fcf6635b62

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java Outdated
Comment thread vm/ByteCodeTranslator/src/com/codename1/tools/translator/DevicePush.java Outdated
- A private method is not virtual, and the opcode no longer says so: from JDK
  11 javac emits invokevirtual for one, nestmates having replaced the
  synthetic bridges. Resolving from the receiver made Base.value() calling
  its own private label() land on a label() that Child happened to declare --
  a different answer, silently. The owner named by the bytecode is consulted
  first, and private methods are no longer copied into a subclass's vtable,
  since Java does not inherit them either.
- A push pins the device its scan found. A push is up to three exchanges --
  try, pair, try again -- each its own connection, and scanning again each
  time picks whoever answers first: with two runtimes on the network, the
  user pairs one phone and the push then goes to the other, which correctly
  reports that it is not paired.
- The two comments I added yesterday in core were classic Javadoc, which
  build-test (17) rejects there. Converted to /// markdown.

PrivateNotVirtual covers the dispatch differentially against the JVM,
including that Child's own private method still wins inside Child.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: da7dfea9c0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java Outdated
Comment thread CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java Outdated
- Package access decides overriding too, not only private. JVMS 5.4.5: a
  package-private method is overridden only from inside its own package, so a
  public method of the same signature in another package is a different method
  that happens to share a name -- and dispatch that followed the receiver ran
  it, silently changing what a library class does when a program subclasses it
  from elsewhere. Virtual resolution now takes the most derived override that
  is in the declaring class's package.
- getSimpleName no longer splits on the last `$`. javac names a local class
  Outer$1Local and an anonymous one Outer$1, whose simple names are "Local"
  and "", and a top-level class may carry a `$` in its own name, where nothing
  should be stripped. The bundle has no InnerClasses attribute, so the
  enclosing name is looked up in it instead: a prefix that is itself a class
  here means this one is nested in it.

packagePrivateMethodsAreNotOverriddenAcrossPackages builds a two-package
fixture; the SimpleNames conformance case covers member, local, anonymous and
array names against the JVM.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d817420b07

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +394 to +395
st.depth++;
if (st.depth > maxDepth) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Charge method entries against the fuel counter

When recursive interpreted code catches the synthetic StackOverflowError and recurses again, execution can continue indefinitely without taking a bytecode back edge. execute() increments only depth; the sole fuel decrement is the next <= insn check in run(), despite the runtime contract promising a checkpoint on method entry. Such code can monopolize the EDT and ignore Stop because cancelRequested is never examined. Decrement/check fuel at each interpreted method entry as well as at back edges.

Useful? React with 👍 / 👎.

Comment on lines +1295 to +1296
if (!m.isStatic() && !m.isAbstract() && !"<clinit>".equals(m.name)) {
return true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude private methods from default-method detection

When JDK 17 pushed sources declare an interface with a private instance helper and a static initializer but no default method, this predicate still marks the helper as a default. Initializing any implementing class therefore initializes that interface early, exposing initializer side effects in an order Java does not permit. A default method must also be non-private, so include !m.isPrivate() in this test.

Useful? React with 👍 / 👎.

Comment on lines +2061 to +2068
int dollar = internalName.lastIndexOf('$');
if (dollar < 0 || dollar < slash) {
return simple;
}
if (bundle.findClass(internalName.substring(0, dollar)) == null) {
// Not a nested class of anything the bundle has: the `$` belongs to
// the class's own name.
return simple;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve dollar signs in nested-class simple names

Fresh evidence after the enclosing-prefix fix is that $ is also legal inside a nested class's own identifier. For class Outer { class Inner$Part {} }, the internal name is Outer$Inner$Part; the last-dollar prefix Outer$Inner is not a class, so this branch returns Outer$Inner$Part, whereas getSimpleName() must return Inner$Part (and if an Outer$Inner class also exists, it instead returns Part). The heuristic still cannot identify the enclosing-name boundary; retain the InnerClasses metadata rather than inferring it from the last $.

Useful? React with 👍 / 👎.

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