str = JSVAL_TO_STRING(v);
str = js_ValueToString(cx, v);
array_join_sub(JSContext *cx, JSObject *obj, JSString *sep, JSBool literalize,	       jsval *rval, JSBool localeString){    JSBool ok;    jsval v;    jsuint length, index;    jschar *chars, *ochars;    size_t nchars, growth, seplen;    const jschar *sepstr;    JSString *str;    JSHashEntry *he;    JSObject *obj2;    ok = js_GetLengthProperty(cx, obj, &length);    if (!ok)	return JS_FALSE;    ok = JS_TRUE;    if (literalize) {	he = js_EnterSharpObject(cx, obj, NULL, &chars);	if (!he)	    return JS_FALSE;	if (IS_SHARP(he)) {#if JS_HAS_SHARP_VARS	    nchars = js_strlen(chars);#else	    chars[0] = '[';	    chars[1] = ']';	    chars[2] = 0;	    nchars = 2;#endif	    goto make_string;	}	/*	 * Allocate 1 + 3 + 1 for "[", the worst-case closing ", ]", and the	 * terminating 0.	 */	growth = (1 + 3 + 1) * sizeof(jschar);	if (!chars) {	    nchars = 0;	    chars = (jschar *) malloc(growth);	    if (!chars)		goto done;	} else {	    MAKE_SHARP(he);	    nchars = js_strlen(chars);	    chars = (jschar *)                realloc((ochars = chars), nchars * sizeof(jschar) + growth);	    if (!chars) {		free(ochars);		goto done;	    }	}	chars[nchars++] = '[';    } else {	if (length == 0) {	    *rval = JS_GetEmptyStringValue(cx);	    return ok;	}	chars = NULL;	nchars = 0;    }    sepstr = NULL;    seplen = sep->length;    v = JSVAL_NULL;    for (index = 0; index < length; index++) {	ok = JS_GetElement(cx, obj, index, &v);	if (!ok)	    goto done;	if (JSVAL_IS_VOID(v) || JSVAL_IS_NULL(v)) {	    str = cx->runtime->emptyString;        } else {            if (localeString) {                if (!js_ValueToObject(cx, v, &obj2))                    goto doneBad;                if (!js_TryMethod(cx, obj2, cx->runtime->atomState.toLocaleStringAtom, 0, NULL, &v))                    goto doneBad;                str = JSVAL_TO_STRING(v);            }            else                str = (literalize ? js_ValueToSource : js_ValueToString)(cx, v);	    if (!str) {  doneBad:		ok = JS_FALSE;		goto done;	    }	}	/* Allocate 3 + 1 at end for ", ", closing bracket, and zero. */	growth = (nchars + (sepstr ? seplen : 0) +		  str->length +		  3 + 1) * sizeof(jschar);	if (!chars) {	    chars = (jschar *) malloc(growth);	    if (!chars)		goto done;	} else {	    chars = (jschar *) realloc((ochars = chars), growth);	    if (!chars) {		free(ochars);		goto done;	    }	}	if (sepstr) {	    js_strncpy(&chars[nchars], sepstr, seplen);	    nchars += seplen;	}	sepstr = sep->chars;	js_strncpy(&chars[nchars], str->chars, str->length);	nchars += str->length;    }  done:    if (literalize) {	if (chars) {	    if (JSVAL_IS_VOID(v)) {		chars[nchars++] = ',';		chars[nchars++] = ' ';	    }	    chars[nchars++] = ']';	}	js_LeaveSharpObject(cx, NULL);    }    if (!ok) {	if (chars)	    free(chars);	return ok;    }  make_string:    if (!chars) {	JS_ReportOutOfMemory(cx);	return JS_FALSE;    }    chars[nchars] = 0;    str = js_NewString(cx, chars, nchars, 0);    if (!str) {	free(chars);	return JS_FALSE;    }    *rval = STRING_TO_JSVAL(str);    return JS_TRUE;}