JsInterop and indexed types

338 views
Skip to first unread message

rhmoller

unread,
Jan 20, 2016, 3:32:20 PM1/20/16
to GWT Users
Hi

Is there any way of mapping to indexed types via JsInterop. Fx to model Uint8Array

var uint8 = new Uint8Array(2);
uint8[0] = 42;


I have not any luck so far.

/Rene

Kirill Prazdnikov

unread,
Jan 21, 2016, 4:26:25 AM1/21/16
to GWT Users
Yes, this is really needed. 
Also it is needed to have a compiler switch that compiles all java arrays an native typed arrays. 
So that I can write code in Java, and use native platform arrays when needed in Graphics and Sound 
(expect all java arrays to be native typed arrays in JS)

Famous TeaVM also can`t do that, unfortunately. 
TeaVM java array class has a field "data" with the underlying native array, so that each access requires to read that field which dramatically hurts real-time performance.

Jens

unread,
Jan 21, 2016, 5:09:48 AM1/21/16
to GWT Users
Even the old spec wasn't able to do that directly without using a helper method that maps to a one liner of JSNI code [1]. So with the current 1.0 spec you probably need to do

@JsType(isNative = true)
public class UintArray {
  public UintArray(int size) {}
  
  @JsOverlay
  public void set(int index, int value) {
     ArrayLikeJsniUtils.set(this, index, value);
  }

  @JsOverlay
  public int get(int index) {
    return ArrayLikeJsniUtils.get(this, index);
  }
}


Hope that helps. 

-- J.





Alexey Andreev

unread,
Jan 23, 2016, 3:09:50 AM1/23/16
to GWT Users

Famous TeaVM also can`t do that, unfortunately. 
 You are wrong. You can do that via @JSIndexer annotation. 

TeaVM java array class has a field "data" with the underlying native array, so that each access requires to read that field which dramatically hurts real-time performance.
Not really. TeaVM's IR has separate instructions for accessing data field (unwrap) and getting element by an index (get). When converting from JVM bytecodes, every occurrence of AALOAD/IALOAD/... is represented by these conseqential instructions. Now consider this Java code:

int a = array[x];
int b = array[y];

We get the following IR:

array1 = unwrap(array);
a = get(array1, x);
array2 = unwrap(array);
b = get(array2, y);

When GVN scans this sequence, it realizes that array1 and array2 are really the same and eliminates array2:

array1 = unwrap(array);
a = get(array1, x);
b = get(array1, y);

Unfortunately, GVN is incapable of handling loops. TeaVM does not perform LICM yet, but it is possible to implement. LICM should solve the issue.

Also, did you try to write benchmarks before claiming that wrapper slows down performance? V8 performs sophisticated performance optimizations. There is a great chance that V8 is capable to recognize an eliminate unnecessary access to data field.

Kirill Prazdnikov

unread,
Jan 27, 2016, 5:13:50 AM1/27/16
to GWT Users


On Saturday, January 23, 2016 at 11:09:50 AM UTC+3, Alexey Andreev wrote:

Famous TeaVM also can`t do that, unfortunately. 
 You are wrong. You can do that via @JSIndexer annotation. 

Sorry for by bad english. 
I meant a different thing.

Consider

class A { 
  int [] computeInJava() {...};
}

class B {
  native void aJsMethod(int data[]) /*-   expect reference to original Int32Array in the argument   -*/;
 }

b.aJsMethod(a.computeInJava());

It is not possible to do such things neither in GWT, nor in TeaVM. 
Not TeaVM, not GWT does not allow passing java arrays as native arrays to native JS code without making a copy.

Also, did you try to write benchmarks before claiming that wrapper slows down performance? V8 performs sophisticated performance optimizations. 

You are very right, there is no point talking about performance without real numbers.
I will reply when I write a test and have a results.

Thanks 
 

Alexey Andreev

unread,
Jan 27, 2016, 12:43:21 PM1/27/16
to GWT Users, te...@googlegroups.com

Sorry for by bad english. 
I meant a different thing.

Oh, now I see. Well, making Java array equal to JavaScript array is not an only solution for passing direct reference to an array. TeaVM could have a method to "unwrap" array, giving a native code reference to `data` field. There is one, but it is like "unsafe" in Oracle JDK: it is not documented and it's not guaranteed to remain its API in future versions. It should look like this:

public static Int8Array unwrapArray(byte[] array) {
    return Platform.getPlatformObject(array);
}
@JSBody(params = "wrapper", script = "return wrapper.data;")
private static native Int8Array doUnwrap(JSObject wrapper);

The magic is in undocumented Platform class, getPlatformObject particulary. It gets a Java object and returns it as JSObject. But do it on your own risk. Also, it's possible to corrupt application by assigning to the array something that does not fit in byte type (a floating point number or a string) or by changing the length of the array.

As for avoiding wrapper class. It's nearly impossible in general, since Java arrays are Java objects as well. Consider the following:

void foo(Object obj) {
    System.out.println(obj.toString());
}
void bar() {
    foo(new int[] { 1, 2, 3 });
}

How could TeaVM implement it without wrapper?

It is possible though to avoid negative effects of wrappers in certains cases, first, as I said, by eliminating unwrap operations when possible, and, second, performing some kind of escape analysis.

Note that the reverse operation (converting JavaScript array to Java array) is impossible in TeaVM by design. TeaVM performs global analysis of your code and for each variable (in terms of SSA) determines its possible types. It's impossible in general case to predict in compile time what actual type method like this may return:

Object wrapPlatformObject(JSObject obj);

I'm not sure how GWT actually works, but I suppose it does something similar, therefore it most likely you will fail with GWT as well. However, it's possible to hardcode additional methods to Platform class that convert JSArray to primitive arrays. You can open an issue if you really are going to use TeaVM for such purpose.

There are JSO wrappers in TeaVM and JSNI wrappers in GWT for TypedArrays. Why don't you use them directly to boost performance?

Kirill Prazdnikov

unread,
Jan 27, 2016, 2:53:58 PM1/27/16
to google-we...@googlegroups.com, te...@googlegroups.com
Hi Alex, 
really thanks for excellent answers. 

I'm writing portable code. This is the reason why I can not use JS TypedArrays directly.
My code must work in GWT, RoboVM and Android.

I'm looking for writing code in Java once and run it with best possible efficiency on all platforms.

In RoboVM platform we have transparent marshalling of java arrays to native layer 
  int[] -> int *, char [] -> short *, e,t,c  String -> utf8 char *
In Android we use Get\Release PrimitiveArrayCritical for such needs to get underlying pointer in native. No copies. 

We don't have something similar on web. Very unfortunately. 
This is a true reason why I think this is urgent and why I'm asking of it.

As a result, we must implement all computations in two ways
  - in Java for native compilers (RoboVM + Android)
  - in JS for Web

As for avoiding wrapper class. It's nearly impossible in general, since Java arrays are Java objects as well. Consider the following:

This is a goal. And it is nice solve it.
 
Thanks
 -Kirill

    

--
You received this message because you are subscribed to a topic in the Google Groups "GWT Users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/google-web-toolkit/YOWINYAoCrI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to google-web-tool...@googlegroups.com.
To post to this group, send email to google-we...@googlegroups.com.
Visit this group at https://groups.google.com/group/google-web-toolkit.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages