Skip to content

Commit 4a97abd

Browse files
committed
Screenshot test should now produce screenshots
1 parent 9126c3c commit 4a97abd

File tree

7 files changed

+317
-12
lines changed

7 files changed

+317
-12
lines changed

Ports/JavaScriptPort/src/main/java/com/codename1/html5/js/canvas/CanvasPattern.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/*
2+
* Copyright (c) 2026 Codename One and contributors.
3+
* Licensed under the PolyForm Noncommercial License 1.0.0.
4+
*/
15
package com.codename1.html5.js.canvas;
26

37
import com.codename1.html5.js.JSObject;
@@ -8,4 +12,4 @@
812
*/
913
public interface CanvasPattern extends JSObject {
1014
void setTransform(double a, double b, double c, double d, double e, double f);
11-
}
15+
}

Ports/JavaScriptPort/src/main/java/com/codename1/html5/js/canvas/ImageData.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/*
2+
* Copyright (c) 2026 Codename One and contributors.
3+
* Licensed under the PolyForm Noncommercial License 1.0.0.
4+
*/
15
package com.codename1.html5.js.canvas;
26

37
import com.codename1.html5.js.JSObject;
@@ -11,4 +15,4 @@ public interface ImageData extends JSObject {
1115
int getWidth();
1216
int getHeight();
1317
Uint8ClampedArray getData();
14-
}
18+
}

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

Lines changed: 195 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,8 @@ function installLifecycleDiagnostics() {
363363
}
364364
const targets = [
365365
["com_codename1_ui_Form", "cn1_com_codename1_ui_Form_show", "FORM_SHOW"],
366+
["com_codename1_ui_Form", "cn1_com_codename1_ui_Form_onShowCompletedImpl", "FORM_ON_SHOW_COMPLETED_IMPL"],
367+
["com_codename1_ui_Form", "cn1_com_codename1_ui_Form_onShowCompleted", "FORM_ON_SHOW_COMPLETED"],
366368
["com_codename1_ui_Display", "cn1_com_codename1_ui_Display_setCurrentForm_com_codename1_ui_Form", "DISPLAY_SET_CURRENT_FORM"],
367369
["com_codename1_system_Lifecycle", "cn1_com_codename1_system_Lifecycle_setCurrentForm_com_codename1_ui_Form", "LIFECYCLE_SET_CURRENT_FORM"],
368370
["com_codenameone_examples_hellocodenameone_tests_Cn1ssDeviceRunner", "cn1_com_codenameone_examples_hellocodenameone_tests_Cn1ssDeviceRunner_runSuite", "CN1SS_RUNNER_SUITE"],
@@ -386,7 +388,20 @@ function installLifecycleDiagnostics() {
386388
const globalTargets = [
387389
["cn1_com_codenameone_examples_hellocodenameone_tests_BaseTest_createForm_java_lang_String_com_codename1_ui_layouts_Layout_java_lang_String_R_com_codename1_ui_Form", "BASETEST_CREATE_FORM"],
388390
["cn1_com_codenameone_examples_hellocodenameone_tests_BaseTest_1___INIT___com_codenameone_examples_hellocodenameone_tests_BaseTest_java_lang_String_com_codename1_ui_layouts_Layout_java_lang_String", "BASETEST_FORM_INIT"],
391+
["cn1_com_codenameone_examples_hellocodenameone_tests_BaseTest_1_onShowCompleted", "BASETEST_ONSHOW_COMPLETED"],
392+
["cn1_com_codenameone_examples_hellocodenameone_tests_BaseTest_1_onShowCompleted__impl", "BASETEST_ONSHOW_COMPLETED_IMPL"],
393+
["cn1_com_codenameone_examples_hellocodenameone_tests_BaseTest_1_lambda_onShowCompleted_0_java_lang_String", "BASETEST_ONSHOW_LAMBDA"],
394+
["cn1_com_codenameone_examples_hellocodenameone_tests_BaseTest_1_lambda_onShowCompleted_0_java_lang_String__impl", "BASETEST_ONSHOW_LAMBDA_IMPL"],
395+
["cn1_com_codenameone_examples_hellocodenameone_tests_Cn1ssDeviceRunnerHelper_emitCurrentFormScreenshot_java_lang_String_java_lang_Runnable", "CN1SS_HELPER_EMIT_SCREENSHOT"],
396+
["cn1_com_codenameone_examples_hellocodenameone_tests_Cn1ssDeviceRunnerHelper_emitCurrentFormScreenshot_java_lang_String_java_lang_Runnable__impl", "CN1SS_HELPER_EMIT_SCREENSHOT_IMPL"],
397+
["cn1_com_codenameone_examples_hellocodenameone_tests_Cn1ssDeviceRunnerHelper_lambda_emitCurrentFormScreenshot_0_java_lang_String_java_lang_Runnable_int_int_com_codename1_ui_Image", "CN1SS_HELPER_EMIT_SCREENSHOT_LAMBDA"],
398+
["cn1_com_codenameone_examples_hellocodenameone_tests_Cn1ssDeviceRunnerHelper_lambda_emitCurrentFormScreenshot_0_java_lang_String_java_lang_Runnable_int_int_com_codename1_ui_Image__impl", "CN1SS_HELPER_EMIT_SCREENSHOT_LAMBDA_IMPL"],
399+
["cn1_com_codenameone_examples_hellocodenameone_tests_Cn1ssDeviceRunnerHelper_emitChannel_byte_1ARRAY_java_lang_String_java_lang_String", "CN1SS_HELPER_EMIT_CHANNEL"],
400+
["cn1_com_codenameone_examples_hellocodenameone_tests_Cn1ssDeviceRunnerHelper_emitChannel_byte_1ARRAY_java_lang_String_java_lang_String__impl", "CN1SS_HELPER_EMIT_CHANNEL_IMPL"],
401+
["cn1_com_codenameone_examples_hellocodenameone_tests_Cn1ssDeviceRunnerHelper_complete_java_lang_Runnable", "CN1SS_HELPER_COMPLETE"],
402+
["cn1_com_codenameone_examples_hellocodenameone_tests_Cn1ssDeviceRunnerHelper_complete_java_lang_Runnable__impl", "CN1SS_HELPER_COMPLETE_IMPL"],
389403
["cn1_com_codename1_ui_Form___INIT___java_lang_String_com_codename1_ui_layouts_Layout", "FORM_INIT_LAYOUT"],
404+
["cn1_com_codename1_ui_Form_onShowCompletedImpl", "FORM_ON_SHOW_COMPLETED_IMPL_GLOBAL"],
390405
["cn1_com_codename1_ui_Display_setCurrent_com_codename1_ui_Form_boolean", "DISPLAY_SET_CURRENT"]
391406
];
392407
for (let i = 0; i < globalTargets.length; i++) {
@@ -943,6 +958,59 @@ bindNative([
943958
return null;
944959
});
945960

961+
bindCiFallback("BlobUtil.canvasToBlobDirect", [
962+
"cn1_com_codename1_teavm_io_BlobUtil_canvasToBlob_com_codename1_html5_js_dom_HTMLCanvasElement_java_lang_String_double_R_com_codename1_teavm_jso_io_Blob",
963+
"cn1_com_codename1_teavm_io_BlobUtil_canvasToBlob_com_codename1_html5_js_dom_HTMLCanvasElement_java_lang_String_double_R_com_codename1_teavm_jso_io_Blob__impl"
964+
], function*(canvas, mimeType, quality) {
965+
const nativeCanvas = jvm.unwrapJsValue(canvas) || canvas;
966+
if (!nativeCanvas || typeof nativeCanvas.toDataURL !== "function") {
967+
emitDiagLine("PARPAR:DIAG:FALLBACK:blobUtilCanvasToBlob:missingCanvas=1");
968+
return null;
969+
}
970+
const mime = mimeType && mimeType.__class === "java_lang_String"
971+
? jvm.toNativeString(mimeType)
972+
: (typeof mimeType === "string" ? mimeType : "image/png");
973+
const q = typeof quality === "number" ? quality : 0.92;
974+
let dataUrl = "";
975+
try {
976+
dataUrl = nativeCanvas.toDataURL(mime || "image/png", q);
977+
} catch (_err) {
978+
dataUrl = nativeCanvas.toDataURL("image/png");
979+
}
980+
const comma = dataUrl.indexOf(",");
981+
if (comma < 0) {
982+
return null;
983+
}
984+
const header = dataUrl.substring(0, comma);
985+
const payload = dataUrl.substring(comma + 1);
986+
const match = /data:([^;]+);base64/i.exec(header);
987+
const contentType = match && match[1] ? match[1] : (mime || "image/png");
988+
const decoded = global.atob ? global.atob(payload) : "";
989+
const bytes = new global.Uint8Array(decoded.length);
990+
for (let i = 0; i < decoded.length; i++) {
991+
bytes[i] = decoded.charCodeAt(i) & 0xff;
992+
}
993+
const blob = new global.Blob([bytes], { type: contentType });
994+
const wrappedBlob = jvm.wrapJsObject(blob, "com_codename1_teavm_jso_io_Blob");
995+
wrappedBlob.__cn1BlobBytes = bytes;
996+
return wrappedBlob;
997+
});
998+
999+
bindCiFallback("BlobUtil.toUint8ArrayDirect", [
1000+
"cn1_com_codename1_teavm_io_BlobUtil_toUint8Array_com_codename1_teavm_jso_io_Blob_R_com_codename1_html5_js_typedarrays_Uint8Array",
1001+
"cn1_com_codename1_teavm_io_BlobUtil_toUint8Array_com_codename1_teavm_jso_io_Blob_R_com_codename1_html5_js_typedarrays_Uint8Array__impl"
1002+
], function*(blob) {
1003+
if (blob && blob.__cn1BlobBytes) {
1004+
return jvm.wrapJsObject(new global.Uint8Array(blob.__cn1BlobBytes), "com_codename1_html5_js_typedarrays_Uint8Array");
1005+
}
1006+
const nativeBlob = jvm.unwrapJsValue(blob);
1007+
if (nativeBlob && nativeBlob.__cn1BlobBytes) {
1008+
return jvm.wrapJsObject(new global.Uint8Array(nativeBlob.__cn1BlobBytes), "com_codename1_html5_js_typedarrays_Uint8Array");
1009+
}
1010+
emitDiagLine("PARPAR:DIAG:FALLBACK:blobUtilToUint8Array:empty=1");
1011+
return jvm.wrapJsObject(new global.Uint8Array(0), "com_codename1_html5_js_typedarrays_Uint8Array");
1012+
});
1013+
9461014
bindNative([
9471015
"cn1_com_codename1_impl_html5_HTML5Implementation_requestAnimationFrameNative_com_codename1_impl_html5_JavaScriptAnimationFrameCallback_R_int",
9481016
"cn1_com_codename1_impl_html5_HTML5Implementation_requestAnimationFrameNative___com_codename1_impl_html5_JavaScriptAnimationFrameCallback_R_int"
@@ -1070,7 +1138,7 @@ bindCiFallback("NativeFont.getCSSNullSafe", [
10701138
} catch (err) {
10711139
const message = String(err && err.message ? err.message : err || "");
10721140
if (message.indexOf("__classDef") >= 0) {
1073-
emitDiagLine("PARPAR:DIAG:FALLBACK:nativeFontGetCSS:nullReceiver=1");
1141+
emitCiFallbackMarker("NativeFont.getCSSNullReceiver", "HIT");
10741142
return jvm.createStringLiteral("16px sans-serif");
10751143
}
10761144
throw err;
@@ -1086,7 +1154,7 @@ bindCiFallback("NativeFont.charWidthNullSafe", [
10861154
try {
10871155
return yield* nativeFontCharWidthOriginal(__cn1ThisObject, chr);
10881156
} catch (err) {
1089-
emitDiagLine("PARPAR:DIAG:FALLBACK:nativeFontCharWidth:defaulted=1");
1157+
emitCiFallbackMarker("NativeFont.charWidthDefaulted", "HIT");
10901158
return 8;
10911159
}
10921160
});
@@ -1562,6 +1630,8 @@ installGlobalIllegalStateBypass(formCtorTitleLayoutMethodId, "formCtorTitleLayou
15621630

15631631
const cn1ssLambdaBridgeMethodId = "cn1_com_codenameone_examples_hellocodenameone_tests_Cn1ssDeviceRunner_lambda_runNextTest_2_java_lang_String_com_codenameone_examples_hellocodenameone_tests_BaseTest_int";
15641632
const cn1ssCompleteMethodId = "cn1_com_codenameone_examples_hellocodenameone_tests_Cn1ssDeviceRunnerHelper_complete_java_lang_Runnable";
1633+
const cn1ssEmitChannelMethodId = "cn1_com_codenameone_examples_hellocodenameone_tests_Cn1ssDeviceRunnerHelper_emitChannel_byte_1ARRAY_java_lang_String_java_lang_String";
1634+
const baseTestRegisterReadyCallbackMethodId = "cn1_com_codenameone_examples_hellocodenameone_tests_BaseTest_registerReadyCallback_com_codename1_ui_Form_java_lang_Runnable";
15651635
const cn1ssRunnerClassId = "com_codenameone_examples_hellocodenameone_tests_Cn1ssDeviceRunner";
15661636
const cn1ssLambdaClassId = "com_codenameone_examples_hellocodenameone_tests_Cn1ssDeviceRunner_lambda_1";
15671637
const cn1ssLambdaBridgeOriginalRunnerMethod = (function() {
@@ -1656,6 +1726,117 @@ bindCiFallback("Cn1ssDeviceRunner.lambdaRunNextTestBridge", [
16561726
}
16571727
});
16581728

1729+
function toCn1StringValue(value) {
1730+
if (value && value.__class === "java_lang_String") {
1731+
try {
1732+
return jvm.toNativeString(value);
1733+
} catch (_err) {
1734+
return "";
1735+
}
1736+
}
1737+
if (value == null) {
1738+
return "";
1739+
}
1740+
return String(value);
1741+
}
1742+
1743+
function byteArrayToBase64(value) {
1744+
if (!value || typeof value.length !== "number") {
1745+
return "";
1746+
}
1747+
const len = value.length | 0;
1748+
const bytes = new Uint8Array(len);
1749+
for (let i = 0; i < len; i++) {
1750+
let b = value[i] | 0;
1751+
if (b < 0) {
1752+
b += 256;
1753+
}
1754+
bytes[i] = b & 0xff;
1755+
}
1756+
let binary = "";
1757+
const chunkSize = 0x8000;
1758+
for (let i = 0; i < bytes.length; i += chunkSize) {
1759+
const sub = bytes.subarray(i, i + chunkSize);
1760+
binary += String.fromCharCode.apply(null, sub);
1761+
}
1762+
if (typeof global.btoa === "function") {
1763+
return global.btoa(binary);
1764+
}
1765+
if (typeof Buffer !== "undefined") {
1766+
return Buffer.from(bytes).toString("base64");
1767+
}
1768+
return "";
1769+
}
1770+
1771+
function normalizeCn1ssTestName(raw) {
1772+
const value = raw && raw.length > 0 ? raw : "default";
1773+
const normalized = String(value).replace(/[^A-Za-z0-9_.-]/g, "_");
1774+
return normalized.length > 0 ? normalized : "default";
1775+
}
1776+
1777+
const cn1ssChunkIndexByStream = Object.create(null);
1778+
const cn1ssScreenshotEmitted = Object.create(null);
1779+
1780+
function emitCn1ssChunks(base64, testName, channelName) {
1781+
const channel = channelName ? String(channelName).toUpperCase() : "";
1782+
const prefix = "CN1SS" + channel;
1783+
const test = normalizeCn1ssTestName(testName);
1784+
const streamKey = channel + "|" + test;
1785+
let nextIndex = cn1ssChunkIndexByStream[streamKey] || 0;
1786+
const chunkSize = 8000;
1787+
for (let offset = 0; offset < base64.length; offset += chunkSize) {
1788+
const payload = base64.substring(offset, offset + chunkSize);
1789+
const index = String(nextIndex++).padStart(6, "0");
1790+
emitDiagLine(prefix + ":" + test + ":" + index + ":" + payload);
1791+
}
1792+
cn1ssChunkIndexByStream[streamKey] = nextIndex;
1793+
if (base64.length === 0) {
1794+
const index = String(nextIndex).padStart(6, "0");
1795+
emitDiagLine(prefix + ":" + test + ":" + index + ":");
1796+
cn1ssChunkIndexByStream[streamKey] = nextIndex + 1;
1797+
}
1798+
}
1799+
1800+
const cn1ssEmitCurrentFormScreenshotMethodId = "cn1_com_codenameone_examples_hellocodenameone_tests_Cn1ssDeviceRunnerHelper_emitCurrentFormScreenshot_java_lang_String_java_lang_Runnable";
1801+
1802+
bindCiFallback("Cn1ssDeviceRunnerHelper.emitCurrentFormScreenshotDom", [
1803+
cn1ssEmitCurrentFormScreenshotMethodId,
1804+
cn1ssEmitCurrentFormScreenshotMethodId + "__impl"
1805+
], function*(testName, completion) {
1806+
const canvas = global.document && typeof global.document.querySelector === "function"
1807+
? global.document.querySelector("canvas")
1808+
: null;
1809+
const test = toCn1StringValue(testName);
1810+
const normalizedTest = normalizeCn1ssTestName(test);
1811+
if (cn1ssScreenshotEmitted[normalizedTest]) {
1812+
emitDiagLine("PARPAR:DIAG:FALLBACK:cn1ssEmitCurrentFormScreenshotDom:skipDuplicate=" + normalizedTest);
1813+
} else if (canvas && typeof canvas.toDataURL === "function") {
1814+
cn1ssScreenshotEmitted[normalizedTest] = true;
1815+
const dataUrl = String(canvas.toDataURL("image/png") || "");
1816+
const comma = dataUrl.indexOf(",");
1817+
const base64 = comma >= 0 ? dataUrl.substring(comma + 1) : "";
1818+
emitCn1ssChunks(base64, normalizedTest, "");
1819+
} else {
1820+
emitDiagLine("PARPAR:DIAG:FALLBACK:cn1ssEmitCurrentFormScreenshotDom:noCanvas=1");
1821+
}
1822+
if (completion && completion.__class) {
1823+
const runMethod = jvm.resolveVirtual(completion.__class, "cn1_java_lang_Runnable_run");
1824+
yield* runMethod(completion);
1825+
}
1826+
return null;
1827+
});
1828+
1829+
bindCiFallback("Cn1ssDeviceRunnerHelper.emitChannelFastJs", [
1830+
cn1ssEmitChannelMethodId,
1831+
cn1ssEmitChannelMethodId + "__impl"
1832+
], function*(payloadBytes, testName, channelName) {
1833+
const base64 = byteArrayToBase64(payloadBytes);
1834+
const test = toCn1StringValue(testName);
1835+
const channel = toCn1StringValue(channelName);
1836+
emitCn1ssChunks(base64, test, channel);
1837+
return null;
1838+
});
1839+
16591840
bindCiFallback("Cn1ssDeviceRunnerHelper.completeNullRunnableGuard", [
16601841
cn1ssCompleteMethodId,
16611842
cn1ssCompleteMethodId + "__impl"
@@ -1668,6 +1849,18 @@ bindCiFallback("Cn1ssDeviceRunnerHelper.completeNullRunnableGuard", [
16681849
return yield* runMethod(completion);
16691850
});
16701851

1852+
bindCiFallback("BaseTest.registerReadyCallbackImmediate", [
1853+
baseTestRegisterReadyCallbackMethodId,
1854+
baseTestRegisterReadyCallbackMethodId + "__impl"
1855+
], function*(_baseTest, _form, callback) {
1856+
emitDiagLine("PARPAR:DIAG:FALLBACK:baseTestRegisterReady:immediateDispatch=1");
1857+
if (!callback || !callback.__class) {
1858+
return null;
1859+
}
1860+
const runMethod = jvm.resolveVirtual(callback.__class, "cn1_java_lang_Runnable_run");
1861+
return yield* runMethod(callback);
1862+
});
1863+
16711864
const baseTestOnShowLambdaMethodId = "cn1_com_codenameone_examples_hellocodenameone_tests_BaseTest_1_lambda_onShowCompleted_0_java_lang_String";
16721865
const baseTestOnShowLambdaCarrierClass = "com_codenameone_examples_hellocodenameone_tests_BaseTest_1_lambda_0";
16731866
if (jvm && typeof jvm.addVirtualMethod === "function" && jvm.classes && jvm.classes[baseTestOnShowLambdaCarrierClass]) {

scripts/javascript_browser_harness.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,17 @@
2727
}
2828
}
2929
30-
function send(line) {
31-
var payload = String(line) + "\n";
30+
var logSendDisabled = false;
31+
var logQueue = '';
32+
var logFlushScheduled = false;
33+
34+
function flushLogs() {
35+
logFlushScheduled = false;
36+
if (logSendDisabled || !logQueue) {
37+
return;
38+
}
39+
var payload = logQueue;
40+
logQueue = '';
3241
try {
3342
if (navigator.sendBeacon) {
3443
var blob = new Blob([payload], { type: 'text/plain' });
@@ -42,7 +51,20 @@
4251
headers: { 'Content-Type': 'text/plain' },
4352
body: payload,
4453
keepalive: true
45-
}).catch(function() {});
54+
}).catch(function() {
55+
logSendDisabled = true;
56+
});
57+
}
58+
59+
function send(line) {
60+
if (logSendDisabled) {
61+
return;
62+
}
63+
logQueue += String(line) + "\n";
64+
if (!logFlushScheduled) {
65+
logFlushScheduled = true;
66+
setTimeout(flushLogs, 50);
67+
}
4668
}
4769
4870
var screenshotStartSent = false;

vm/ByteCodeTranslator/src/com/codename1/tools/translator/JavascriptMethodGenerator.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,8 @@ private static boolean appendStraightLineBasicInstruction(StringBuilder out, Byt
761761
String indexTemp = ctx.nextTemp("__idx");
762762
out.append(" { const ").append(arrayTemp).append(" = ").append(arr)
763763
.append("; const ").append(indexTemp).append(" = ").append(idx)
764-
.append("; if (!").append(arrayTemp).append(".__array) throw new Error(\"Array expected\"); if (")
764+
.append("; if (!").append(arrayTemp).append(" || !").append(arrayTemp).append(".__array) throw new Error(\"Array expected: \" + (")
765+
.append(arrayTemp).append(" == null ? \"null\" : (").append(arrayTemp).append(".__class || typeof ").append(arrayTemp).append("))); if (")
765766
.append(indexTemp).append(" < 0 || ").append(indexTemp).append(" >= ").append(arrayTemp)
766767
.append(".length) throw new Error(\"ArrayIndexOutOfBoundsException\"); ")
767768
.append(ctx.push(arrayTemp + "[" + indexTemp + "]")).append("; }\n");
@@ -782,7 +783,8 @@ private static boolean appendStraightLineBasicInstruction(StringBuilder out, Byt
782783
String indexTemp = ctx.nextTemp("__idx");
783784
out.append(" { const ").append(arrayTemp).append(" = ").append(arr)
784785
.append("; const ").append(indexTemp).append(" = ").append(idx)
785-
.append("; if (!").append(arrayTemp).append(".__array) throw new Error(\"Array expected\"); if (")
786+
.append("; if (!").append(arrayTemp).append(" || !").append(arrayTemp).append(".__array) throw new Error(\"Array expected: \" + (")
787+
.append(arrayTemp).append(" == null ? \"null\" : (").append(arrayTemp).append(".__class || typeof ").append(arrayTemp).append("))); if (")
786788
.append(indexTemp).append(" < 0 || ").append(indexTemp).append(" >= ").append(arrayTemp)
787789
.append(".length) throw new Error(\"ArrayIndexOutOfBoundsException\"); ")
788790
.append(arrayTemp).append("[").append(indexTemp).append("] = ").append(value).append("; }\n");
@@ -1594,7 +1596,7 @@ private static void appendBasicInstruction(StringBuilder out, BytecodeMethod met
15941596
case Opcodes.BALOAD:
15951597
case Opcodes.CALOAD:
15961598
case Opcodes.SALOAD:
1597-
out.append(" { const idx = stack.pop(); const arr = stack.pop(); if (!arr.__array) throw new Error(\"Array expected\"); if (idx < 0 || idx >= arr.length) throw new Error(\"ArrayIndexOutOfBoundsException\"); stack.push(arr[idx]); pc = ").append(index + 1).append("; break; }\n");
1599+
out.append(" { const idx = stack.pop(); const arr = stack.pop(); if (!arr || !arr.__array) throw new Error(\"Array expected: \" + (arr == null ? \"null\" : (arr.__class || typeof arr))); if (idx < 0 || idx >= arr.length) throw new Error(\"ArrayIndexOutOfBoundsException\"); stack.push(arr[idx]); pc = ").append(index + 1).append("; break; }\n");
15981600
return;
15991601
case Opcodes.AASTORE:
16001602
case Opcodes.IASTORE:
@@ -1604,7 +1606,7 @@ private static void appendBasicInstruction(StringBuilder out, BytecodeMethod met
16041606
case Opcodes.BASTORE:
16051607
case Opcodes.CASTORE:
16061608
case Opcodes.SASTORE:
1607-
out.append(" { const value = stack.pop(); const idx = stack.pop(); const arr = stack.pop(); if (!arr.__array) throw new Error(\"Array expected\"); if (idx < 0 || idx >= arr.length) throw new Error(\"ArrayIndexOutOfBoundsException\"); arr[idx] = value; pc = ").append(index + 1).append("; break; }\n");
1609+
out.append(" { const value = stack.pop(); const idx = stack.pop(); const arr = stack.pop(); if (!arr || !arr.__array) throw new Error(\"Array expected: \" + (arr == null ? \"null\" : (arr.__class || typeof arr))); if (idx < 0 || idx >= arr.length) throw new Error(\"ArrayIndexOutOfBoundsException\"); arr[idx] = value; pc = ").append(index + 1).append("; break; }\n");
16081610
return;
16091611
case Opcodes.MONITORENTER:
16101612
out.append(" jvm.monitorEnter(jvm.currentThread, stack.pop()); pc = ").append(index + 1).append("; break;\n");

0 commit comments

Comments
 (0)