I got a question regarding C++ Object & Javascript Object life cycle mis-synchronization and hope here your gurus could help me out.
Specifically, I am embedding SpiderMonkey in my C++ program. I am not sure if my approach is right or not. What I am doing is like
(1) C++ program loads a Javascript file and call an entry function.
(2) In the entry function, some C++ functions are called to initialize the program. During these calls, some C++ objects will be created.
(3) Based on user interaction, corresponding script function will be called as event handler.
This approach works, but with one problem (there could be unidentified more :)
That is,
In my JS event handler function, I need to fetch a C++ object to the Javascript context and call it member function. For this, in my C++ fetching function, I check if its corresponding JS peer object has been created or not. If not, I use JS_NewObject to create one and return it. Then the JS function could call native function on it.
The problem is that in some cases, the result of such native function call will lead the death of the C++ object. However, I can not find a way to notify the JS context to delete its JS peer object too. I failed to find a JSAPI function to do so.
In my current program, all the JS objects created using JS_NewObject are destroyed when finally the JS runtime is destroyed.
I guess this has something do with SipderMonkey's "garbage collection". But I have not found a good guide yet. Many thanks for any suggestionto
JS is a GC'd environment so you can't simply "delete" a GC allocated object. There are basically 2 options you can take:
Make your C++ object be dependent on the JS wrapper object, if you were using refcounting for instance you would increment the C++ object's ref when you created a wrapper, and decrement the ref in the wrapper objects finalizer.
When you destroy the C++ object, fetch the wrapper object (if it exists) as clear the reference to the C++ object. All your callbacks will now need to null check prior to using the C++ object, but you won't crash (you could throw a JS exception in response perhaps?)
In most cases option 1 is what users expect.
I'd point to the required API but i don't know the SM API (I know the JSC API instead, but they same concepts apply)
Related
Note: I now believe this question was based on assumptions about the javascript specification which are actually implementation specific.
I am attempting to build a runtime debugging hook system for a complex dynamic javascript application. A series of choices have let me to choose to use javascript Proxy and Reflect metaprogramming constructs to interpose function calls in the application I am debugging, wrapping all incoming functions arguments in Proxy/Reflect constructs.
The approach involves replacing high level application functions with Proxies and using traps and handlers to provide debugging functionality, ultimately passing arguments through to the application in a transparent way. All property get/set and function executions act as normal. However, by wrapping all objects and functions in Proxies allows tracing of the runtime.
I am installing this hook system into Chrome.
(Note: Please do NOT provide an answer suggesting a different methodology for debugging hooks - options have been evaluated extensively.)
The issue is that some javascript methods in the application invoke closures and pass "this" parameters. When "this" parameters are wrapped in a Proxy, the runtime fails to execute a closure, instead throwing an "Illegal Invocation" Exception.
I have tried reengineering the debugging hook system to not wrap arguments for some methods, or selectively wrap arguments. I have not been able to find a way to tell if an argument is intended to be used as a context, making code that tries this approach hardcoded to many possible methods and calling conventions. Ultimately this is too fragile to calling convention edge cases and requires too many case statements.
I have also removed the logic for wrapping arguments before passing them through. This removes the benefit from the debug hooking system, and so I have always reverted the logic to wrap all incoming arguments.
alert.apply(this, [1]);
p = new Proxy(this, {});
try {
alert.apply(p, [1]);
} catch (e) {
console.log(e);
}
This throws an "Illegal Invocation" Exception.
typeof this === 'object'
true
But it seems that contexts are objects just like everything else.
I expect that passing a Proxy() through to context should succeed in an invocation. Barring this, I would expect the type of a context to be specific enough to determine whether it should be wrapped in a Proxy() or not.
I have two questions.
(1) What are the semantics of context binding closures in javascript that would cause binding to a Proxy(context) to fail with an illegal invocation?
(2) What type of object are contexts, and how can a javascript method tell one apart from other javascript objects by inspecting its properties at runtime?
What type of object are contexts, and how can a javascript method tell one apart from other javascript objects by inspecting its properties at runtime?
There is no special type. Every object can become a context by calling a method upon it. Most objects that will become a context of a method call do have that very method as an (inherited) property, but there's no guarantee.
You cannot tell them apart.
What are the semantics of context binding in javascript that would cause binding to a Proxy(context) to fail with an illegal invocation?
When the method is a native one. In user code functions, the this context being a proxy doesn't make a difference, when you access it then it will just behave as a proxy.
The problem is native methods that expect their this argument to be a native object of the respective type. Sure, those objects are still javascript objects, but they may contain private data on internal properties as well. A proxy's target and handler references are implemented through such internal properties as well, for example - you can sometimes inspect them in the debugger. The native methods don't know to unwrap a proxy and use its target instead, they just look at the object and notice that it doesn't have the required internal properties for the method to do its job. You could've passed a plain {} as well.
Examples for such methods can be found as builtins of the ECMAScript runtime:
Map.prototype.has/get/set/…
Set.prototype.has/get/set/…
TypeArrayPrototype.slice/copyWithin/map/forEach/…
Number/String/Boolean prototype methods
But also (and even more of them) as host objects supplied by the environment:
window.alert/prompt
EventTarget.prototype.addEventListener/removeEventListener
document.createElement
Element.prototype.appendChild/remove/…
really just anything that's browser-specific
but also in other environments, like the nodejs os module
I have tried unwrapping Proxies in the right places by coding in edge cases and by blanket/heuristic policies.
I think the only reasonable approach would be to check whether the called function is a native one, and unwrap all arguments (including the this argument) for them.
Only a few native functions could be whitelisted, such as most of those on the Array.prototype which are explicitly specified in the language standard to work on arbitrary objects.
I'm a longtime Java/C++ programmer and novice Javascript programmer. I'm trying to make a web app with a class I have previously coded in C++.
In my Javascript web app, I'm using Embind to create and use the class originally coded in C++. On the Embind documentation page it says,
JavaScript code must explicitly delete any C++ object handles it has received, or the Emscripten heap will grow indefinitely.
and the examples on the page show the created object being deleted immediately after use:
var x = new Module.MyClass;
x.method();
x.delete();
In my web app, I want my object from C++ to persist for the lifetime of the webpage. I want to be able to press a button on the page and update the state of my object. If I .delete() the object at the end of the script, it won't persist when I try pushing the button later.
In the Embind example, embind.test.js, it is possible to call .deleteLater() on a newly created object:
var v = (new cm.ValHolder({})).deleteLater();
My question is, if I simply call .deleteLater() upon the object creation, is this enough for the object to be deleted when the app is done running or when the page is closed? I'm trying to avoid growing the heap indefinitely or cause any memory leaks.
Again, I'm new to Javascript so please point out if I'm missing anything obvious or if ignorant of a best practice concerning memory leaks and pointers in Javascript.
Let me know if I need to clarify anything. Thanks!
reference: https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/embind.html#memory-management
I'm on the same path and really don't have a concrete answer for you, but as a JS developer I can collaborate with this:
Calling delete() on an already deleted object throws an ugly exception (uncatchable from JS). There is an undocumented method to check this: obj.isDeleted(). Also obj.SS.count will be 0 when the object is "deleted"
In the browser not deleting objects could for sure break your application but from the point of view of a C++ developer this only happens in the context of the document - so by just reloading the page - you get all the memory back (is not necessary to kill the browser)
when exceptions are thrown from C++ code , like sigint, bad memory allocation, etc, it seems is not possible to catch them, even using DISABLE_EXCEPTION_CATCHING or the rest of the debug flags. Module.onAbort or similar also won't handle them. So If anybody will handle deleteLater() registered objects when the program throws must be at C++ side.
I see there's no documentation about delete(), isDeleted() deleteLater() I think those would be great candidates for a PR.
I am working on an application that utilizes Spider Monkey to run our JS. I only have a single object type (JSNode) that acts as an interface to a complex DOM consisting of various objects with properties and methods. Everything is created and registered on the fly. I am running into a problem where I have an object with a function that needs to be associated dynamically. The problem is when I run the script from the context of the associated object, the NewResolve (which I usually use to recognize and define the properties), as far as I can tell cannot know it's a function definition to allow me to define the function on the fly. I don't get the sense that JS_CompileScript will correctly build the function and associate it with the HandleObject. And of course I can't utilize JS_CompileFunction without doing all of the script parsing myself, which to me feels like the point of utilizing spider monkey in the first place, but maybe I am wrong.
Any ideas or guidance on this issue?
Looking at this page from firebreath.org I found this excerpt:
You can return a JSAPI instance to a JavaScript caller in the form of a JSAPIPtr and use that to make calls on a different JSAPI object, e.g. plugin().method1().method2() will call method1() on the Root JSAPI object and method2() on the JSAPI object returned in the first call.
Any examples?
My objective:
I want to call another class's (which is also implementing FB:JSAPIAuto) member (say ABCAPI:FB:JSAPIAuto ) through my root JSAPI object which is created automatically by the prepscript i.e. same as described above by creating the JSAPIPtr of the class. Am I right here?
Also, whether the JSAPI object of ABCAPI that was created by me should also get a plugin reference or not?
I went through this page too, but am not able to follow.
Till now, I could create a method returning FB::JSAPIPtr which had the value of another Class (implementing FB::JSAPIAuto) pointer.
A little example would be a great help here!
*Another doubt:
How do you expose a simple c++ class(not extending any Firebreath class) to the Javascript so that i can access its members?*I found a v8 Javascript engine thing.Don't have any idea about this. I want my plugin to be available for all other browsers too apart from chrome.Do i need this?
Okay, there are a couple of things here. First, the prep script doesn't create JSAPI objects for you -- that was fbgen. This is an important distinction because you will run the prep script many times, but fbgen you only run once to create the project skeleton.
Next, you're making this far more complicated than it needs to be. A JSAPI object is just a class object; if you have a reference to it in C++, you can call a member of the other class just like you would any other object. There is nothing magical about it, except maybe when you give it to javascript, and then just that the methods you expose to javascript are the only ones you can use.
What you haven't explained is where the reference to the second JSAPI object comes from. Are you passing it in from javascript? If so, things get more tricky, and you'll have to call it using ->Invoke like you would a method on any other javascript object passed in from the page. Did you create it in c++? If so, then you just use it like any other object.
As to whether or not the hypothetical ABCAPI object should get a plugin reference or not, that's totally up to you. The Root JSAPI object doesn't need one, it's just for your convenience in case you want to access the plugin.
For examples, go look at FBTestPlugin in the firebreath code base. It has examples of nesting JSAPI objects and such.
I'm writing an Android app which uses Javascript in a WebView for most of the UI. I've exposed to JS a simple interface to create temporary files. In Java, I provide a function to create a temporary file, which returns a file ID, and a set of functions to operate on temporary files given an ID. In JS, I wrap these functions with a TempFile object which keeps track of its own ID internally.
The problem with this is the Java side has a list of files, but knows nothing about the objects that represent them in Javascript. So when a TempFile is collected in JS, the file object is still around on the Java side. Is there an "oncollect" or such callback that I can use to tell Java to free the file corresponding to a TempFile that's been collected?
Look at Finalizer
Since ES12 you can find FinalizationRegistry. Use it to tell Java to free the file corresponding to a TempFile that's been collected.
const registry = new FinalizationRegistry((fileName) => {
console.log(fileName);
// ... here your function to comunicate with Java
});
let tempFileObject;
registry.register(tempFileObject, filename);
Here we create an instance of FinalizationRegistry and attached the js 'tempFile' to it using .register. Soon as the 'tempFile' is garbage collected, the callback function passed to the FinalizationRegistry method communicate with java.
Possible duplicate
How to implement function that fires when JavaScript object is garbage collected?
I'm fairly sure the answer is "no" - you can't hook into the JS garbage collection process in the same way that you can with Java's finalizers (or ReferenceQueues).
Can you instead deal with this more declaratively? Your question seems to imply that the only way your system "knows" when a file is no longer needed, is when it is GCed (or in other words, your system doesn't know at all). Are you really referencing these files all over the application? Good practice would be for these resources to be used with a well-defined lifecycle, such that the part of the system that creates a temp file is also responsible for destroying it after it's finished with it.
Under that model, when you (explicitly) destroy the file in JS, you can call back to Java to perform the required clean up.
Releasing a resource by simply removing all references to it, as you're doing at the moment, is not particularly good practice.
No. You will need to call a Java function from your JavaScript when you don't need the files anymore.
Javascript does not have such hook.
You need to explicitly create close() function or such method for this use case and call it.
Some more info
http://forums.mozillazine.org/viewtopic.php?f=19&p=5517055