Comments (3)
You are right that putMember()
and removeMember()
are not overly fast. The root of the problem is that they are generic (work for any property/member) and as such cannot specialize itself well. I suggest you to use evaluation of an appropriate script instead. A script that contains a separate assignment for each binding can specialize each assignment and can be much faster. You can imagine that each assignment remembers where to write the value while the general method has to find the right place with each invocation.
So, you can rewrite your bindAll
to something like
StringBuilder sb = new StringBuilder();
variables.forEach((name, value) -> {
sb.append(name).append("=variables['").append(name).append("'];");
});
String script = sb.toString();
BiConsumer<Evaluator, String> bindAll =
(evaluator, snippet) -> {
evaluator.bind("variables", ProxyObject.fromMap(variables));
evaluator.eval(script);
};
There is a similar problem with the repeated invocation of removeMember()
in close()
. You can rewrite it to
StringBuilder sb = new StringBuilder();
bindings.getMemberKeys().forEach(s -> sb.append(s).append("=undefined;"));
eval(sb.toString());
You may wonder why I don't suggest to use delete
i.e.
bindings.getMemberKeys().forEach(s -> sb.append("delete ").append(s).append(';'));
That's because I found that we do not specialize well the delete performed on a global object. I have fixed this bug already, but I don't expect you to use the latest development build. So, the delete
variant is (unfortunately) slow in the latest release still.
In fact, it may be redundant to do anything in close()
. If you decide to write all values for every script then you can keep close()
empty. Actually, writing the same set of properties/members may be a good idea because it leads to the same set of "hidden classes/shapes" of the global object. So, the locations (where the value should be written) are kept consistent for all scripts.
Finally, I noticed that your example runs in interpreter mode only (without runtime compilation). I hope that this is just to keep the example simple. If you care about performance then you should run with runtime compilation, of course.
When I applied the mentioned suggestions then the execution time of your example decreased from ~30s to ~0.35s on my machine.
from graaljs.
Thank you!
Using a script to bind the values has improved performance dramatically. I've modified my code (and committed to the repo) to time 300,000 evaluations (originally 30,000) and to use runtime compilation and execution after warmup is - for me - ~1.5 seconds with GraalJS vs 2 seconds with Rhino.
The reason I was using interpreter only mode is that I'm only able to execute with compilation enabled when running from my IDE. With an uber jar I get an exception saying: No language and polyglot implementation was found on the class-path
but that was lower down my list of things to solve than bindings performance - guess it's now risen to the top!
$ mvn clean package &&
> "$JAVA_HOME/bin/java" -Dpolyglotimpl.TraceClassPathIsolation=true -jar target/binding-test.jar
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------< jon.test:js-perf-test >------------------------
[INFO] Building js-perf-test 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
:
:
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.939 s
[INFO] Finished at: 2024-01-12T10:57:43Z
[INFO] ------------------------------------------------------------------------
[class-path-isolation] Start polyglot class-path isolation
[class-path-isolation] Collected 1 class-path entries from java.class.path system property
[class-path-isolation] Class-path entry: target\binding-test.jar
[class-path-isolation] No truffle-api and/or polyglot found on classpath.
Exception in thread "main" java.lang.IllegalStateException: No language and polyglot implementation was found on the class-path. Make sure at last one language is added on the class-path. If you put a language on the class-path and you encounter this error then there could be a problem with isolated class loading. Use -Dpolyglotimpl.TraceClassPathIsolation=true to debug class loader islation problems. For best performance it is recommended to use polyglot from the module-path instead of the class-path.
at org.graalvm.polyglot.Engine$PolyglotInvalid.noPolyglotImplementationFound(Engine.java:2071)
at org.graalvm.polyglot.Engine$PolyglotInvalid.createHostAccess(Engine.java:2057)
at org.graalvm.polyglot.Engine$PolyglotInvalid.createHostAccess(Engine.java:2023)
at org.graalvm.polyglot.Engine$Builder.build(Engine.java:753)
at org.graalvm.polyglot.Engine.create(Engine.java:346)
at jon.test.js.LazyBinding.graalEvaluatorFactory(LazyBinding.java:85)
at jon.test.js.LazyBinding.main(LazyBinding.java:296)
from graaljs.
@iamstolis Thanks for your advice on all of this, it took me longer to circle back to it than I had hoped it would.
I ended up dealing with "unbinding" by evaluating:
Object.keys(globalThis).forEach(k=>globalThis[k]=undefined)
From your comment, it seems that using delete may be the way to go in the future; however, using delete currently seems to have no effect (the variable remains in the bindings map with its value unchanged).
(Incidentally, the issue with running in non-interpreted mode was resolved by moving to the 21.0.2 VM)
from graaljs.
Related Issues (20)
- Get (heap) memory usage information
- "ab".split(/(?:ab)*/) crashes graaljs HOT 1
- Losing double type when returning 1.0 from JS HOT 1
- Polyglot version compatibility check failed on GraalVM for JDK 22 Community 22.0.0
- Expose wrapPromise and Thenable in the GraalJS public API
- Polyglot options not working consistently with JS HOT 2
- No org.graalvm.js:js version 24.0.0 on Maven Central? HOT 4
- No language for id regex found, Supported languages are: [js] HOT 2
- Support for Node.js `http` and `fs` modules in GraalJS HOT 1
- Can not resolve NodeJS Promise Concurrently from Java Side HOT 6
- GraalJS should support Ahead-of-Time(AOT) compilation to Native binary like GraalPy.
- nodejs c-addon seems to leak HOT 1
- Provide the WinterCG minimum common API HOT 1
- Does not find values from the global context HOT 4
- 'GraalJSEngineFactory could not be instantiated' on JDK22 HOT 1
- Extending a Java class in Javascript without using Java.extend HOT 4
- Add instructions for enabling usage of Java
- Wildcards in classpath do not work anymore HOT 1
- "10".match(/a*/g) crashes graaljs HOT 3
- Graal JS Script Engine is very slow compared to Rhino HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from graaljs.