-
Hi everybody. I'm implementing my pet project using TeaVM. During implementation I found that some methods/classes could lead to final code size increase or performance degradation.
Example of performance degradation is implicit usage of long in Double.toString. As I showed in #560 it works 3-5 times slower than same float/int case. Now, here is the question: is it possible in TeaVM compiler identify specific places where some class/method is implicitly used. Currently I'm doing this by analisyng generated JS. While I am able to identify that regexps are not used, but it seems that longs are implicitly used somewhere, but I can't identify the exact place. Is it possible to intercept compilation somehow and find usages of specific class/method/primitive? |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments
-
There's no way to "identify" such methods, but there's a way to remove them, triggering TeaVM errors. See ElementFilter interface. Implement it and use ServiceLoader convention to register it. From implementation return |
Beta Was this translation helpful? Give feedback.
-
Hi @konsoletyper |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
First part is easy with finding methods. Look through patterns like lj_String_valueOf in non-minified JS code. Sometimes it's in method pool, so find corresponging string in method pool and find what invokes such function. Second part was more complicated. Still, I managed to find possible sources of long usage. Example 1. private record RGBAColor(int r, int g, int b, double a) {} Yes, here long is used. Because autogenerated hashCode uses Double.hashCode and therefore public static int hashCode(double d) {
long h = doubleToLongBits(d);
return (int) (h >>> 32) ^ (int) h;
} There could be microoptimization with avoiding intermediate Long by the way. Example 2. @EqualsAndHashCode
public class TableContent {
private String[][] table;
} HashCode part somewhere deep would include public static int deepHashCode(Object[] a) {
if (a == null) {
return 0;
}
int hash = 1;
for (int i = 0; i < a.length; ++i) {
Object el = a[i];
int h;
if (a[i] instanceof boolean[]) {
h = hashCode((boolean[]) el);
} else if (a[i] instanceof byte[]) {
h = hashCode((byte[]) el);
} else if (a[i] instanceof short[]) {
h = hashCode((short[]) el);
} else if (a[i] instanceof char[]) {
h = hashCode((char[]) el);
} else if (a[i] instanceof int[]) {
h = hashCode((int[]) el);
} else if (a[i] instanceof long[]) {
h = hashCode((long[]) el);
} else if (a[i] instanceof float[]) {
h = hashCode((float[]) el);
} else if (a[i] instanceof double[]) {
h = hashCode((double[]) el);
} else if (a[i] instanceof Object[]) {
h = deepHashCode((Object[]) el);
} else {
h = Objects.hashCode(el);
}
hash = 31 * hash + h;
}
return hash;
} and code presend for long will be automatically included. Example 3. double length = 5.0;
String explanation = "You need to run " + length + " more kilometers" would result in long usage. Example 4. public interface TSpliterator<T> {
...
long estimateSize();
... here it appears. Fortunately in current TeaVM implementation the only place where it's used is Stream.toArray conversion.
There could be more examples actually. Still, in my case that were all. After refactoring and getting rid of such places, I have a project with 3,6 MB uncompressed and 870 KiB compressed JS which completely avoids using longs. |
Beta Was this translation helpful? Give feedback.
First part is easy with finding methods. Look through patterns like lj_String_valueOf in non-minified JS code. Sometimes it's in method pool, so find corresponging string in method pool and find what invokes such function.
Second part was more complicated. Still, I managed to find possible sources of long usage.
Example 1.
Yes, here long is used. Because autogenerated hashCode uses Double.hashCode and therefore
There could be microoptimization with avoiding intermediate Long by the way.
We can get rid of lo…