Converting from Int8Array to byte[] without copying

286 views
Skip to first unread message

Machtin Below

unread,
Feb 15, 2018, 9:05:48 AM2/15/18
to TeaVM
Is it possible to convert an Int8Array to a byte array without having the array being copied?

I have tried using a helper method:

@JSBody( params = { "array" }, script = "return array;" )
public static native byte[] convertToArray( @Nonnull final Int8Array array );

The produced JavaScript contains this line:
$bytes = otji_JS_unwrapByteArray($array);

...which creates a copy of the array. Is there a way to work around this?

Thanks
Martin

Alexey Andreev

unread,
Feb 15, 2018, 9:25:16 AM2/15/18
to te...@googlegroups.com
> I have tried using a helper method:
>
> @JSBody( params = { "array" }, script = "return array;" )
> public static native byte[] convertToArray( @Nonnull final Int8Array array );
>
> The produced JavaScript contains this line:
> $bytes = otji_JS_unwrapByteArray($array);
>
> ...which creates a copy of the array. Is there a way to work around this?
>
Right, TeaVM copies arrays. If you want to pass a Java array to
JavaScript function without copying, you can use @JsByRef annotation
(it's only possible to use this annotation with certain types of array).
However, it's impossible to return JavaScript array to Java without
copying. The reason is following: in JVM you have following contract: if
a != b, then modifying a[0] won't affect b[0]. This contract can be used
by optimizations which use alias analysis. In TeaVM, Java arrays aren't
JavaScript arrays, they are wrapper objects around JavaScript arrays
(otherwise it's hard to implement equals/hashCode/clone without
performance overhead). If you return same array from JavaScript twice,
two distinct Java wrappers will be created by TeaVM, which have
different identity. However, modifying the first array will affect the
second one, which violates contract, and thus can break execution after
optimizations. Of course, there are some dirty tricks to make TeaVM
reuse existing wrappers, but these trick *are* dirty and can cause
additional overhead.

As a workaround, you can rewrite you code that returns byte[] array into
code that gets byte[] array and fills it with values, i.e.:

int[] foo() {
    return new byte[] { 1, 2, 3 };
}

can be rewritten to

int foo(int[] consumer) {
   consumer[0] = 1;
   consumer[1] = 2;
   consumer[2] = 3;
   return 3;
}

Also, I strongly suggest profiling your code. Indeed, copying introduces
additional unwilling overhead. The question is: does this overhead
inflict major performance degradation of whole app? What are the hotspot
function shown by your profiler? If functions that copy arrays work
significant time and become a bottleneck, I'll try to help you to solve
the problem and invent some way to reduce overhead.
Reply all
Reply to author
Forward
0 new messages