Spidermonkey gets fixed and gets ready to move from “beta” to “stable”


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:

typedef struct _php_jsparent {
    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 : null }
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 :D

, , , , ,

  1. #1 by scott on May 6, 2010 - 11:03 pm

    Instead of making JavaScript run inside PHP, would it be possible to run it right on top of Zend for a viable server side JavaScript implementation?

  2. #2 by Ronald Baltus on May 31, 2010 - 10:59 am

    - If an object implements ArrayAccess and Iterator (or other PHP interfaces to have the object behave like an array) it would be nice if the object can be accessed as an array in JavaScript too.

    - Setting properties and reading properties in javascript are directly mapped to the properties in PHP. However, we want to be able to do some testing before it, or to make readonly properties. In other words: we want to be able to map the JS properties to PHP functions.

    Spidermonkey is a great addition to our software and we can add alot of functionality with a small script. Thanks!

  3. #3 by ss on August 9, 2010 - 9:04 pm

    Being able to throw JavaScript exceptions from within PHP would be nice, so you can capture the JS line number (via try/catch blocks in JS) of an error that happens on the PHP side — for example when you pass an invalid parameter to your registered PHP object from within JS.

(will not be published)