mozilla / rhino

Rhino is an open-source implementation of JavaScript written entirely in Java
https://rhino.github.io
Other
4.12k stars 848 forks source link

Rhino for Android #282

Closed F43nd1r closed 3 years ago

F43nd1r commented 8 years ago

I am the creator of the wrapper for Rhino on Android. It is generally working well. However, there are ~80 failing Tests that I either don't know what they should do or don't know how to fix.

Is there anybody with some insight on Rhino and its tests who would be willing to look at the tests run on an Android device? (I can give precise directions on how to setup the testing environment if needed.)

Note: I posted about some of these tests in #211, but did not receive any answer.

TheDiamondYT1 commented 7 years ago

Just include rhino in your project using gradle and it works...

F43nd1r commented 7 years ago

@TheDiamondYT1 But only in interpreted mode, and JavaAdapter can't be used.

AlexTrotsenko commented 7 years ago

I tried to run sample project of rhino-android with quickly found algorithm for Pi calculation. And I was surprised by the performance improvement: with setOptimizationLevel(1) it's 3 time faster to execute JS comparing to setOptimizationLevel(-1), which is only possible option now! (E.g. compilation vs interpretation.)

F43nd1r commented 7 years ago

with setOptimizationLevel(1) it's 3 time faster to execute JS comparing to setOptimizationLevel(-1)

@AlexTrotsenko where did you get that number from? I've just tested it with the Pi computation. For me interpreted mode is faster until about 10.000 iterations. After about 100.000 iterations compiled mode goes down to about 70% of interpreted mode, but I can't reach multitudes of 2, let alone 3.

F43nd1r commented 7 years ago
Optimization Compilation Execution Sum
-1 3ms (100%) 120744ms (100%) 120747ms (100%)
0 106ms (3533%) 94754ms (78%) 94860ms (78%)
1 83ms (2766%) 92963ms (76%) 93046ms (77%)

These are my results for 10.000.000 iterations

AlexTrotsenko commented 7 years ago

Hello @F43nd1r , thanks for reply. Following is my data. I will push my code soon.

With optimisation:

 E/MainActivity: 1st invocation & compilation took: 403, JS did 1000 iterations optimization level 1, result: 3.141093153121447
 E/MainActivity: Average execution of 'compiled' JS took: 4, JS did 1000 iterations, Java repeatTimes: 100
 E/MainActivity: Average execution of 'compiled' JS took: 3, JS did 1000 iterations, Java repeatTimes: 100
 E/MainActivity: Average execution of 'compiled' JS took: 3, JS did 1000 iterations, Java repeatTimes: 100
 E/MainActivity: Average execution of 'compiled' JS took: 37, JS did 10000 iterations, Java repeatTimes: 100
 E/MainActivity: Average execution of 'compiled' JS took: 37, JS did 10000 iterations, Java repeatTimes: 100
 E/MainActivity: Average execution of 'compiled' JS took: 37, JS did 10000 iterations, Java repeatTimes: 100

Without optimisation:

 E/MainActivity: 1st invocation & compilation took: 33, JS did 1000 iterations optimization level -1, result: 3.141093153121447
 E/MainActivity: Average execution of 'compiled' JS took: 16, JS did 1000 iterations, Java repeatTimes: 100
 E/MainActivity: Average execution of 'compiled' JS took: 16, JS did 1000 iterations, Java repeatTimes: 100
 E/MainActivity: Average execution of 'compiled' JS took: 15, JS did 1000 iterations, Java repeatTimes: 100
 E/MainActivity: Average execution of 'compiled' JS took: 156, JS did 10000 iterations, Java repeatTimes: 100
 E/MainActivity: Average execution of 'compiled' JS took: 157, JS did 10000 iterations, Java repeatTimes: 100
 E/MainActivity: Average execution of 'compiled' JS took: 156, JS did 10000 iterations, Java repeatTimes: 100
AlexTrotsenko commented 7 years ago

@F43nd1r Here is the source code of the my changes. The important part is that I do compile and re-use compiled Function comparing to running evaluate each time. As far as I see evaluate internally does compile, but do not saves it anywhere, so I do it manually in this example.

AlexTrotsenko commented 7 years ago

Source code: https://github.com/AlexTrotsenko/RhinoCompiledTest

AlexTrotsenko commented 6 years ago

If someone decide to add support for "compiled" mode: looks like Byte Buddy supports both Java and Android byte code generation - thus it could be a good option for Rhino as well. Also, far as I see, Hibernate also decided to migrate to it.

F43nd1r commented 6 years ago

@AlexTrotsenko I've looked at what Bytebuddy does under the hood and its no different to what my library does. So, I believe using bytebuddy wouldn't give any different results.

Rhino is good at generating bytecode (for its usecases), so unless a library directly generates dex code, I'd be surprised to see any significant performance increase.

AlexTrotsenko commented 6 years ago

@F43nd1r you are right, there might be no big difference in performance.

I suggested Bytebuddy because it seams like good candidate for unification of java code, which generates new byte code for both Java and Android. This way this code could be merged back to Rhino project.

Also I have issues, when I re-start or re-install my app with new changes. You can use my project above for testing. Following is 2 examples of recent exceptions:

W/System.err: UNEXPECTED TOP-LEVEL EXCEPTION:
W/System.err: java.util.zip.ZipException: Duplicate entry name: org/mozilla/javascript/gen/_hello_world__1.class
W/System.err:     at java.util.zip.ZipFile.readCentralDir(ZipFile.java:452)
W/System.err:     at java.util.zip.ZipFile.<init>(ZipFile.java:175)
W/System.err:     at java.util.zip.ZipFile.<init>(ZipFile.java:131)
W/System.err:     at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:244)
W/System.err:     at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)
W/System.err:     at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)
W/System.err:     at com.android.dx.command.dexer.Main.processOne(Main.java:672)
W/System.err:     at com.android.dx.command.dexer.Main.processAllFiles(Main.java:574)
W/System.err:     at com.android.dx.command.dexer.Main.runMonoDex(Main.java:311)
W/System.err:     at com.android.dx.command.dexer.Main.run(Main.java:277)
W/System.err:     at com.faendir.rhino_android.AndroidClassLoader.dexJar(AndroidClassLoader.java:103)
W/System.err:     at com.faendir.rhino_android.AndroidClassLoader.defineClass(AndroidClassLoader.java:64)
W/System.err:     at org.mozilla.javascript.optimizer.Codegen.defineClass(Codegen.java:130)
W/System.err:     at org.mozilla.javascript.optimizer.Codegen.createFunctionObject(Codegen.java:101)
W/System.err:     at org.mozilla.javascript.Context.compileImpl(Context.java:2532)
W/System.err:     at org.mozilla.javascript.Context.compileFunction(Context.java:1517)
W/System.err:     at org.mozilla.javascript.Context.compileFunction(Context.java:1506)
W/System.err:     at com.thinotest.alex.rhinocompiledtest.MainActivity.computePiByJs(MainActivity.java:93)
W/System.err:     at com.thinotest.alex.rhinocompiledtest.MainActivity.access$000(MainActivity.java:29)
W/System.err:     at com.thinotest.alex.rhinocompiledtest.MainActivity$1$1.run(MainActivity.java:58)
W/System.err:     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
W/System.err:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269)
W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
W/System.err:     at java.lang.Thread.run(Thread.java:818)
W/System.err: 1 error; aborting

and followed by

E/MainActivity: JS failed 
    com.faendir.rhino_android.AndroidClassLoader$FatalLoadingException: Failed to define class
        at com.faendir.rhino_android.AndroidClassLoader.defineClass(AndroidClassLoader.java:66)
        at org.mozilla.javascript.optimizer.Codegen.defineClass(Codegen.java:130)
        at org.mozilla.javascript.optimizer.Codegen.createFunctionObject(Codegen.java:101)
        at org.mozilla.javascript.Context.compileImpl(Context.java:2532)
        at org.mozilla.javascript.Context.compileFunction(Context.java:1517)
        at org.mozilla.javascript.Context.compileFunction(Context.java:1506)
        at com.thinotest.alex.rhinocompiledtest.MainActivity.computePiByJs(MainActivity.java:93)
        at com.thinotest.alex.rhinocompiledtest.MainActivity.access$000(MainActivity.java:29)
        at com.thinotest.alex.rhinocompiledtest.MainActivity$1$1.run(MainActivity.java:58)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
        at java.util.concurrent.FutureTask.run(FutureTask.java:237)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
        at java.lang.Thread.run(Thread.java:818)
     Caused by: java.io.IOException: No original dex files found for dex location /data/user/0/com.thinotest.alex.rhinocompiledtest/cache/classes/dex-234972975.jar
        at dalvik.system.DexFile.openDexFileNative(Native Method)
        at dalvik.system.DexFile.openDexFile(DexFile.java:295)
        at dalvik.system.DexFile.<init>(DexFile.java:111)
        at dalvik.system.DexFile.loadDex(DexFile.java:151)
        at com.faendir.rhino_android.AndroidClassLoader.dexJar(AndroidClassLoader.java:104)
        at com.faendir.rhino_android.AndroidClassLoader.defineClass(AndroidClassLoader.java:64)
        at org.mozilla.javascript.optimizer.Codegen.defineClass(Codegen.java:130) 
        at org.mozilla.javascript.optimizer.Codegen.createFunctionObject(Codegen.java:101) 
        at org.mozilla.javascript.Context.compileImpl(Context.java:2532) 
        at org.mozilla.javascript.Context.compileFunction(Context.java:1517) 
        at org.mozilla.javascript.Context.compileFunction(Context.java:1506) 
        at com.thinotest.alex.rhinocompiledtest.MainActivity.computePiByJs(MainActivity.java:93) 
        at com.thinotest.alex.rhinocompiledtest.MainActivity.access$000(MainActivity.java:29) 
        at com.thinotest.alex.rhinocompiledtest.MainActivity$1$1.run(MainActivity.java:58) 
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423) 
        at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269) 
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
        at java.lang.Thread.run(Thread.java:818) 

P.S. I tried once again performance of compiled with not-compiled Rhino, now for calculating of fibonacci numbers. This time for 10000 iteration I had difference of 2.9 sec vs 2.3 sec.

F43nd1r commented 6 years ago

You seem to be using an old version of my library. Try with 1.5

AlexTrotsenko commented 6 years ago

@F43nd1r you are right, I was using 1.4, but it's strange as 1.4 was last version, which I was able to see in both maven and github page yesterday.

Now I run the app on Pixel 2 XL, Android 8.1 and got following exception on re-start:

12:04:37.858 W/System.err: UNEXPECTED TOP-LEVEL EXCEPTION:
12:04:37.858 W/System.err: java.util.zip.ZipException: invalid CEN header (duplicate entry)
12:04:37.858 W/System.err:     at java.util.zip.ZipFile.open(Native Method)
12:04:37.858 W/System.err:     at java.util.zip.ZipFile.<init>(ZipFile.java:235)
12:04:37.858 W/System.err:     at java.util.zip.ZipFile.<init>(ZipFile.java:149)
12:04:37.858 W/System.err:     at java.util.zip.ZipFile.<init>(ZipFile.java:163)
12:04:37.858 W/System.err:     at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:244)
12:04:37.858 W/System.err:     at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)
12:04:37.858 W/System.err:     at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)
12:04:37.859 W/System.err:     at com.android.dx.command.dexer.Main.processOne(Main.java:672)
12:04:37.859 W/System.err:     at com.android.dx.command.dexer.Main.processAllFiles(Main.java:574)
12:04:37.859 W/System.err:     at com.android.dx.command.dexer.Main.runMonoDex(Main.java:311)
12:04:37.859 W/System.err:     at com.android.dx.command.dexer.Main.run(Main.java:277)
12:04:37.859 W/System.err:     at com.faendir.rhino_android.AndroidClassLoader.dexJar(AndroidClassLoader.java:103)
12:04:37.859 W/System.err:     at com.faendir.rhino_android.AndroidClassLoader.defineClass(AndroidClassLoader.java:64)
12:04:37.859 W/System.err:     at org.mozilla.javascript.optimizer.Codegen.defineClass(Codegen.java:130)
12:04:37.859 W/System.err:     at org.mozilla.javascript.optimizer.Codegen.createFunctionObject(Codegen.java:101)
12:04:37.859 W/System.err:     at org.mozilla.javascript.Context.compileImpl(Context.java:2532)
12:04:37.859 W/System.err:     at org.mozilla.javascript.Context.compileFunction(Context.java:1517)
12:04:37.859 W/System.err:     at org.mozilla.javascript.Context.compileFunction(Context.java:1506)
12:04:37.859 W/System.err:     at com.example.alex.quickapp.FibonacciCalculator.runFibonacciRhino(FibonacciCalculator.java:209)
12:04:37.859 W/System.err:     at com.example.alex.quickapp.TestActivity.lambda$runPerfTest$2$TestActivity(TestActivity.java:193)
12:04:37.859 W/System.err:     at com.example.alex.quickapp.TestActivity$$Lambda$2.run(Unknown Source:0)
12:04:37.859 W/System.err:     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457)
12:04:37.859 W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:266)
12:04:37.859 W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
12:04:37.859 W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
12:04:37.859 W/System.err:     at java.lang.Thread.run(Thread.java:764)
12:04:37.860 W/System.err: 1 error; aborting
12:04:37.860 W/zygote: Opening an oat file without a class loader. Are you using the deprecated DexFile APIs?
12:04:37.860 E/zygote: Could not get the realpath of dex_location /data/user/0/com.example.alex.quickapp/cache/classes/dex-213651216.jar: No such file or directory

Very similar is on Nexus 5, Android 6.0.1

 UNEXPECTED TOP-LEVEL EXCEPTION:
 java.util.zip.ZipException: Duplicate entry name: org/mozilla/javascript/gen/fibonacci_1.class
     at java.util.zip.ZipFile.readCentralDir(ZipFile.java:452)
     at java.util.zip.ZipFile.<init>(ZipFile.java:175)
     at java.util.zip.ZipFile.<init>(ZipFile.java:131)
     at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:244)
     at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)
     at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)
     at com.android.dx.command.dexer.Main.processOne(Main.java:672)
     at com.android.dx.command.dexer.Main.processAllFiles(Main.java:574)
     at com.android.dx.command.dexer.Main.runMonoDex(Main.java:311)
     at com.android.dx.command.dexer.Main.run(Main.java:277)
     at com.faendir.rhino_android.AndroidClassLoader.dexJar(AndroidClassLoader.java:103)
     at com.faendir.rhino_android.AndroidClassLoader.defineClass(AndroidClassLoader.java:64)
     at org.mozilla.javascript.optimizer.Codegen.defineClass(Codegen.java:130)
     at org.mozilla.javascript.optimizer.Codegen.createFunctionObject(Codegen.java:101)
     at org.mozilla.javascript.Context.compileImpl(Context.java:2532)
     at org.mozilla.javascript.Context.compileFunction(Context.java:1517)
     at org.mozilla.javascript.Context.compileFunction(Context.java:1506)
     at com.example.alex.quickapp.FibonacciCalculator.runFibonacciRhino(FibonacciCalculator.java:209)
     at com.example.alex.quickapp.TestActivity$4.run(TestActivity.java:204)
     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
     at java.lang.Thread.run(Thread.java:818)
 1 error; aborting
F43nd1r commented 6 years ago

This is still not 1.5. com.faendir.rhino_android.AndroidClassLoader is not present in 1.5, but it is in your logs.

it's strange as 1.4 was last version, which I was able to see in both maven and github page yesterday.

Maven sync failed on 1.5 upload, which I noticed yesterday. Beforehand, 1.5 was only on bintray.

filozirka commented 6 years ago

I'm sorry for beeing uninformed, but I'm not a programmer, just want to use Rhino to draw some designs and machine parts. Or is this some other, different Rhino? If this is the right Rino, how can I install it? Is there an Apk for Android?

F43nd1r commented 6 years ago

@filozirka this is a javascript engine, you are probably talking about rhino3d.com, which is not related to this at all.

p-bakker commented 3 years ago

I looked through this and the only actionable item left in this case is answering the question what your failing tests mean, details of which you posted in #211

As the questions is also in #211, I'm closing this case