Skip to content

Commit 1a38cd0

Browse files
committed
One more chance...
1 parent 0857312 commit 1a38cd0

4 files changed

Lines changed: 95 additions & 2 deletions

File tree

Ports/JavaScriptPort/STATUS.md

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,27 @@ JavaScript Port Status (ParparVM)
55

66
Last updated: 2026-04-11
77

8+
Latest Investigation Snapshot (this round)
9+
------------------------------------------
10+
11+
- Input artifacts analyzed:
12+
- `~/Downloads/job-logs.txt`
13+
- `~/Downloads/javascript-ui-tests/browser.log`
14+
- Confirmed in that artifact set:
15+
- Suite completes (`CN1SS:SUITE:FINISHED`) and 32 named streams decode.
16+
- Most PNGs are still identical/white (`canvasSig=7263bb45` repeated).
17+
- Screenshot helper repeatedly falls back due:
18+
- `PARPAR:DIAG:FALLBACK:cn1ssEmitCurrentFormScreenshotDom:originalInvokeErr=Error: Missing JS member get for host receiver`
19+
- New code changes in workspace (not CI-validated yet):
20+
1. Host/runtime JSO bridge now supports array-like indexed fallback for `get(index)`/`set(index,value)` when no callable member exists.
21+
2. Host bridge attempts to avoid per-pixel host RPC by cloning typed-array payloads.
22+
3. Host bridge has explicit `getter:data` fast-return clone path.
23+
4. BaseTest on-show lambda shim now guards missing `target.__classDef` by resolving class metadata from `target.__class`.
24+
5. Screenshot fallback now logs short `originalInvokeStack` for first-failure localization.
25+
- Important caveat from local replay:
26+
- Replaying patched runtime against the previously archived CI zip can regress to timeout and show `originalInvokeErr=Cannot read properties of null (reading '__classDef')` during per-test screenshot emission.
27+
- This indicates the first blocker has shifted from missing host `.get` to a null receiver/class-init path in translated screenshot execution.
28+
829
Current State
930
-------------
1031

@@ -163,10 +184,45 @@ What Was Fixed In This Pass
163184
- Expected effect:
164185
- Restore named screenshot stream emission (`CN1SS:<test>`) instead of collapsing to `default`-only stream.
165186

187+
14. Added JSO bridge indexed-access compatibility for array-like receivers.
188+
- Files:
189+
- `vm/ByteCodeTranslator/src/javascript/browser_bridge.js`
190+
- `vm/ByteCodeTranslator/src/javascript/parparvm_runtime.js`
191+
- Changes:
192+
- If a bridged `method` call has member `get`/`set` and receiver is array-like (`length`), map to indexed element access when no callable JS member exists.
193+
- Motivation:
194+
- Fixes deterministic screenshot-path failure:
195+
- `Missing JS member get for host receiver`
196+
- Seen when translated code accesses pixel buffers via `get(index)`.
197+
198+
15. Added host bridge typed-array transfer fast paths.
199+
- File:
200+
- `vm/ByteCodeTranslator/src/javascript/browser_bridge.js`
201+
- Changes:
202+
- `hostResult()` now clones/returns typed-array and `ArrayBuffer` values directly instead of always creating host refs.
203+
- Added explicit `getter:data` direct-clone return path in `__cn1_jso_bridge__`.
204+
- Motivation:
205+
- Prevents pathological per-element host RPC loops during pixel-buffer reads.
206+
- Status:
207+
- Local replay indicates this removes the old `Missing JS member get...` failure, but uncovers a later null `__classDef` path that still needs repair.
208+
209+
16. Hardened BaseTest on-show lambda shim for missing class definition.
210+
- File:
211+
- `Ports/JavaScriptPort/src/main/webapp/port.js`
212+
- Changes:
213+
- `target.__classDef` access now falls back to `jvm.classes[target.__class]` and exits safely with diagnostic if unresolved.
214+
- Motivation:
215+
- Targets recurring per-test failure signature:
216+
- `Cannot read properties of null (reading '__classDef')`
217+
- This is now the highest-priority blocker after `.get` bridge repair.
218+
166219
Known Failing Symptoms (Latest CI Logs/Artifacts)
167220
-------------------------------------------------
168221

169222
- Screenshot suite finishes but many tests fail during `runTest`.
223+
- Latest primary blocker progression:
224+
- Earlier blocker in CI artifacts: `Missing JS member get for host receiver`.
225+
- After bridge compatibility work in local replay: blocker shifts to `Cannot read properties of null (reading '__classDef')` in translated screenshot helper path.
170226
- Repeated deterministic blockers in browser log:
171227
- `TabsScreenshotTest`: `cn1_com_codename1_ui_Button_initLaf_com_codename1_ui_plaf_UIManager is not defined`
172228
- `OrientationLockScreenshotTest`: `document is not defined`
@@ -199,7 +255,7 @@ Priority Next Steps
199255
4. Validate `CN1SS` named test streams are emitted again (not only `default/bootstrap`).
200256
5. Validate `originalResolved=translated:...__impl` (or equivalent non-recursive path) in CI browser log after translated-method preservation patch.
201257
6. If white-frame reuse persists, capture and compare per-test `settleSig`/`canvasSig`/`canvasSource` to identify whether paint is not happening or capture target is still wrong.
202-
7. Fix per-test null receiver/init path (`__classDef` null) at first failing stack, not via broad fallbacks.
258+
7. Fix per-test null receiver/init path (`__classDef` null) at first failing stack in translated screenshot/helper execution (no new broad fallbacks).
203259
8. Fix missing `Button.initLaf(UIManager)` symbol resolution in worker runtime path.
204260
9. Fix worker-mode orientation lock path so DOM access is host-bridge mediated (no direct `document` access in worker).
205261
10. Confirm VM completeness stability in CI with parser/runtime patches (`expected 7` consistently).

Ports/JavaScriptPort/src/main/webapp/port.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3181,6 +3181,10 @@ bindCiFallback("Cn1ssDeviceRunnerHelper.emitCurrentFormScreenshotDom", [
31813181
} catch (originalErr) {
31823182
emitDiagLine("PARPAR:DIAG:FALLBACK:cn1ssEmitCurrentFormScreenshotDom:originalInvokeErr="
31833183
+ String(originalErr && originalErr.message ? originalErr.message : originalErr));
3184+
if (originalErr && originalErr.stack) {
3185+
emitDiagLine("PARPAR:DIAG:FALLBACK:cn1ssEmitCurrentFormScreenshotDom:originalInvokeStack="
3186+
+ String(originalErr.stack).split("\n").slice(0, 2).join(" | "));
3187+
}
31843188
shouldUseDomFallback = true;
31853189
} finally {
31863190
cn1ssEmitCurrentFormScreenshotInvokeDepth = Math.max(0, cn1ssEmitCurrentFormScreenshotInvokeDepth - 1);
@@ -3328,7 +3332,11 @@ function installBaseTestOnShowLambdaShim() {
33283332
if (!target || !target.__class) {
33293333
return null;
33303334
}
3331-
const classDef = target.__classDef;
3335+
const classDef = target.__classDef || (jvm.classes ? jvm.classes[target.__class] : null);
3336+
if (!classDef) {
3337+
emitDiagLine("PARPAR:DIAG:FALLBACK:baseTestOnShowLambda:noClassDef=1:class=" + String(target.__class || "null"));
3338+
return null;
3339+
}
33323340
let method = (classDef && classDef.methods) ? classDef.methods[baseTestOnShowLambdaMethodId] : null;
33333341
if (!method) {
33343342
method = jvm.resolveVirtual(target.__class, baseTestOnShowLambdaMethodId);

vm/ByteCodeTranslator/src/javascript/browser_bridge.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,19 @@
209209
if (value == null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
210210
return value;
211211
}
212+
// Avoid per-element host RPC on large typed-array reads (e.g. ImageData.data).
213+
// Returning a clone transfers data once to the worker so get(index) executes locally.
214+
if (typeof Uint8ClampedArray !== 'undefined' && value instanceof Uint8ClampedArray) {
215+
return new Uint8Array(value);
216+
}
217+
if (typeof ArrayBuffer !== 'undefined') {
218+
if (value instanceof ArrayBuffer) {
219+
return value.slice(0);
220+
}
221+
if (typeof ArrayBuffer.isView === 'function' && ArrayBuffer.isView(value)) {
222+
return value.slice ? value.slice(0) : value;
223+
}
224+
}
212225
return storeHostRef(value);
213226
}
214227

@@ -330,12 +343,23 @@
330343
var fn = receiver[member];
331344
if (typeof fn === 'function') {
332345
value = fn.apply(receiver, args);
346+
} else if (member === 'get' && args.length === 1 && receiver && typeof receiver.length === 'number') {
347+
value = receiver[args[0] | 0];
348+
} else if (member === 'set' && args.length === 2 && receiver && typeof receiver.length === 'number') {
349+
receiver[args[0] | 0] = args[1];
350+
value = null;
333351
} else if (!args.length && Object.prototype.hasOwnProperty.call(receiver, member)) {
334352
value = receiver[member];
335353
} else {
336354
throw new Error('Missing JS member ' + member + ' for host receiver');
337355
}
338356
}
357+
if (kind === 'getter' && member === 'data' && value && typeof value.length === 'number') {
358+
if (value.slice) {
359+
return value.slice(0);
360+
}
361+
return Array.prototype.slice.call(value);
362+
}
339363
noteDrawTarget(receiver, kind, member);
340364
if (isCanvasLike(receiver) && kind === 'method' && member === 'getContext') {
341365
global.__cn1LastDrawCanvas = receiver;

vm/ByteCodeTranslator/src/javascript/parparvm_runtime.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,11 @@ const jvm = {
740740
const fn = receiver[bridge.member];
741741
if (typeof fn === "function") {
742742
result = fn.apply(receiver, nativeArgs);
743+
} else if (bridge.member === "get" && nativeArgs.length === 1 && receiver && typeof receiver.length === "number") {
744+
result = receiver[nativeArgs[0] | 0];
745+
} else if (bridge.member === "set" && nativeArgs.length === 2 && receiver && typeof receiver.length === "number") {
746+
receiver[nativeArgs[0] | 0] = nativeArgs[1];
747+
result = null;
743748
} else if (!nativeArgs.length && Object.prototype.hasOwnProperty.call(receiver, bridge.member)) {
744749
result = receiver[bridge.member];
745750
} else {

0 commit comments

Comments
 (0)