Skip to content

Switch initializr JavaScript build to local ParparVM target#5200

Open
shai-almog wants to merge 14 commits into
masterfrom
initializr-local-javascript-build
Open

Switch initializr JavaScript build to local ParparVM target#5200
shai-almog wants to merge 14 commits into
masterfrom
initializr-local-javascript-build

Conversation

@shai-almog

Copy link
Copy Markdown
Collaborator

Summary

Switches the initializr's JavaScript build from the remote cloud build target to the local ParparVM-based translator.

CN1BuildMojo already routes any local--prefixed target locally: local-javascriptdoJavaScriptLocalBuild()JavaScriptBuilder (ParparVM bytecode → JavaScript). The plain javascript target went remote (Ant codeNameOne task → build server → download result.zip). The local path was already fully wired, so this change is purely a build-target switch in the initializr — no Mojo/builder changes.

Automate mode still logs in with the server secret, so the pipeline behaves the same as before.

Changes (all under scripts/initializr/)

  • javascript/pom.xmlcodename1.defaultBuildTarget: javascriptlocal-javascript
  • build.sh / build.bat — these pass -Dcodename1.buildTarget=javascript explicitly (overriding the pom default), so both flipped to local-javascript
  • README.adoc + bundled skill docs (SKILL.md, references/build-and-run.md, references/native-interfaces.md) — document the JS build as the local ParparVM target, with the cloud javascript target noted as the fallback

Notes

  • The maven/cn1app-archetype template (shipped to generated user projects) is intentionally not changed here — it still defaults to the cloud javascript target.

🤖 Generated with Claude Code

shai-almog and others added 2 commits June 8, 2026 20:34
The initializr javascript module previously built via the remote
`javascript` build target (cloud build server). Switch it to the
local `local-javascript` target, which routes through
CN1BuildMojo#doJavaScriptLocalBuild -> JavaScriptBuilder (ParparVM
bytecode -> JavaScript translator). Automate mode still authenticates
with the server secret, so the build pipeline is unaffected.

Changes (all under scripts/initializr/):
- javascript/pom.xml: codename1.defaultBuildTarget javascript -> local-javascript
- build.sh / build.bat: explicit -Dcodename1.buildTarget -> local-javascript
  (these override the pom default)
- README.adoc and bundled skill docs (SKILL.md, build-and-run.md,
  native-interfaces.md): document the JS build as local ParparVM, with
  the cloud `javascript` target noted as the fallback

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The local-javascript build failed in the initializr/website pipeline
because JavaScriptBuilder.checkUserLevel() only accepted an explicit
javascript.userLevel / CN1_USER_LEVEL / codename1.userLevel property.
The website build (build_initializr_for_site -> set_cn1_user_token)
authenticates by writing the CN1 user+token to the /com/codename1/ui
preferences node (SetUserTokenMojo / cn1:set-user-token), not by
setting a userLevel property, so the gate rejected an authenticated
build.

Honor that login directly: if a CN1 user+token is present in prefs the
local JS build is authorized, the same way the cloud build is. The
explicit userLevel property remains a fallback for logged-out CLI use.

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

shai-almog commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 128 screenshots: 128 matched.

Native Android coverage

  • 📊 Line coverage: 14.12% (8546/60528 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 11.42% (42136/368959), branch 4.96% (1719/34653), complexity 6.00% (1995/33247), method 10.42% (1621/15559), class 17.07% (374/2191)
    • 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: 14.12% (8546/60528 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 11.42% (42136/368959), branch 4.96% (1719/34653), complexity 6.00% (1995/33247), method 10.42% (1621/15559), class 17.07% (374/2191)
    • 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 1078.000 ms
Base64 CN1 encode 339.000 ms
Base64 encode ratio (CN1/native) 0.314x (68.6% faster)
Base64 native decode 1475.000 ms
Base64 CN1 decode 301.000 ms
Base64 decode ratio (CN1/native) 0.204x (79.6% faster)
Image encode benchmark status skipped (SIMD unsupported)

@github-actions

github-actions Bot commented Jun 8, 2026

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 and others added 2 commits June 8, 2026 21:37
The website CI builds the initializr against the released codenameone
plugin (cn1.plugin.version=7.0.250), whose JavaScriptBuilder license
gate only reads the javascript.userLevel / CN1_USER_LEVEL /
codename1.userLevel inputs -- it does not yet honor the logged-in CN1
account. set_cn1_user_token performs the login, but the released gate
still rejected the build ("JavaScript build failed").

Declare codename1.arg.javascript.userLevel=Enterprise in the shared
initializr settings so the released plugin's gate is satisfied. The
javascript module's getCN1ProjectDir() resolves to ../common, so this
flows into the build request as the javascript.userLevel arg. The
companion plugin change lets newer plugins accept the login directly,
at which point this declaration is redundant but harmless.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
With codename1.buildTarget=local-javascript the ParparVM builder emits
a zip whose entries are nested under a single top-level directory
(e.g. Initializr-js/index.html), whereas the cloud result.zip is flat
with index.html at the root. The website extraction therefore failed
its "missing index.html after extraction" check.

After unzip, if index.html isn't at the root, flatten a single
top-level wrapper directory so the served initializr-app layout is
identical for both the local and cloud builders. No-op for the flat
cloud bundles (Playground/Skin Designer still build via the cloud
javascript target).

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

shai-almog commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator Author

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

Benchmark Results

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

Build and Run Timing

Metric Duration
Simulator Boot 109000 ms
Simulator Boot (Run) 1000 ms
App Install 55000 ms
App Launch 9000 ms
Test Execution 292000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 1259.000 ms
Base64 CN1 encode 1738.000 ms
Base64 encode ratio (CN1/native) 1.380x (38.0% slower)
Base64 native decode 390.000 ms
Base64 CN1 decode 1240.000 ms
Base64 decode ratio (CN1/native) 3.179x (217.9% slower)
Base64 SIMD encode 512.000 ms
Base64 encode ratio (SIMD/native) 0.407x (59.3% faster)
Base64 encode ratio (SIMD/CN1) 0.295x (70.5% faster)
Base64 SIMD decode 461.000 ms
Base64 decode ratio (SIMD/native) 1.182x (18.2% slower)
Base64 decode ratio (SIMD/CN1) 0.372x (62.8% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 80.000 ms
Image createMask (SIMD on) 30.000 ms
Image createMask ratio (SIMD on/off) 0.375x (62.5% faster)
Image applyMask (SIMD off) 187.000 ms
Image applyMask (SIMD on) 163.000 ms
Image applyMask ratio (SIMD on/off) 0.872x (12.8% faster)
Image modifyAlpha (SIMD off) 258.000 ms
Image modifyAlpha (SIMD on) 163.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.632x (36.8% faster)
Image modifyAlpha removeColor (SIMD off) 219.000 ms
Image modifyAlpha removeColor (SIMD on) 163.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.744x (25.6% faster)
Image PNG encode (SIMD off) 1582.000 ms
Image PNG encode (SIMD on) 1245.000 ms
Image PNG encode ratio (SIMD on/off) 0.787x (21.3% faster)
Image JPEG encode 881.000 ms

The Initializr page template references /initializr-app/icon.png. The
cloud build's bundle shipped that icon; the local ParparVM bundle does
not, so the link/image validator failed ("Cannot find file ...
initializr-app/icon.png").

Copy scripts/initializr/common/icon.png into the extracted bundle when
it is absent, so the served layout matches the cloud build.

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

shai-almog commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 77 screenshots: 77 matched.
✅ Native Mac screenshot tests passed.

Benchmark Results

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

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Cloudflare Preview

@shai-almog

shai-almog commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator Author

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

Benchmark Results

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

Build and Run Timing

Metric Duration
Simulator Boot 122000 ms
Simulator Boot (Run) 1000 ms
App Install 20000 ms
App Launch 18000 ms
Test Execution 408000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 1268.000 ms
Base64 CN1 encode 2001.000 ms
Base64 encode ratio (CN1/native) 1.578x (57.8% slower)
Base64 native decode 461.000 ms
Base64 CN1 decode 1257.000 ms
Base64 decode ratio (CN1/native) 2.727x (172.7% slower)
Base64 SIMD encode 548.000 ms
Base64 encode ratio (SIMD/native) 0.432x (56.8% faster)
Base64 encode ratio (SIMD/CN1) 0.274x (72.6% faster)
Base64 SIMD decode 634.000 ms
Base64 decode ratio (SIMD/native) 1.375x (37.5% slower)
Base64 decode ratio (SIMD/CN1) 0.504x (49.6% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 106.000 ms
Image createMask (SIMD on) 30.000 ms
Image createMask ratio (SIMD on/off) 0.283x (71.7% faster)
Image applyMask (SIMD off) 297.000 ms
Image applyMask (SIMD on) 150.000 ms
Image applyMask ratio (SIMD on/off) 0.505x (49.5% faster)
Image modifyAlpha (SIMD off) 249.000 ms
Image modifyAlpha (SIMD on) 313.000 ms
Image modifyAlpha ratio (SIMD on/off) 1.257x (25.7% slower)
Image modifyAlpha removeColor (SIMD off) 340.000 ms
Image modifyAlpha removeColor (SIMD on) 368.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 1.082x (8.2% slower)
Image PNG encode (SIMD off) 1756.000 ms
Image PNG encode (SIMD on) 1357.000 ms
Image PNG encode ratio (SIMD on/off) 0.773x (22.7% faster)
Image JPEG encode 808.000 ms

@shai-almog

shai-almog commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator Author

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

Native-interface stubs (com_<pkg>_<Class>.js) generated by StubGenerator
end with `})(cn1_get_native_interfaces());` and self-register into that
registry. The accessor is defined only in fontmetrics.js, which loads on
the main thread; the worker imports the stubs via importScripts but never
loads fontmetrics.js, so the IIFE throws "ReferenceError:
cn1_get_native_interfaces is not defined" and aborts worker startup before
jvm.start(). Any app with a JS-port NativeInterface (e.g. the Initializr's
WebsiteThemeNative) therefore never boots; HelloCodenameOne has none, so
the screenshot suite never caught it.

Define a worker-local registry before the imports, mirroring the existing
getParameterByName worker-local shim.

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

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

✅ ByteCodeTranslator Quality Report

Test & Coverage

  • Tests: 387 total, 0 failed, 11 skipped

Benchmark Results

  • Execution Time: 23542 ms

  • Hotspots (Top 20 sampled methods):

    • 18.97% java.lang.String.indexOf (487 samples)
    • 17.37% java.util.ArrayList.indexOf (446 samples)
    • 15.27% com.codename1.tools.translator.Parser.isMethodUsed (392 samples)
    • 3.31% com.codename1.tools.translator.Parser.addToConstantPool (85 samples)
    • 2.80% com.codename1.tools.translator.ByteCodeClass.updateAllDependencies (72 samples)
    • 2.73% com.codename1.tools.translator.BytecodeMethod.appendMethodSignatureSuffixFromDesc (70 samples)
    • 2.69% com.codename1.tools.translator.BytecodeMethod.addToConstantPool (69 samples)
    • 2.34% com.codename1.tools.translator.ByteCodeClass.calcUsedByNative (60 samples)
    • 1.99% com.codename1.tools.translator.ByteCodeClass.markDependent (51 samples)
    • 1.95% com.codename1.tools.translator.BytecodeMethod.optimize (50 samples)
    • 1.83% java.lang.StringBuilder.append (47 samples)
    • 1.48% com.codename1.tools.translator.Parser.generateClassAndMethodIndexHeader (38 samples)
    • 1.36% java.lang.Object.hashCode (35 samples)
    • 1.36% com.codename1.tools.translator.BytecodeMethod.equals (35 samples)
    • 1.01% com.codename1.tools.translator.BytecodeMethod.appendCMethodPrefix (26 samples)
    • 0.97% org.objectweb.asm.ClassReader.readCode (25 samples)
    • 0.90% java.lang.System.identityHashCode (23 samples)
    • 0.82% com.codename1.tools.translator.bytecodes.CustomInvoke.appendInstruction (21 samples)
    • 0.78% com.codename1.tools.translator.Parser.getClassByName (20 samples)
    • 0.66% java.util.TreeMap.getEntry (17 samples)
  • ⚠️ 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.

shai-almog and others added 2 commits June 9, 2026 04:22
The local ParparVM JavaScript builder (codename1.buildTarget=
local-javascript) and its fixes live in the repo's 8.0-SNAPSHOT plugin,
not the pinned 7.0.250 release the initializr was building against. So
the preview never exercised the repo's builder/translator/JS-port — the
native-interface worker fix, the login-aware license gate, etc. could
not take effect.

Mirror the Playground/Skin Designer path for the initializr:
- cn1-local-workspace profile now overrides cn1.version AND
  cn1.plugin.version to 8.0-SNAPSHOT (was a vestigial 7.0.250 re-pin).
- build_initializr_for_site bootstraps the local snapshots and builds
  with -Dcn1.localWorkspace=true under the bootstrapped JDK 17.
- bootstrap_local_cn1_snapshots is now idempotent (the full reactor
  build runs once even though all three site apps call it).
- website-docs.yml sets WEBSITE_BOOTSTRAP_CN1_SNAPSHOTS=true so the
  preview builds the site apps against repo HEAD.

Validated locally: the initializr JS bundle builds against 8.0-SNAPSHOT
and its worker.js carries the cn1_get_native_interfaces registry shim.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
NativeLookup.create() returned null on the ParparVM JS port: there was
no <Iface>Impl, the cn1_native_interfaces registry was never read, and
the worker imported the JS stub (which crashed on the undefined
cn1_get_native_interfaces). Native interfaces simply weren't wired.

Implement them end to end, modeled on the cloud builder's
JSStubGenerator/NativeLookup.register flow but adapted to the
worker/host-call model so the developer's JS impl runs on the MAIN
thread (DOM access), as it must:

- JavaScriptBuilder: scan staged classes for NativeInterface subtypes
  and generate a <Iface>Impl per interface whose methods box their args
  and delegate to NativeInterfaceBridge.call*. The launcher emits
  NativeLookup.register(iface, impl) so create() resolves and the
  optimizer keeps the impl (otherwise reached only reflectively).
- NativeInterfaceBridge (com.codename1.impl.platform.js -> HOST_HOOK):
  call{Boolean,Int,...,String,Object,Void}(iface, method, args). The
  worker suspends and the call replays on the main thread.
- browser_bridge.js: main-thread handlers look up
  cn1_native_interfaces[iface][method_], invoke it with (args..., {
  complete, error }) and resume the worker via the host callback.
- JavascriptBundleWriter: native-interface stubs (identified by the
  cn1_get_native_interfaces marker) load on the MAIN thread (index.html)
  and are excluded from the worker importScripts.
- parparvm_runtime: marshal Java String -> JS string in
  toHostTransferArg so the iface/method names reach the host correctly.
- worker.js: drop the earlier worker-local registry shim (the
  degrade-in-worker approach); stubs no longer load in the worker.

The existing JS impl format (cn1_native_interfaces["<pkg>_<Iface>"]
["<method>_<paramTypes>"](args..., callback)) is preserved so stubs
work as-is. Validated locally: the initializr bundle's
WebsiteThemeNativeImpl is reachable and emits callBoolean/callVoid
host-hooks; browser_bridge registers the handlers; index.html loads the
stub and the worker does not. boolean/void/numeric returns are complete;
String/Object/long return wrapping is a follow-up.

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

shai-almog commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

Native Windows port

Compared 125 screenshots: 124 matched, 1 updated.

  • StatusBarTapDiagnosticScreenshotTest — updated screenshot. Screenshot differs (784x561 px, bit depth 8).

    StatusBarTapDiagnosticScreenshotTest
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as StatusBarTapDiagnosticScreenshotTest.png in workflow artifacts.

shai-almog and others added 6 commits June 9, 2026 08:01
Extend native-interface support to every NativeInterface type (all
primitives, String, the primitive arrays byte[]/int[]/long[]/double[]/
float[]/boolean[]/char[]/short[], and String[]) in both directions.

- NativeInterfaceBridge: per-primitive call* + callString/callVoid/
  callObject, plus a typed callArray(iface, method, args, componentToken)
  for array returns.
- JavaScriptBuilder: <Iface>Impl return-type dispatch routes arrays to
  callArray with the element's component token (JAVA_INT.../
  java_lang_String) and boxes primitive args into the Object[].
- JavascriptNativeRegistry: the call* symbols are RUNTIME_IMPLEMENTED so
  the translator defers to the worker-side wrappers.
- parparvm_runtime.js: bindNative wrappers funnel through the single
  __cn1_native_interface_call__ host hook and coerce the resolved JS
  value to the declared Java type -- createJavaString (String/String[]),
  _LfromNumber (long/long[]), jvm.newArray(token) (typed arrays),
  int/short/byte/char/float/double normalisation. toHostTransferArg now
  unboxes argument values too (boxed Integer/Long/.../Boolean -> JS
  primitive, long {__l} -> number) so primitive/long/array arguments
  marshal correctly to the host.
- browser_bridge.js: one __cn1_native_interface_call__ handler dispatches
  to cn1_native_interfaces[iface][method](args..., callback).

Verified in the local initializr bundle: no "Missing javascript native
method" stubs remain, the bindNative wrappers/array builder are present,
and WebsiteThemeNativeImpl is reachable. PeerComponent returns route
through callObject (best-effort) pending dedicated peer wrapping.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Complete the supported-type set with com.codename1.ui.PeerComponent in
both directions:

- Return: the generated <Iface>Impl wraps the call result with
  PeerComponent.create(callObject(...)). The host returns the native
  element; cn1InvokeNativeInterface now host-ref-wraps any non-array
  object result (hostResult) so the un-cloneable DOM element survives
  postMessage to the worker and works as an HTMLElement JSO receiver (the
  JSO bridge dispatches on __cn1HostRef). PeerComponent.create routes to
  HTML5Implementation.createNativePeer -> new HTML5Peer((HTMLElement)..).
- Argument: a PeerComponent param is passed as peer.getNativePeer() (the
  underlying native element / host-ref), not the Java peer wrapper;
  toHostTransferArg already marshals the host-ref. The method key uses the
  _com_codename1_ui_PeerComponent suffix.

Validated by temporarily adding int[]/String[]/PeerComponent methods to a
native interface and rebuilding: the generated impl compiles (callArray
with JAVA_INT/java_lang_String tokens, PeerComponent.create, getNativePeer)
-- malformed codegen would have failed javac. Reverted the temp methods;
the initializr's WebsiteThemeNative (boolean/void) still builds clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The translator emits translated_app.js one statement per line with
generous indentation for readability; in a deployed bundle that
indentation + blank lines is ~20% dead weight the browser must download
and (more importantly) parse. Strip per-line leading/trailing whitespace
and drop blank lines before writing each chunk -- safe regardless of ASI
or // comments since newlines are preserved (one statement per line).

Initializr translated_app.js: 11.93 MB -> 9.58 MB raw (-2.36 MB, ~20%),
cutting parse time. Set -Dparparvm.js.pretty=true to keep the readable
form for debugging the generated code.

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

Per-suspension-boundary emission step: in methods with no exception
wrapper (~91% of methods), a throwing instruction (method call, field/
array access, NEW, ...) no longer forces its own case + pc=N+1; break;
tail. That break+redispatch existed only so exception unwind could
resume at the right frame pc; with no handler wrapper a thrown error
propagates straight out of the generator and yield* resumes inline via
delegation, so it's pure overhead.

- computeJumpTargets takes forceThrowingTargets; only adds the post-throw
  i+1 target when the method has an exception wrapper.
- mergeThrowing (gated !hasTryCatch, kill switch parparvm.js.merge.throwing.off)
  extends the safe-strip to throwing ops.

Modest on its own (~0.21MB; case scaffolding is only ~7% of the bundle --
the bulk is per-bytecode statement emission, addressed by the
expression-folding work that follows) but a correct foundational step.
node --check clean; CI JS screenshot suite is the functional gate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add buildBasicBlocks() (instruction list -> basic blocks + successor
edges) and isAcyclicForward() as the foundation for the structured
control-flow (relooper) emitter that will replace the verbose
while(true) switch(pc) state machine with if/else (and later while/for)
for reducible CFGs -- keeping the generator threading model but emitting
far more compact JS.

Pure analysis: nothing consumes it for emission yet, so output is
unchanged. The acyclic-if/else emitter (slice 1) lands on top next,
gated behind a flag with switch(pc) as the irreducible fallback.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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