*sp = NULL;
js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap,		    jschar **sp){    JSSharpObjectMap *map;    JSHashTable *table;    JSIdArray *ida;    JSHashNumber hash;    JSHashEntry *he, **hep;    jsatomid sharpid;    char buf[20];    size_t len;    map = &cx->sharpObjectMap;    table = map->table;    if (!table) {	table = JS_NewHashTable(8, js_hash_object, JS_CompareValues,				JS_CompareValues, NULL, NULL);	if (!table) {	    JS_ReportOutOfMemory(cx);	    return NULL;	}	map->table = table;    }    ida = NULL;    if (map->depth == 0) {	he = MarkSharpObjects(cx, obj, &ida);	if (!he)	    return NULL;	JS_ASSERT((((jsatomid) he->value) & SHARP_BIT) == 0);	if (!idap) {	    JS_DestroyIdArray(cx, ida);	    ida = NULL;	}    } else {	hash = js_hash_object(obj);	hep = JS_HashTableRawLookup(table, hash, obj);	he = *hep;	/*	 * It's possible that the value of a property has changed from the	 * first time the object's properties are traversed (when the property	 * ids are entered into the hash table) to the second (when they are	 * converted to strings), i.e. the getProperty() call is not	 * idempotent.	 */	if (!he) {	    he = JS_HashTableRawAdd(table, hep, hash, obj, (void *)0);	    if (!he)		JS_ReportOutOfMemory(cx);	    *sp = NULL;            sharpid = 0;	    goto out;	}    }    sharpid = (jsatomid) he->value;    if (sharpid == 0) {	*sp = NULL;    } else {	len = JS_snprintf(buf, sizeof buf, "#%u%c",			  sharpid >> 1, (sharpid & SHARP_BIT) ? '#' : '=');	*sp = js_InflateString(cx, buf, len);	if (!*sp) {	    if (ida)		JS_DestroyIdArray(cx, ida);	    return NULL;	}    }out:    if ((sharpid & SHARP_BIT) == 0) {	if (idap && !ida) {	    ida = JS_Enumerate(cx, obj);	    if (!ida) {		if (*sp) {		    JS_free(cx, *sp);		    *sp = NULL;		}		return NULL;	    }	}	map->depth++;    }    if (idap)	*idap = ida;    return he;}