Skip to content

fix: copy a Java array when spreading it - #55

Merged
marevol merged 1 commit into
es6/fix-class-name-errorfrom
es6/fix-spread-array-copy
Aug 28, 2026
Merged

fix: copy a Java array when spreading it#55
marevol merged 1 commit into
es6/fix-class-name-errorfrom
es6/fix-spread-array-copy

Conversation

@marevol

@marevol marevol commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Stacked on #54.

Spreading a Java array of a reference type produced an array that shared storage with it, against the "a new array holding the elements" the method documents:

var StringArray = Java.type("java.lang.String[]");
var a = new StringArray(2); a[0] = "x"; a[1] = "y";
var js = [...a];

js[0] = "changed";   // a is now changed,y
js[0] = 42;          // java.lang.ArrayStoreException: java.lang.Integer
js[1] = {};          // java.lang.ArrayStoreException: ...JO4

Both come out of an ordinary assignment as raw Java exceptions, which script code cannot recover from.

Cause

toApplyArgs returns the very array it is given when that array is an Object[], and Global.allocate wraps rather than copies — ArrayData.allocate(Object[]) makes an ObjectArrayData over the same storage. Every other branch of TO_ARRAY builds a fresh array, and the start > 0 path already copied with Arrays.copyOfRange; only this one aliased.

Fix

Copy with Arrays.copyOf(array, length, Object[].class) rather than clone(), because a String[] clones to a String[]: the component type has to go too, or the second and third lines above still throw.

Verification

./gradlew build testOptimistic testPessimistic

suite before after
test 665, 0 fail 665, 0 fail
testOptimistic 1717, 0 fail 1717, 0 fail
testPessimistic 1717, 0 fail 1717, 0 fail

Spreading a Java array of a reference type produced an array that shared storage
with it, against the "a new array holding the elements" the method documents:

    var StringArray = Java.type("java.lang.String[]");
    var a = new StringArray(2); a[0] = "x"; a[1] = "y";
    var js = [...a];

    js[0] = "changed";   a is now changed,y
    js[0] = 42;          java.lang.ArrayStoreException: java.lang.Integer
    js[1] = {};          java.lang.ArrayStoreException: ...JO4

Both come out of an ordinary assignment as raw Java exceptions, which script code
cannot recover from.

toApplyArgs returns the very array it is given when that array is an Object[],
and Global.allocate wraps rather than copies - ArrayData.allocate(Object[]) makes
an ObjectArrayData over the same storage. Every other branch of TO_ARRAY builds a
fresh array, and the start > 0 path already copied with Arrays.copyOfRange; only
this one aliased.

Copying with Arrays.copyOf(array, length, Object[].class) rather than clone()
because a String[] clones to a String[]: the component type has to go too, or the
second and third lines above still throw.

./gradlew build testOptimistic testPessimistic:

  suite            before         after
  test             665, 0 fail    665, 0 fail
  testOptimistic   1717, 0 fail   1717, 0 fail
  testPessimistic  1717, 0 fail   1717, 0 fail
@marevol
marevol force-pushed the es6/fix-spread-array-copy branch from 51aa880 to 58d5ab9 Compare August 28, 2026 05:11
@marevol marevol self-assigned this Aug 28, 2026
@marevol
marevol merged commit dbd4468 into master Aug 28, 2026
1 check 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