Sunday, May 15, 2011

Porting to JS 1.8.5 with GPSEE 0.3: Part III, Strings

SpiderMonkey 1.8.5 changed a number of internal details with respect to JSString representation. Fortunately, most of these changes do not affect the JSAPI embedder writing well-behaved applications.

The biggest changes are with respect to how the memory for the JSString storage is allocated. JSAPI no longer has functions for taking memory allocated by the embedder and pushing it to become the backing storefor a JSString object, nor will it GC-entrain alternate (C string) representations to accommodate the embedder.

JS_GetStringBytes

The JS_GetStringBytes() function has been removed from SpiderMonkey 1.8.5. This function previously returned an approximate representation of the JSString as a C string (the rules for moving from 16- to 8-bit strings vary based on JS_CStringsAreUT8()). This memory was allocated by the JS Garbage Collector, and the GC held a reference to it until the JSString was collected.

GPSEE 0.3 introduces gpsee_getStringBytes(), in a effort to restore this functionality. This allows fast updating of existing JS embeddings, and it makes it possible to write embeddings which continue to work where the newer interfaces (like JS_EncodeBuffer()) are not available.

Please be very careful when substituting gpsee_getStringBytes() for JS_GetStringBytes(): the memory allocation semantics are subtly different. The GPSEE version of this function will free the returned C string when the calling function returns (i.e. the string is alloated with alloca()). We suggest examining each call site, and making sure the resultant pointer does not escape the calling function; if it does, the string should be strdup'd and later free'd.

-  cstrId = JS_GetStringBytes(jstrId);
+  cstrId = gpsee_getStringBytes(cx, jstrId);

JS_GetStringChars

This interface was removed from JSAPI, but we have re-created it with GPSEE-0.3, with one important difference: the returned pointer is now const. This means that your embedding or GPSEE mdoules will probably generate a lot of warnings like this:

vm.c:234: warning: assignment discards qualifiers from pointer target type

The solution is to change your variable declarations from JSString * to const JSString * whenever they reference the return value of JS_GetStringChars(). This will also help you to audit your code for any call sites which try to modify string data where it is stored by the JS engine: this has always been unsupported, but it is now more dangerous than ever.

   JSString      *str;
-  jschar        *ptr;
+  const jschar  *ptr;

   str = JS_ValueToString(cx, argv[0]);
   if (!str)
    return JS_FALSE; /* OOM */
   argv[0] = STRING_TO_JSVAL(str);                  /* Provide a temporary GC root */
   ptr = JS_GetStringChars(str);
Aside
The assignment to argv[0] in this sample is an example of code using the old "root-as-you-go" GC safety technique. It is no longer necessary with SpiderMonkey 1.8.5, as str is stored on the C stack, and as such will be found by the new stack-scanning conservative garbage collector.

No comments:

Post a Comment