Skip to content

Fix iOS native stub -stop selector ambiguity on Xcode 26#5052

Merged
shai-almog merged 1 commit into
masterfrom
fix/native-stub-stop-selector-collision
May 28, 2026
Merged

Fix iOS native stub -stop selector ambiguity on Xcode 26#5052
shai-almog merged 1 commit into
masterfrom
fix/native-stub-stop-selector-collision

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

Summary

  • Cast ptr to the lib's concrete peer class in the generated [ptr methodName...] message send, so clang resolves the selector against the lib's own @interface instead of against id.
  • Fixes Xcode 26 / iOS 26 SDK builds of any cn1lib whose native interface declares a method whose name collides with a - (void)… selector exposed by AVFoundation / Foundation (e.g. stop, play, pause, start, …).

Why

The generated stub native_<class>ImplCodenameOne.m messages the native peer through an id-typed pointer:

id ptr = (id)get_field_..._nativePeer(me);
JAVA_BOOLEAN returnValue = [ptr stop];

On the iOS 26 SDK, AVFoundation pulls in many classes with - (void)stopAVAudioEngine, AVAudioPlayer, AVAudioPlayerNode, AVAudioRecorder, AVAudioSequencer, AVMIDIPlayer, AVCaptureExternalDisplayConfigurator, NSNetServices, … Clang in Xcode 26 picks one of those void declarations when resolving the selector against id, and the build fails with:

error: initializing 'JAVA_BOOLEAN' (aka 'int') with an expression of incompatible type 'void'
  104 |     JAVA_BOOLEAN returnValue = [ptr stop];

(Reported in the wild against CN1Webserver, which has -(BOOL)stop. Hiding GCDWebServer.h in shannah/CN1Webserver#1 removed one source of collision but could not prevent AVFoundation — that header arrives transitively via CodenameOne_GLViewController.h, so the same error reappears against AVFoundation's -stop overloads.)

Approach

The stub already #imports <classNameWithUnderscores>Impl.h, which declares @interface <classNameWithUnderscores>Impl (a convention every cn1lib follows — verified across core tests, TestNativeInterfaces, parse4cn1, firebase-cn1, etc.). Casting ptr at the message send gives clang a known receiver type so the selector resolves against the lib's @interface, not against the global id pool.

Runtime dispatch is unchanged — Objective-C method lookup is dynamic, the cast is a compile-time hint only. No cn1lib needs to be rebuilt once the new builder is deployed.

Test plan

  • iOS release build of a CN1Webserver-using app on Xcode 26.x succeeds.
  • iOS builds of existing cn1libs (parse4cn1, firebase, googleplay, etc.) still succeed.
  • start, stop, isRunning, etc. continue to function at runtime.

🤖 Generated with Claude Code

The generated stub native_<class>ImplCodenameOne.m messages the native
peer through an `id`-typed pointer:

    id ptr = (id)get_field_..._nativePeer(me);
    JAVA_BOOLEAN returnValue = [ptr stop];

On the iOS 26 SDK, AVFoundation pulls in many classes with
`- (void)stop` (AVAudioEngine, AVAudioPlayer, AVAudioPlayerNode,
AVAudioRecorder, AVAudioSequencer, AVMIDIPlayer,
AVCaptureExternalDisplayConfigurator, NSNetServices, ...). Clang in
Xcode 26 picks one of those `void` declarations when resolving the
selector against `id`, and the build fails with:

    error: initializing 'JAVA_BOOLEAN' (aka 'int') with an expression
    of incompatible type 'void'

Hiding GCDWebServer.h (CN1Webserver PR #1) removed one source of
collision but cannot prevent AVFoundation -- that header is imported
transitively via CodenameOne_GLViewController.h, so the same crash
reappears.

Cast `ptr` to the lib's concrete peer class at the message send so
clang resolves the selector against the @interface in the lib's own
header (which is already #imported by the stub). Runtime dispatch is
unchanged (ObjC is dynamic), so no cn1lib needs rebuilding.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 27, 2026

Compared 47 screenshots: 47 matched.
✅ JavaScript-port screenshot tests passed.

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 27, 2026

Compared 116 screenshots: 116 matched.

Native Android coverage

  • 📊 Line coverage: 12.36% (7160/57934 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 10.09% (36025/357185), branch 4.24% (1436/33832), complexity 5.27% (1712/32478), method 9.21% (1400/15204), class 15.04% (318/2114)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 12.36% (7160/57934 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 10.09% (36025/357185), branch 4.24% (1436/33832), complexity 5.27% (1712/32478), method 9.21% (1400/15204), class 15.04% (318/2114)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 821.000 ms
Base64 CN1 encode 129.000 ms
Base64 encode ratio (CN1/native) 0.157x (84.3% faster)
Base64 native decode 746.000 ms
Base64 CN1 decode 231.000 ms
Base64 decode ratio (CN1/native) 0.310x (69.0% faster)
Image encode benchmark status skipped (SIMD unsupported)

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 27, 2026

Compared 116 screenshots: 116 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

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

Build and Run Timing

Metric Duration
Simulator Boot 64000 ms
Simulator Boot (Run) 0 ms
App Install 12000 ms
App Launch 5000 ms
Test Execution 319000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 785.000 ms
Base64 CN1 encode 1571.000 ms
Base64 encode ratio (CN1/native) 2.001x (100.1% slower)
Base64 native decode 497.000 ms
Base64 CN1 decode 1337.000 ms
Base64 decode ratio (CN1/native) 2.690x (169.0% slower)
Base64 SIMD encode 596.000 ms
Base64 encode ratio (SIMD/native) 0.759x (24.1% faster)
Base64 encode ratio (SIMD/CN1) 0.379x (62.1% faster)
Base64 SIMD decode 803.000 ms
Base64 decode ratio (SIMD/native) 1.616x (61.6% slower)
Base64 decode ratio (SIMD/CN1) 0.601x (39.9% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 61.000 ms
Image createMask (SIMD on) 10.000 ms
Image createMask ratio (SIMD on/off) 0.164x (83.6% faster)
Image applyMask (SIMD off) 140.000 ms
Image applyMask (SIMD on) 97.000 ms
Image applyMask ratio (SIMD on/off) 0.693x (30.7% faster)
Image modifyAlpha (SIMD off) 114.000 ms
Image modifyAlpha (SIMD on) 121.000 ms
Image modifyAlpha ratio (SIMD on/off) 1.061x (6.1% slower)
Image modifyAlpha removeColor (SIMD off) 336.000 ms
Image modifyAlpha removeColor (SIMD on) 146.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.435x (56.5% faster)
Image PNG encode (SIMD off) 1325.000 ms
Image PNG encode (SIMD on) 951.000 ms
Image PNG encode ratio (SIMD on/off) 0.718x (28.2% faster)
Image JPEG encode 519.000 ms

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 27, 2026

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

Benchmark Results

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

Build and Run Timing

Metric Duration
Simulator Boot 94000 ms
Simulator Boot (Run) 1000 ms
App Install 35000 ms
App Launch 8000 ms
Test Execution 317000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 1088.000 ms
Base64 CN1 encode 1904.000 ms
Base64 encode ratio (CN1/native) 1.750x (75.0% slower)
Base64 native decode 431.000 ms
Base64 CN1 decode 1284.000 ms
Base64 decode ratio (CN1/native) 2.979x (197.9% slower)
Base64 SIMD encode 811.000 ms
Base64 encode ratio (SIMD/native) 0.745x (25.5% faster)
Base64 encode ratio (SIMD/CN1) 0.426x (57.4% faster)
Base64 SIMD decode 717.000 ms
Base64 decode ratio (SIMD/native) 1.664x (66.4% slower)
Base64 decode ratio (SIMD/CN1) 0.558x (44.2% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 77.000 ms
Image createMask (SIMD on) 19.000 ms
Image createMask ratio (SIMD on/off) 0.247x (75.3% faster)
Image applyMask (SIMD off) 314.000 ms
Image applyMask (SIMD on) 180.000 ms
Image applyMask ratio (SIMD on/off) 0.573x (42.7% faster)
Image modifyAlpha (SIMD off) 216.000 ms
Image modifyAlpha (SIMD on) 54.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.250x (75.0% faster)
Image modifyAlpha removeColor (SIMD off) 306.000 ms
Image modifyAlpha removeColor (SIMD on) 249.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.814x (18.6% faster)
Image PNG encode (SIMD off) 1917.000 ms
Image PNG encode (SIMD on) 1265.000 ms
Image PNG encode ratio (SIMD on/off) 0.660x (34.0% faster)
Image JPEG encode 773.000 ms

@shai-almog shai-almog merged commit c75f751 into master May 28, 2026
26 checks passed
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.

1 participant