[TIMOB-12802] Android: Reduce JNI bridge calls used for string,object hashes
GitHub Issue | n/a |
---|---|
Type | Story |
Priority | Low |
Status | Open |
Resolution | Unresolved |
Affected Version/s | Release 3.0.0 |
Fix Version/s | n/a |
Components | Android |
Labels | n/a |
Reporter | Blain Hamon |
Assignee | Unknown |
Created | 2013-02-21T08:08:37.000+0000 |
Updated | 2018-02-28T20:03:39.000+0000 |
Description
In investigating android performance hits, I noticed a LOT of calls to the JNI bridge in order to determine and convert between Java and v8 data types.
In adding JNI-dedicated functionality to KrollDict, we can significantly reduce the bridge hits with 5 methods, an enum, and an array:
An enum of data types, one of which is a meta-type to indicate 'done'
An array of strings of common values and keys. Index 0 is NULL.
On C++, there may also be a sparse lookup table to allow for quick conversion from a string into an array index.
long getNextJNIEntry()
On first call, it stashes on the Java side an array of keys and returns the first 'entry' for that key. Each subsequent call goes to the next key and returns the 'entry' for that key. After the last key is used, the 'done' meta-type is returned. This removes the need to get a key count or track indexes.
The returned long maps to three values that are maskable:
0xFFFF FFFF 0000 0000
is value if int type, value string index if in string table
0x0000 0000 FFFF 0000
is key string index if in table (0 otherwise)
0x0000 0000 0000 FFFF
is data type
As such, this can shortcut many values as well as remove the need for many keys or string conversions, as well as remove all introspection bridge hits.
String getJNIKey()
Object getJNIObject()
double getJNIDouble()
These fetch values from the current 'entry', the nature of which is dependent on the data type. For example, date actually uses the getDouble as milliseconds.
void putJNIValue(int keyInt, String keyString, int dataType, double valueDouble, Object valueObject);
Defaults are 0/null. If keyInt is nonzero, keyString is ignored (should be null) and the lookup is used. The reason for having a single setter is that it reduces the number of method signatures needed, and the combinatorics of value/keys would require 4 methods instead.
In doing it this way, we should be able to reduce the number of JNI bridge calls used in converting values to and from Java by at least an order of magnitude.
Addendum: The same optimizations can be tooled to method call arrays and to event type strings.
Addendum addendum: Before I go to sleep and forget it, this does not allow for reentrancy, but that's probably alright. After all, were a hash to contain itself directly or indirectly, our current conversion would be caught in an infinite loop.
Also, look further into V8 and what string format is the fastest. Considering the conversion is between Java and v8, it may not ever live as char*.
Those playing the home game, https://github.com/BlainHamon/titanium_mobile/compare/timob-12802
Based on comments, it appears this may not actually be a bottleneck. Deferring.