Well, at least one person asked me to post or blog something if I found a way to limit how much processing any given script is allowed.
So I'm posing this to provide one such solution (it's a hack, but it works well for my particular need). Perhaps the info will be useful to others as well. The solution/workaround for those interested: ---------------------------------------------------------- Based on the upcoming Rhino version 1.7R2 (release candidate 1 is currently available, a link is in this forums archives), there are some new features around the continuation capabilities that allow you to capture and resume a continuation outside the JS environment. The limitation is that the continuation must be initiated from within a JS function (it can be a Native Java Method as in the provided test example ContinuationsApiTest class). So the trick I've come up with (mind you, I'm quite sure that there are cleaner ways to implement this, I just don't know them nor want to make the numerous changes to the base code that would be required) is to inject a call to a JS function that will initiate the continuation. I've done this with some code in the interpreter that watches for line breaks (those appear to be safe places to inject a function call) and also watches for a Boolean condition to be set (in my case I'm counting instructions and breaking when the # of instructions executed exceeds a threshold). At that point, instead of continuing execution of the compiled bytecode, I inject 5 operations, and allow them to process in sequence (the same 5 operations that would be used to make a JS function call), then restore the registers I used to their original state at the end. I've included the source that I changed Interpreter.class. It's set up to call the same object/function used in the ContinuationsApiTest class. There are only 2 areas in the code that I updated, you can identify them by searching for the word "hack" added in comments anywhere I made changes. The first is the code in the interpretLoop to inject the function when appropriate, and the other is in the compiler to force it to include line changes even if the script doesn't have any newline characters (this is just to avoid a script stripping all newlines in an attempt to bypass this mechanism, and will have the side effect of calling the onLineChange method in the debugger multiple times for the same source line in some cases). As part of my particular case I am executing many different scripts, each in their own scope, and each time I resume a particular scope/script I have a debugger object and contextData object associated with that scope. I set the debugger and contextData object that I've associated with that scope each time I resume processing a new script (Context.SetDebugger(myDebugger, myContextDataObj)). The Context Data object that is passed in contains the variables used by the workaround code in the interpertLoop, so it's important to make sure that the contextData object stays with the particular scope. As far as performance, I've been able to call a bit over 2000 scripts, have each of them performing a resume and suspend operation after executing their allotment of ~1000 bytecode operations, then perform a few other minor operations, all in 1 second on average using a laptops 1.9 ghz single cpu core processor. I am pretty happy with the scalability of JS continuations. Anyway, if someone tries this out I'd be happy to explain in more detail. If you want to play with this you should start with the included ContinuationsApiTest.class and tweak that example with this little hack in place to see it working. Dave p.s. A big thanks to everyone contributing to Rhino!! And for adding the new continuation functionality, that was a homerun for me!
_______________________________________________ dev-tech-js-engine-rhino mailing list [email protected] https://lists.mozilla.org/listinfo/dev-tech-js-engine-rhino
