Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
fbedbc5
Add iOS on-device debugging support
shai-almog May 21, 2026
56b9c02
Address review feedback on on-device debugging
shai-almog May 21, 2026
f40ead0
Merge remote-tracking branch 'origin/master' into on-device-debug-ios
shai-almog May 21, 2026
0683cc0
Avoid proselint Diacritical false positive on 'Resume'
shai-almog May 21, 2026
54fc1e8
On-device debug UX: waiting overlay, non-blocking start, JDWP reattach
shai-almog May 22, 2026
7e8c0b8
On-device-debug: object inspection + native stdout + CN1-core BP docs
shai-almog May 22, 2026
08a9a8d
Fix EventRequest.Set walking past payload + IntelliJ console docs
shai-almog May 22, 2026
36531d1
On-device debug: method invocation (Class/ObjectReference InvokeMethod)
shai-almog May 22, 2026
0a018f4
Proxy: --trace-jdwp flag for diagnosing IDE-specific step / invoke is…
shai-almog May 22, 2026
23fa131
Proxy: fix off-by-one in JDWP EventRequest modifier-kind numbering
shai-almog May 22, 2026
0d6772c
Proxy: invalidate stack / locals cache on suspend & resume events
shai-almog May 22, 2026
4fcb521
Array inspection: ArrayReference.Length / GetValues + array type tag
shai-almog May 22, 2026
9b84847
Docs: reflect array + invoke-method support, fix vale issues
shai-almog May 22, 2026
6256054
Merge remote-tracking branch 'origin/master' into on-device-debug-ios
shai-almog May 22, 2026
4997071
Docs: drive developer-guide LanguageTool count to zero on this branch
shai-almog May 22, 2026
7a2cf9d
On-device debug: ship IDE configs in archetype + IDE-first dev guide
shai-almog May 23, 2026
5792654
Archetype: actually check in the IDE run configs
shai-almog May 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
**/__pycache__/
**/private/*
**/.idea/*
# The cn1app-archetype ships project-level IDE configs (run / debug
# configurations + recommended source roots) that need to land in the
# generated project's .idea/. Un-ignore them so they stay checked in.
!maven/cn1app-archetype/src/main/resources/archetype-resources/.idea
!maven/cn1app-archetype/src/main/resources/archetype-resources/.idea/**
**/build/*
**/dist/*
*.zip
Expand Down Expand Up @@ -69,6 +74,10 @@ node_modules
**/genfiles.properties
**/private/private.properties
.idea/
# Same exception as for **/.idea/* above: keep the archetype's
# bundled IDE configs versioned.
!maven/cn1app-archetype/src/main/resources/archetype-resources/.idea
!maven/cn1app-archetype/src/main/resources/archetype-resources/.idea/**
.claude/
target
pom.xml.versionsBackup
Expand All @@ -88,6 +97,8 @@ pom.xml.tag
!.brokk/project.properties
dependency-reduced-pom.xml

/artifacts/

# Hugo website generated artifacts
/docs/website/.hugo_build.lock
/docs/website/hugo_stats.json
Expand Down
26 changes: 24 additions & 2 deletions Ports/iOSPort/nativeSources/CodenameOne_GLAppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -322,9 +322,17 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(

// Override point for customization after application launch.

// Install signal handlers so that rather than the app crashing upon a BAD_ACCESS, the
// Install signal handlers so that rather than the app crashing upon a BAD_ACCESS, the
// app will throw an NPE.
installSignalHandlers();
#ifdef CN1_ON_DEVICE_DEBUG
// Spawn the on-device-debug listener thread. Non-blocking: if
// CN1ProxyWaitForAttach=YES the function also installs a translucent
// overlay UIWindow so the user sees a "Waiting for debugger..." message
// instead of the launch splash while the wait is in progress.
extern void cn1_debugger_start(void);
cn1_debugger_start();
#endif
[self cn1EnsureViewController];
#ifndef CN1_USE_UI_SCENE
[self cn1InstallRootViewControllerIntoWindow:self.window];
Expand All @@ -341,12 +349,26 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
}
}
}
#ifdef CN1_ON_DEVICE_DEBUG
// Defer the VM callback until the on-device-debug proxy reports an IDE
// has attached (if CN1ProxyWaitForAttach=YES). Otherwise this fires
// synchronously and behaves identically to the non-debug build.
extern void cn1_debugger_run_when_ready(void (^onReady)(void));
id locationValueDeferred = [launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey];
cn1_debugger_run_when_ready(^{
com_codename1_impl_ios_IOSImplementation_callback__(CN1_THREAD_GET_STATE_PASS_SINGLE_ARG);
if (locationValueDeferred) {
com_codename1_impl_ios_IOSImplementation_appDidLaunchWithLocation__(CN1_THREAD_GET_STATE_PASS_SINGLE_ARG);
}
});
#else
com_codename1_impl_ios_IOSImplementation_callback__(CN1_THREAD_GET_STATE_PASS_SINGLE_ARG);

id locationValue = [launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey];
if (locationValue) {
com_codename1_impl_ios_IOSImplementation_appDidLaunchWithLocation__(CN1_THREAD_GET_STATE_PASS_SINGLE_ARG);
}
#endif

#ifdef INCLUDE_CN1_BACKGROUND_FETCH
[application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
Expand Down
127 changes: 127 additions & 0 deletions Ports/iOSPort/nativeSources/cn1_debugger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Codename One designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*/

#ifndef CN1_DEBUGGER_H
#define CN1_DEBUGGER_H

#ifdef CN1_ON_DEVICE_DEBUG

#include "cn1_globals.h"


/**
* Boots the on-device-debug listener thread (non-blocking). Reads the
* desktop proxy host and port from Info.plist keys CN1ProxyHost /
* CN1ProxyPort, spawns a background thread that opens an outbound TCP
* connection, sends a HELLO event, and services commands (set/clear
* breakpoint, resume, step, get stack, get locals) in a loop.
*
* Returns immediately. If Info.plist has CN1ProxyWaitForAttach=YES, the
* function also installs a "Waiting for debugger" overlay UIWindow so the
* user sees something other than the splash while the wait is in progress;
* the overlay is dismissed automatically when {@link
* cn1_debugger_run_when_ready} fires its block.
*/
extern void cn1_debugger_start(void);

/**
* Per-class instance-field descriptor emitted by the translator (one
* static array per generated class), then registered with the debugger
* runtime by a __attribute__((constructor)) shim that the translator also
* emits. The runtime uses these to answer CMD_GET_OBJECT_FIELDS without
* any reflection / RTTI from ParparVM.
*
* offset is from the start of the object struct (i.e. offsetof). type is
* a JVM type-char ('I','J','F','D','Z','B','S','C','L' — 'L' covers
* arrays too since arrays are JAVA_OBJECT in the struct).
*/
typedef struct cn1_field_entry {
int fieldId;
int offset;
char type;
const char* name;
} cn1_field_entry;

/**
* Translator-generated constructors call this once at process load to
* publish the class's field table to the debugger runtime. classId is
* the cn1_class_id_XXX constant.
*/
extern void cn1_debugger_register_fields(int classId,
const cn1_field_entry* table,
int count);

/* --- Method invocation -------------------------------------------------- */

/**
* Argument or scratch slot for a debugger-driven method invocation. All
* args travel as a flat array of these; the thunk reads the right field
* for each declared parameter. Floats/doubles round-trip through the bit
* width of their integer counterparts since debug clients pass them as
* raw 32/64-bit values.
*/
typedef union cn1_invoke_arg {
JAVA_INT i;
JAVA_LONG j;
JAVA_FLOAT f;
JAVA_DOUBLE d;
JAVA_OBJECT o;
} cn1_invoke_arg;

/**
* Result of a debugger-driven method invocation. {@code type} is a JVM
* type-char ('V', 'I', 'J', 'F', 'D', 'L', 'Z', 'B', 'S', 'C') or 'X'
* if the call threw — in which case {@code value.o} carries the
* Throwable.
*/
typedef struct cn1_invoke_result {
char type;
cn1_invoke_arg value;
} cn1_invoke_result;

/**
* Translator-emitted per-method shim. The thunk unpacks {@code args}
* into the typed C parameters the underlying translated function
* expects, dispatches through {@code virtual_<sym>(...)} (instance) or
* the static symbol (static), and packs the return into {@code result}.
* Exceptions are caught and surfaced as result.type='X'.
*
* Runs on the suspended Java thread so it has a valid
* {@code threadStateData} context.
*/
typedef void (*cn1_invoke_thunk_t)(struct ThreadLocalData* threadStateData,
JAVA_OBJECT thisObj,
const cn1_invoke_arg* args,
cn1_invoke_result* result);

/**
* Translator-emitted constructor registers each method's thunk at
* process load. methodId matches the same value the sidecar carries,
* so the proxy can look up by name → methodId and forward to the
* device with no further mapping.
*/
extern void cn1_debugger_register_invoke_thunk(int methodId, cn1_invoke_thunk_t thunk);

#ifdef __BLOCKS__
/**
* Defers the VM callback until the proxy reports the IDE has attached, so
* the AppDelegate can keep `didFinishLaunchingWithOptions` returning
* promptly and let UIKit draw the waiting overlay.
*
* If CN1ProxyWaitForAttach=NO (or the on-device-debug listener isn't
* configured), the block is invoked synchronously on the calling thread.
* Otherwise the block is stored and the proxy listener invokes it on the
* main queue once it receives the first RESUME from the desktop proxy.
*/
extern void cn1_debugger_run_when_ready(void (^onReady)(void));
#endif

#endif // CN1_ON_DEVICE_DEBUG
#endif // CN1_DEBUGGER_H
Loading
Loading