Posts Tagged pecl
Spidermonkey gets fixed and gets ready to move from “beta” to “stable”
Posted by Christophe Robin in C, Code, PHP on March 7, 2010
Hello, it’s been a while since I last wrote something on this blog. Today I come back to tell you that version 0.1.4 of spidermonkey has finally been released and provide fixes for 3 bugs that where posted on the PECL bug tracker, I’ll do a small explanation of each bug and how they were resolved bellow. I also took care of integrating some patches for spidermonkey 1.9, added the config.w32 from hoshino at labs dot cybozu dot co dot jp and changed a couple stuff there and there in the source code. I also added regression tests for the solved bugs and updated some of the previous ones to reflect the corresponding changes.
Fixed bugs
Bug 16866:
This bug was pretty basic, when an empty string was returned from Javascript, the current PHP thread would segfault. The reason was simple, when Spidermonkey hold a variable that contains an empty string, it doesn’t possess a char* that would point to this empty string to save memory, so when I tried to retrieve this non-existing value to create an empty string in PHP, it would just segfault. I just solved this by checking the variable length in JS before doing the conversion, quite trivial compared to some bugs to come. It also solved bug 16876.
Bug 16890:
That one was another beast, when an object created in javascript was converted to PHP, it would become NULL on the next call. Clearly there was something weird going on here, after some painful debug, I saw that the issue came from a small caching system I had made that had no sense at all and was actually useless. Here is what it was doing:
When the javascript class was converted, it created the object and store it in a Zend HashTable with the JSObject id as its index. It would then retrieve the object from this “cache” when trying to access the object again. The basic idea at the time was to optimize objects that where converted back and forth a lot of time by pulling them from the cache, and preventing cyclic references by providing the cached objects without having to traverse it ( otherwise it would result in an infinite loop ). While the goal was great, the execution had several flaw, the biggest one was that for an unknown reason all objects that where stored were returned as NULL by the HashTable. But even if it had worked it would have caused issue with objects that were converted, modified in Javascript afterward and converted again, as the stored object would have been returned and not the updated one.
To solve this cyclic reference issue, I totally changed the approach by first removing this HashTable idea and then creating a basic structure that looked like:
JSObject *obj;
zval *zobj;
struct _php_jsparent *parent;
} php_jsparent;
When I run my js to zval routine, I pass a new parameter php_jsparent *parent that is NULL by default, if i’m converting an object, I create this jsparent object, store the current JSObject being converted, the stdClass zval that is being created and our parent if theres one and call the converting method recursively on each children. Now when *parent is defined, before converting an object I do a quick traversal of the parent links and if I find a JSObject *obj that is the same as the object I’m converting I just return the stored zobj, effectively solving the cyclic referencing issue.
Sample code:
a.b = a
/* in this case, trying to convert the a object result as a cyclic reference
when trying to convert the properties, the new code solves this when
trying to convert b, it checks it's parent which is in this case a, and
see that a == b, returning then the parent zobj and solving the issue */
Bug 16983:
Another tricky one. When the magic __get() method was defined on a class it became impossible to call any method on it.
The issue with this one was the JS_PropertyGetterPHP() function, which is a C getter function that is called on a Javascript object even if a property exists, I would then call the Zend getter function on the object and return the value if found. The main issue was that I wasn’t taking care of properties already defined on the JS side, and always trying to retrieve the data from the PHP side. This issue was solved pretty fast, I decided to reproduce the same functionality as PHP, that means that when this getter is called it first try to retrieve data from JS, in the case of methods, if would retrieve the property I had defined beforehand when creating the object and return it to our context. If it effectively doesn’t find anything on javascript, if then fallback on the PHP item, calling __get() if necessary.
Feedback
Most blocking bugs have been solved with this release, feel free to post on the bug tracker any new issue you would encounter and I’ll make sure to take a look. If no bugs are found, then I’ll make sure to finish a few things there and there and will release version 1.0.0 as stable to allow more peoples to use it safely.
Future tasks
There are several thing I’d like to do, like better debugging support using the tracing API that is being added in spidermonkey since 1.8+. But first would be support for closures in both directions, that means having access to JS function directly from PHP (that one is really hard, it will takes some time of tingling with the PHP internals to make it works) and assigning closures in JS (should be a lot easier). I already added the test on the SVN, and I’ll try to tackle this one in the next months.
If you have any idea of feature that you’d like to see implemented, feel free to ask in the comments
Spidermonkey in PECL
Posted by Christophe Robin in C, Code, PHP on February 24, 2009
Today I finally released spidermonkey on PECL, you can find it here: http://pecl.php.net/package/spidermonkey/
The whole thing should work fine, I’m already working on several optimisations thanks to jorendorff from Mozilla on IRC. The next thing is to provide better error report, compilation/decompilation of scripts and more default functions for a bunch of things like Iterators and the like.
The last thing I added is a bunch of function applied to streams, here is an exemple:
$ctx = new JSContext();
/* provide fopen/fclose functions */
$ctx->registerFunction('fopen');
$ctx->registerFunction('fclose');
/* for output */
$ctx->registerFunction('printf');
Then in Javascript:
fd = fopen('somefile.txt', 'r')
while (line = fd.getline()) {
printf("%s\n", line)
}
fclose(fd)
Or
fd = fopen('somefile.txt', 'w')
/* here fd.SEEK_SET is the default value and is optional */
fd.seek(1024, fd.SEEK_SET)
fd.write("some text here :D")
fclose(fd)