Device runtime: run pushed Codename One apps on a phone - #5561
Device runtime: run pushed Codename One apps on a phone#5561shai-almog wants to merge 71 commits into
Conversation
ddc43de to
7623680
Compare
There was a problem hiding this comment.
💡 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".
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>
7623680 to
c6c6ada
Compare
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>
💡 Codex ReviewOn every Android launch this support check is false because no code installs the newly added 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 For an already-paired LAN push, If any unrelated service happens to accept this port during the subnet sweep, the callback marks it as found before ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
✅ Continuous Quality ReportTest & Coverage
Static Analysis
Generated automatically by the PR CI workflow. |
There was a problem hiding this comment.
💡 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".
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>
💡 Codex ReviewWhen 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. CodenameOne/CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java Lines 1347 to 1350 in 7e92c49 For a peerless interpreted object, calls inherited from When compiled output contains Kotlin classes, even explicitly passing a Kotlin source directory to Entry-point discovery recognizes only classes whose immediate superclass is ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
There was a problem hiding this comment.
💡 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".
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>
There was a problem hiding this comment.
💡 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".
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>
There was a problem hiding this comment.
💡 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".
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>
💡 Codex ReviewCodenameOne/Ports/Android/src/com/codename1/impl/android/AndroidImplementation.java Lines 1565 to 1567 in 3155e0b On every Android runtime build, CodenameOne/CodenameOne/src/com/codename1/impl/interp/InterpRuntime.java Lines 677 to 679 in 3155e0b When the leaf type is interpreted, allocating every reference array as a plain ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
|
Compared 12 screenshots: 12 matched. |
|
Developer Guide build artifacts are available for download from this workflow run:
Developer Guide quality checks: |
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>
There was a problem hiding this comment.
💡 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".
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>
There was a problem hiding this comment.
💡 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".
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>
There was a problem hiding this comment.
💡 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".
- The bundle body is read with a heartbeat instead of an unbounded wait. Nothing has authenticated at that point -- the response covers the bundle, so it cannot be checked until the bytes are here -- and a peer that declared a plausible length and then stopped sending held the dial and the sweep for good. Each chunk restarts the grace, so a slow link finishes and a stalled one is closed. Only a human typing a pairing code still waits without limit. - A generated peer rethrows an unchecked exception as itself. A pushed `MyIllegalArgumentException extends IllegalArgumentException` has a peer that *is* one, and letting the interpreter's carrier escape meant the framework's own `catch (IllegalArgumentException)` never ran. - A relative resource name resolves against the caller's package, as Java does. `getResourceAsStream(MyApp.class, "data.json")` reads /com/example/data.json, which is the path the bundle stores it under; the class token is exchanged for a host ancestor on the way to the host, so the name is qualified while the package is still known. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4dc4c126e9
ℹ️ 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".
- The approval prompt waits without a clock again. Everything before it is bounded because anything on the network can reach it; by the time the person is asked, the peer has proved it holds the secret and the bundle matched, so closing the connection under them would run the program while telling the desktop the push failed. The wait goes back to bounded as soon as the dialog closes. - A stop that lands between the guard and publishing the runtime now rolls back: the runtime is detached, the program forgotten, and the resources and theme put back the way a stop leaves them. Throwing without that left a stopped program reported as loaded with its callbacks live. - The Lifecycle is recorded before init rather than after start. init is already far enough in to have opened a listener or a sensor, and an init that threw had nothing to release it -- the failure path called stop() and found no lifecycle to call it on. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 55d839617a
ℹ️ 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".
- An accepted connection is now under a deadline of its own. The dial and the sweep watch theirs; an accepted one had nothing behind it, and the framework gives every accepted connection a thread -- so a peer that connects and sends nothing parked one forever, and enough of them would take the app's threads and sockets without authenticating anything. A watchdog closes the silent ones, which is what ends the read they are parked in, and stops itself when there is nothing left to watch. - An interpreted method returning an array has its elements exchanged for their peers, as an argument's already were. Host code casting an element to the interface it implements was getting the interpreter's wrapper. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e7c764cf44
ℹ️ 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".
An authenticated push stays open-ended through installation and startup. The wait was going back to bounded the moment the approval dialog closed, but the desktop is waiting for the result on that same connection while the bundle is installed and the entry point runs -- so a program that took more than ten seconds to start had its stream closed under it and was reported as a failed push while running. Nothing unauthenticated reaches that point: a v3 push answered the challenge over the bundle and was approved, and v1 is loopback only. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0ceb1cedd1
ℹ️ 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".
Waiting for another thread's class initializer is uninterruptible, as JVMS 5.5 requires. An interrupt was escaping as a checked exception from whatever instruction triggered the initialization -- a getstatic, a new -- which is not something those can report. The interrupt is remembered and reasserted instead, so the program still sees it at its next interruptible point. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7b57afd8bc
ℹ️ 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".
- The fuel counter is restored across a reentrant callback, as the entry clock already was. A loop whose body dispatches a listener reset it on every iteration, so no back edge ever reached a checkpoint and Stop had nothing to act on -- which is the one thing the counter exists for. - A package declaration is parsed rather than pattern-matched against line starts. `/* license */ package com.example;` is one ordinary line, and reading it as the default package stored the source under a key the runtime never looks up, so the push was refused for missing source that had been supplied. Comments and literals are blanked and the scan works in tokens. thePackageIsParsedRatherThanPatternMatched covers the shapes, including a package declaration that is only inside a comment. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8aaddf6310
ℹ️ 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".
- The push tool drops its read deadline once the bundle is away. Past that point the device may be waiting for a person to approve the push and then installing and starting the program, and a 120-second socket timeout there reported a failed push for a program that was running. Discovery and authentication keep their deadlines. - The package scan decodes `\uXXXX` first, as javac does. `package com.example;` is a package declaration -- odd, legal, and invisible to a scanner reading raw text -- and only an odd run of backslashes escapes. - Failure diagnostics are published as one record. Three separate volatile fields could be read half-updated, pairing one thread's throwable with another's frames, which is a confidently wrong stack rather than a missing one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
# Conflicts: # docs/developer-guide/languagetool-accept.txt
master added com.codename1.home -- HomeKit on iOS, Matter and Google Home on Android -- and the shim set follows the framework mechanically, so it is already covered: 1115 shims rather than 1110, all compiling. The package is also declared as a native capability, so the runtime app links the SDKs behind it: debugging an accessory is exactly what a simulator cannot do, and reporting it unsupported on a device that has it is the one place it matters. Also moves a cast out of a try whose catch is Throwable, which the cast-semantics gate rightly refused. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
A //NOPMD on its own line suppresses nothing -- it has to sit on the line it excuses, which is where the two sentinel comparisons in InterpObject now carry it. The fuel decrement moved out of its condition, and the array scan became a foreach. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
UIManagerLargeTextScaleTest arrived from master without one. It only shows up now because merging master makes it a new file in this branch's diff, and the gate is right either way: every source file carries the header. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: db976bdc2b
ℹ️ 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".
Three iOS-side deviations from what the symbol sidecar and JLS 5.4.3.3 promise about pushed programs. Every host class advertises rank 1--3 array ids in the sidecar so a pushed `new HostType[1]` or `HostType[].class` has an id to resolve to, but the id-to-clazz registration only ran when the closed world already happened to use that rank as an array. The lookup returned a valid id whose registry entry was absent; `newObjectArray` silently fell back to `Object[]` and broke casts, class literals and host calls expecting the array type. Interp-host builds now seed `arrayTypes` for every host class before emission so `getArrayClazz`, the array struct loop, the extern block, the array vtable initializer and the registration all match the advertised rows. InterpIOSLinker's `initializeClass` walked the host superclass chain top down but never asked each class for its default-bearing superinterfaces before running its initializer, and the separate runtime interface walk only covers interfaces the interpreted subclass declares directly. An interface inherited through a host superclass could therefore initialize after its implementor, reversing the order JLS 12.4.1 requires. The walk now calls `initializeDefaultBearing` for each host class id before `initializeClassById`, with one visited set shared across the chain so a diamond is not initialized twice. InterpIOSSymbols' `methodId` searched each class's interfaces before moving to the superclass, so an interface default could be picked over a concrete method the superclass inherited. Java gives class methods precedence, per JLS 5.4.3.3. The resolution is now two passes: first the whole superclass chain for a class method, then the interfaces of every class in the chain, with one visited set spanning the DAG so a shared interface is walked once. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 44475d20e6
ℹ️ 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".
Two follow-ups on the iOS resolution path. Interface method lookup returned the first depth-first match, so for a class declaring `implements I, J` where `J extends I` and both define the method, the superinterface `I`'s default was picked over `J`'s override. JLS 5.4.3.3 says pick the maximally specific one. The lookup now collects every candidate interface, filters to those no other candidate's declaring interface subtypes, and returns one of them -- deterministically the first found when several are maximally specific and JLS leaves the tie arbitrary. Constructor resolution routed through the generic `<init>` lookup, which walks the superclass chain. A subclass whose exact constructor descriptor is absent -- an SDK newer than the installed runtime, or a subclass that declares only some parent constructors -- silently matched the superclass thunk, which allocates and returns a base instance. `construct` now goes through a new `declaredMethodId` that does no walk, so `new Sub(args)` fails with a NoSuchMethodError instead of handing back a `Base`. The marshalling half of `invoke` is factored out so this path dispatches with the resolved id directly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ee4b55ace8
ℹ️ 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".
Two follow-ups from the previous round. Maximally-specific interface selection ran per class. A receiver declaring `implements I` whose superclass declares `implements J extends I` returned I.m immediately at the receiver level and never saw J's more specific override -- because the filter only considered one class's interface graph at a time. The interface pass now pools candidates from every class in the chain first and picks the maximally-specific one across the whole set, with the visited hashtable shared so a diamond is still walked once. `__STATIC_INITIALIZER_` registration excluded interfaces, so the default-bearing walk added last round called `initializeClassById` on an unregistered slot for every host interface and did nothing. A host default-bearing interface with a nonconstant static initializer stayed uninitialized until one of its methods was entered -- which may never happen and is always after the implementor's constructor, reversing JLS 12.4.1. The registration now runs for interfaces too; `__STATIC_INITIALIZER_` is already emitted for them and is idempotent, so it costs one row per interface. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f221aa6e93
ℹ️ 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".
| Integer id = (Integer)methodIds.get(ifaceName + "." + name + descriptor); | ||
| if (id != null) { | ||
| candidateOwners.addElement(ifaceName); | ||
| candidateIds.addElement(id); |
There was a problem hiding this comment.
Exclude static methods from interface dispatch candidates
On iOS, when a host class implements unrelated interfaces A and B, where A declares a static m() and B declares a default instance m() with the same descriptor, an interpreted call through B can execute A.m() if A is visited first. Fresh evidence beyond the maximally-specific-interface fix is that method symbol rows carry no access flags and this collection admits every registered interface thunk, including static and private methods that are not inherited; retain method-kind metadata and collect only eligible instance methods.
Useful? React with 👍 / 👎.
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
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/Ports/{Android,iOSPort}vm/ByteCodeTranslatorDevicePushtoolscripts/cn1-device-runtime/scripts/devruntime-ide-project/scripts/devruntime-probes/docs/developer-guide/Device-Runtime.asciidocDecisions 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 theclass 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 theruntime'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.
InterpHostVtableSynthesisIntegrationTeststays for the day that changes.
synchronizeduses the real object monitor, not a private lock table, whichis what makes
wait/notifywork.Framework fixes that fell out
AndroidImplementation.getHostOrIP()returneddummy0's IPv6 link-localinstead of a usable IPv4 — affects any caller.
CodenameOneImplementation.getResourceAsStreamgained a local-resource hook,so a pushed program's
theme.resis found byResources.openLayered, whichnever 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
Lifecyclerather thanmain.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:
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.
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.ymlruns 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/) sosupplyanddeliverconsume it directly, withstore/privacy.mdfor bothstores' data forms and
store/README.mdfor the secrets, the pre-submissionchecklist 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
NativeLookupstubbing covers the Java half of a cn1lib; the native halfreports 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