Search code examples
arraysgwtbytejsni

GWT internal representation of byte[]


I'm working on a GWT project where we occasionally use JSNI to call native JavaScript code. A performance bottleneck seems to be the passing of values back and forth between the Java code and the JavaScript code. Specifically, there's no way to pass a byte[] from the Java side into the JS code and vice versa -- one can only pass int, byte, String etc. but not byte[]. This means we must convert our arrays to strings before calling and then converting back to the byte array representation (byte[] or UInt8Array). This seems unnecessary because GWT's byte[]'s must be have some native JavaScript representation. Does anyone know how GWT represents byte arrays? Changing the GWT compiler in order to allow us direct access to the arrays might be an option.


Solution

  • Almost all numeric types, including byte, are represented as a JavaScript Number (exceptions are boxed types and long). The compiler inserts range checks or 'overflow's as needed to properly emulate expected Java behavior.

    As of GWT 2.6.x (and current GWT trunk), any primitive number array is implemented as a JavaScript Array when compiled. However, when running in Dev Mode, a native Java array is used, so you cannot write JSNI code that simply passes a Java array to JavaScript, and expect it to behave correctly. See http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsJSNI.html#sharing:

    Java array

    opaque value that can only be passed back into Java code

    Even without taking Dev Mode into account, be careful about treating a Java array as if it were a JavaScript one - any future compiler optimization that emits a typed array (as you allude to in your question) could break your code unexpectedly.

    That said, there are ways to create both JavaScript arrays and TypedArrays in your Gwt/Java code so that you can use them from JavaScript. Use the JsArrayNumber type to hold double objects (recall that JS 'Numbers' are effectively Java double), or use the com.google.gwt.typedarrays.shared.Uint8Array class and the rest of the typedarrays package to deal with typed arrays in Java.

    As far as changing the compiler goes, I submitted a patch late last year (https://gwt-review.googlesource.com/4260) that attempted to add this functionality. Two main things prevented this idea from working:

    • First and foremost, other changes happened to the array compilation that broke my patch, multiple times over the course of a month or so. These changes improved general object arrays, so are beneficial, and I see no reason that my patch can't eventually be made to work. However...
    • The patch changed all primitive arrays (except long, since there is no 64bit int typedarray in JS) to be ArrayBuffer based. Somewhat paradoxically, this introduced performance regressions in many cases, since now any small array must be allocated as a typed array, and at the time this was slower in most/all browsers than actually creating the typical JS array object. Several ideas have been discussed to deal with this - a flag to turn this feature globally on/of, an annotation to declare that an instance will be a typed array, a special TypedJavaArrays factory class to create primitive Java arrays that are backed by JS TypedArrays (and so any performance issue is up to the user), etc.

    I'm still pursuing this as time permits, and can't say for sure if it will make GWT 2.7 or a later release - we don't want to slow down all GWT code for the sake of some specialized cases which can refer to the typedarrays package anyway.