outermost = (cx->sharpObjectMap.depth == 0);
outermost = (cx->version != JSVERSION_1_2) && (cx->sharpObjectMap.depth == 0);
js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,		jsval *rval){    JSBool ok, outermost;    JSHashEntry *he;    JSIdArray *ida;    jschar *chars, *ochars, *vchars, *vsharp;    size_t nchars, vlength, vsharplength;    char *comma;    jsint i, j, length, valcnt;    jsid id;    JSObject *obj2;    JSProperty *prop;    uintN attrs;    jsval val[2];#if JS_HAS_GETTER_SETTER    JSString *gsop[2];#endif    JSString *idstr, *valstr, *str;    outermost = (cx->sharpObjectMap.depth == 0);    he = js_EnterSharpObject(cx, obj, &ida, &chars);    if (!he)	return JS_FALSE;    if (IS_SHARP(he)) {	/* we didn't enter -- obj is already sharp */	JS_ASSERT(!ida);#if JS_HAS_SHARP_VARS	nchars = js_strlen(chars);#else	chars[0] = '{';	chars[1] = '}';	chars[2] = 0;	nchars = 2;#endif	goto make_string;    }    JS_ASSERT(ida);    ok = JS_TRUE;    /* Allocate 4 + 1 for "({})" and the terminator. */    if (!chars) {	chars = malloc((4 + 1) * sizeof(jschar));	nchars = 0;	if (!chars)	    goto error;    } else {	JS_ASSERT(!outermost);	MAKE_SHARP(he);	nchars = js_strlen(chars);	chars = realloc((ochars = chars), (nchars + 2 + 1) * sizeof(jschar));	if (!chars) {	    free(ochars);	    goto error;	}    }    if (outermost)	chars[nchars++] = '(';    chars[nchars++] = '{';    comma = NULL;    for (i = 0, length = ida->length; i < length; i++) {	/* Get strings for id and value and GC-root them via argv. */	id = ida->vector[i];#if JS_HAS_GETTER_SETTER	ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);	if (!ok)	    goto error;        ok = OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &attrs);        if (ok) {            if (prop &&                OBJ_IS_NATIVE(obj2) &&                (attrs & (JSPROP_GETTER | JSPROP_SETTER))) {                valcnt = 0;                if (attrs & JSPROP_GETTER) {                    val[valcnt] = (jsval)                        SPROP_GETTER((JSScopeProperty *)prop, obj2);                    gsop[valcnt] =                        ATOM_TO_STRING(cx->runtime->atomState.getterAtom);                    valcnt++;                }                if (attrs & JSPROP_SETTER) {                    val[valcnt] = (jsval)                        SPROP_SETTER((JSScopeProperty *)prop, obj2);                    gsop[valcnt] =                        ATOM_TO_STRING(cx->runtime->atomState.setterAtom);                    valcnt++;                }            } else {                valcnt = 1;                gsop[0] = NULL;                ok = OBJ_GET_PROPERTY(cx, obj, id, &val[0]);            }        }        if (prop)            OBJ_DROP_PROPERTY(cx, obj2, prop);#else        valcnt = 1;        ok = OBJ_GET_PROPERTY(cx, obj, id, &val[0]);#endif        if (!ok)            goto error;	/* Convert id to a jsval and then to a string. */	id = js_IdToValue(id);	idstr = js_ValueToString(cx, id);	if (!idstr) {	    ok = JS_FALSE;	    goto error;	}	argv[0] = STRING_TO_JSVAL(idstr);        /* If id is a non-identifier string, it needs to be quoted. */        if (JSVAL_IS_STRING(id) && !js_IsIdentifier(idstr)) {            idstr = js_QuoteString(cx, idstr, (jschar)'\'');            if (!idstr) {                ok = JS_FALSE;                goto error;            }            argv[0] = STRING_TO_JSVAL(idstr);        }        for (j = 0; j < valcnt; j++) {            /* Convert val[j] to its canonical source form. */            valstr = js_ValueToSource(cx, val[j]);            if (!valstr) {                ok = JS_FALSE;                goto error;            }            argv[1+j] = STRING_TO_JSVAL(valstr);            vchars = valstr->chars;            vlength = valstr->length;            /* If val[j] is a non-sharp object, consider sharpening it. */            vsharp = NULL;            vsharplength = 0;#if JS_HAS_SHARP_VARS            if (!JSVAL_IS_PRIMITIVE(val[j]) && vchars[0] != '#') {                he = js_EnterSharpObject(cx, JSVAL_TO_OBJECT(val[j]), NULL,                                         &vsharp);                if (!he) {                    ok = JS_FALSE;                    goto error;                }                if (IS_SHARP(he)) {                    vchars = vsharp;                    vlength = js_strlen(vchars);                } else {                    if (vsharp) {                        vsharplength = js_strlen(vsharp);                        MAKE_SHARP(he);                    }                    js_LeaveSharpObject(cx, NULL);                }            }#endif            /* Allocate 1 + 1 at end for closing brace and terminating 0. */            chars = realloc((ochars = chars),                            (nchars + (comma ? 2 : 0) +                             idstr->length + 1 +#if JS_HAS_GETTER_SETTER                             (gsop[j] ? 1 + gsop[j]->length : 0) +#endif                             vsharplength + vlength +                             (outermost ? 2 : 1) + 1) * sizeof(jschar));            if (!chars) {                /* Save code space on error: let JS_free ignore null vsharp. */                JS_free(cx, vsharp);                free(ochars);                goto error;            }            if (comma) {                chars[nchars++] = comma[0];                chars[nchars++] = comma[1];            }            comma = ", ";            js_strncpy(&chars[nchars], idstr->chars, idstr->length);            nchars += idstr->length;#if JS_HAS_GETTER_SETTER            if (gsop[j]) {                chars[nchars++] = ' ';                js_strncpy(&chars[nchars], gsop[j]->chars, gsop[j]->length);                nchars += gsop[j]->length;            }#endif            chars[nchars++] = ':';            if (vsharplength) {                js_strncpy(&chars[nchars], vsharp, vsharplength);                nchars += vsharplength;            }            js_strncpy(&chars[nchars], vchars, vlength);            nchars += vlength;            if (vsharp)                JS_free(cx, vsharp);        }    }    chars[nchars++] = '}';    if (outermost)	chars[nchars++] = ')';    chars[nchars] = 0;error:    js_LeaveSharpObject(cx, &ida);    if (!ok) {	if (chars)	    free(chars);	return ok;    }    if (!chars) {	JS_ReportOutOfMemory(cx);	return JS_FALSE;    }  make_string:    str = js_NewString(cx, chars, nchars, 0);    if (!str) {	free(chars);	return JS_FALSE;    }    *rval = STRING_TO_JSVAL(str);    return JS_TRUE;}