Beispiel #1
0
JSAtom *
js_AtomizeDouble(JSContext *cx, jsdouble d, uintN flags)
{
    jsdouble *dp;
    JSHashNumber keyHash;
    jsval key;
    JSAtomState *state;
    JSHashTable *table;
    JSHashEntry *he, **hep;
    JSAtom *atom;
    char buf[2 * ALIGNMENT(double)];

    dp = ALIGN(buf, double);
    *dp = d;
    keyHash = HASH_DOUBLE(dp);
    key = DOUBLE_TO_JSVAL(dp);
    state = &cx->runtime->atomState;
    JS_LOCK(&state->lock, cx);
    table = state->table;
    hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
    if ((he = *hep) == NULL) {
#ifdef JS_THREADSAFE
        uint32 gen = state->tablegen;
#endif
        JS_UNLOCK(&state->lock,cx);
        if (!js_NewDoubleValue(cx, d, &key))
            return NULL;
        JS_LOCK(&state->lock, cx);
#ifdef JS_THREADSAFE
        if (state->tablegen != gen) {
            hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
            if ((he = *hep) != NULL) {
                atom = (JSAtom *)he;
                goto out;
            }
        }
#endif
        he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
        if (!he) {
            JS_ReportOutOfMemory(cx);
            atom = NULL;
            goto out;
        }
    }

    atom = (JSAtom *)he;
    atom->flags |= flags;
    cx->lastAtom = atom;
out:
    JS_UNLOCK(&state->lock,cx);
    return atom;
}
Beispiel #2
0
JSAtom *
js_AtomizeDouble(JSContext *cx, jsdouble d)
{
    JSAtomState *state;
    JSDHashTable *table;
    JSAtomHashEntry *entry;
    uint32 gen;
    jsdouble *key;
    jsval v;

    state = &cx->runtime->atomState;
    table = &state->doubleAtoms;

    JS_LOCK(cx, &state->lock);
    entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, &d, JS_DHASH_ADD));
    if (!entry)
        goto failed_hash_add;
    if (entry->keyAndFlags == 0) {
        gen = ++table->generation;
        JS_UNLOCK(cx, &state->lock);

        key = js_NewWeaklyRootedDouble(cx, d);
        if (!key)
            return NULL;

        JS_LOCK(cx, &state->lock);
        if (table->generation == gen) {
            JS_ASSERT(entry->keyAndFlags == 0);
        } else {
            entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, key,
                                                       JS_DHASH_ADD));
            if (!entry)
                goto failed_hash_add;
            if (entry->keyAndFlags != 0)
                goto finish;
            ++table->generation;
        }
        INIT_ATOM_ENTRY(entry, key);
    }

  finish:
    v = DOUBLE_TO_JSVAL((jsdouble *)ATOM_ENTRY_KEY(entry));
    cx->weakRoots.lastAtom = v;
    JS_UNLOCK(cx, &state->lock);

    return (JSAtom *)v;

  failed_hash_add:
    JS_UNLOCK(cx, &state->lock);
    JS_ReportOutOfMemory(cx);
    return NULL;
}
Beispiel #3
0
JSAtom *
js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length)
{
    JSString str, *str2;
    JSAtomState *state;
    JSDHashEntryHdr *hdr;

    if (length == 1) {
        jschar c = *chars;
        if (c < UNIT_STRING_LIMIT)
            return (JSAtom *) STRING_TO_JSVAL(JSString::unitString(c));
    }

    str.initFlat((jschar *)chars, length);
    state = &cx->runtime->atomState;

    JS_LOCK(cx, &state->lock);
    hdr = JS_DHashTableOperate(&state->stringAtoms, &str, JS_DHASH_LOOKUP);
    str2 = JS_DHASH_ENTRY_IS_BUSY(hdr)
           ? (JSString *)ATOM_ENTRY_KEY(TO_ATOM_ENTRY(hdr))
           : NULL;
    JS_UNLOCK(cx, &state->lock);

    return str2 ? (JSAtom *)STRING_TO_JSVAL(str2) : NULL;
}
Beispiel #4
0
static JSAtom *
js_AtomizeHashedKey(JSContext *cx, jsval key, JSHashNumber keyHash, uintN flags)
{
    JSAtomState *state;
    JSHashTable *table;
    JSHashEntry *he, **hep;
    JSAtom *atom;

    state = &cx->runtime->atomState;
    JS_LOCK(&state->lock, cx);
    table = state->table;
    hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
    if ((he = *hep) == NULL) {
        he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
        if (!he) {
            JS_ReportOutOfMemory(cx);
            atom = NULL;
            goto out;
        }
    }

    atom = (JSAtom *)he;
    atom->flags |= flags;
out:
    JS_UNLOCK(&state->lock,cx);
    return atom;
}
Beispiel #5
0
JSBool
js_SetClassPrototype(JSContext *cx, JSFunction *fun, JSObject *obj)
{
    JSBool ok;

    ok = JS_TRUE;
    JS_LOCK(cx);
    if (!js_DefineProperty(cx, fun->object,
			   (jsval)cx->runtime->atomState.classPrototypeAtom,
			   OBJECT_TO_JSVAL(obj), NULL, NULL,
			   JSPROP_READONLY | JSPROP_PERMANENT)) {
	ok = JS_FALSE;
	goto out;
    }
    if (!js_DefineProperty(cx, obj,
			   (jsval)cx->runtime->atomState.constructorAtom,
			   OBJECT_TO_JSVAL(fun->object), NULL, NULL,
			   JSPROP_READONLY | JSPROP_PERMANENT)) {
	ok = JS_FALSE;
	goto out;
    }
out:
    JS_UNLOCK(cx);
    return ok;
}
Beispiel #6
0
JSBool
js_GetClassPrototype(JSContext *cx, JSClass *clasp, JSObject **protop)
{
    JSBool ok;
    JSObject *ctor;
    jsval pval;
    JSProperty *prop;

    *protop = NULL;
    JS_LOCK(cx);
    ok = FindConstructor(cx, clasp, &pval);
    if (!ok || !JSVAL_IS_FUNCTION(pval))
	goto out;
    ctor = JSVAL_TO_OBJECT(pval);
    if (!js_LookupProperty(cx, ctor,
			   (jsval)cx->runtime->atomState.classPrototypeAtom,
			   NULL, &prop)) {
	ok = JS_FALSE;
	goto out;
    }
    if (prop) {
	pval = prop->object->slots[prop->slot];
	if (JSVAL_IS_OBJECT(pval))
	    *protop = JSVAL_TO_OBJECT(pval);
    }
out:
    JS_UNLOCK(cx);
    return ok;
}
Beispiel #7
0
static JSBool
obj_getCount(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
    jsint count;
    JSProperty *prop;

    count = 0;
    JS_LOCK(cx);
    for (prop = obj->map->props; prop; prop = prop->next)
	if (prop->flags & JSPROP_ENUMERATE)
	    count++;
    JS_UNLOCK(cx);
    *vp = INT_TO_JSVAL(count);
    return JS_TRUE;
}
Beispiel #8
0
obj_setSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
    JSObject *obj2;
    jsint slot;
    JSBool ok;

    if (!JSVAL_IS_OBJECT(*vp))
	return JS_TRUE;
    obj2 = JSVAL_TO_OBJECT(*vp);
    slot = JSVAL_TO_INT(id);
    JS_LOCK(cx);
    while (obj2) {
	if (obj2 == obj) {
	    JS_ReportError(cx, "cyclic %s value", object_props[slot].name);
	    ok = JS_FALSE;
	    goto out;
	}
	obj2 = JSVAL_TO_OBJECT(js_GetSlot(cx, obj2, slot));
    }
    ok = js_SetSlot(cx, obj, slot, *vp);
out:
    JS_UNLOCK(cx);
    return ok;
}
Beispiel #9
0
JSAtom *
js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
{
    jsval v;
    JSAtomState *state;
    JSDHashTable *table;
    JSAtomHashEntry *entry;
    JSString *key;
    uint32 gen;

    JS_ASSERT(!(flags & ~(ATOM_PINNED|ATOM_INTERNED|ATOM_TMPSTR|ATOM_NOCOPY)));
    JS_ASSERT_IF(flags & ATOM_NOCOPY, flags & ATOM_TMPSTR);

    if (str->isAtomized())
        return (JSAtom *) STRING_TO_JSVAL(str);

    size_t length = str->length();
    if (length == 1) {
        jschar c = str->chars()[0];
        if (c < UNIT_STRING_LIMIT)
            return (JSAtom *) STRING_TO_JSVAL(JSString::unitString(c));
    }

    /*
     * Here we know that JSString::intStringTable covers only 256 (or at least
     * not 1000 or more) chars. We rely on order here to resolve the unit vs.
     * int string atom identity issue by giving priority to unit strings for
     * '0' through '9' (see JSString::intString in jsstrinlines.h).
     */
    JS_STATIC_ASSERT(INT_STRING_LIMIT <= 999);
    if (2 <= length && length <= 3) {
        const jschar *chars = str->chars();

        if ('1' <= chars[0] && chars[0] <= '9' &&
            '0' <= chars[1] && chars[1] <= '9' &&
            (length == 2 || ('0' <= chars[2] && chars[2] <= '9'))) {
            jsint i = (chars[0] - '0') * 10 + chars[1] - '0';

            if (length == 3)
                i = i * 10 + chars[2] - '0'; 
            if (jsuint(i) < INT_STRING_LIMIT)
                return (JSAtom *) STRING_TO_JSVAL(JSString::intString(i));
        }
    }

    state = &cx->runtime->atomState;
    table = &state->stringAtoms;

    JS_LOCK(cx, &state->lock);
    entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, str, JS_DHASH_ADD));
    if (!entry)
        goto failed_hash_add;
    if (entry->keyAndFlags != 0) {
        key = (JSString *)ATOM_ENTRY_KEY(entry);
    } else {
        /*
         * We created a new hashtable entry. Unless str is already allocated
         * from the GC heap and flat, we have to release state->lock as
         * string construction is a complex operation. For example, it can
         * trigger GC which may rehash the table and make the entry invalid.
         */
        ++table->generation;
        if (!(flags & ATOM_TMPSTR) && str->isFlat()) {
            str->flatClearMutable();
            key = str;
        } else {
            gen = table->generation;
            JS_UNLOCK(cx, &state->lock);

            if (flags & ATOM_TMPSTR) {
                if (flags & ATOM_NOCOPY) {
                    key = js_NewString(cx, str->flatChars(), str->flatLength());
                    if (!key)
                        return NULL;

                    /* Finish handing off chars to the GC'ed key string. */
                    str->mChars = NULL;
                } else {
                    key = js_NewStringCopyN(cx, str->flatChars(), str->flatLength());
                    if (!key)
                        return NULL;
                }
            } else {
                JS_ASSERT(str->isDependent());
                if (!js_UndependString(cx, str))
                    return NULL;
                key = str;
            }

            JS_LOCK(cx, &state->lock);
            if (table->generation == gen) {
                JS_ASSERT(entry->keyAndFlags == 0);
            } else {
                entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, key,
                                                           JS_DHASH_ADD));
                if (!entry)
                    goto failed_hash_add;
                if (entry->keyAndFlags != 0) {
                    key = (JSString *)ATOM_ENTRY_KEY(entry);
                    goto finish;
                }
                ++table->generation;
            }
        }
        INIT_ATOM_ENTRY(entry, key);
        key->flatSetAtomized();
    }

  finish:
    ADD_ATOM_ENTRY_FLAGS(entry, flags & (ATOM_PINNED | ATOM_INTERNED));
    JS_ASSERT(key->isAtomized());
    v = STRING_TO_JSVAL(key);
    cx->weakRoots.lastAtom = v;
    JS_UNLOCK(cx, &state->lock);
    return (JSAtom *)v;

  failed_hash_add:
    JS_UNLOCK(cx, &state->lock);
    JS_ReportOutOfMemory(cx);
    return NULL;
}
Beispiel #10
0
JSAtom *
js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
{
    JSHashNumber keyHash;
    jsval key;
    JSAtomState *state;
    JSHashTable *table;
    JSHashEntry *he, **hep;
    JSAtom *atom;

    keyHash = js_HashString(str);
    key = STRING_TO_JSVAL(str);
    state = &cx->runtime->atomState;
    JS_LOCK(&state->lock, cx);
    table = state->table;
    hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
    if ((he = *hep) == NULL) {
#ifdef JS_THREADSAFE
        uint32 gen = state->tablegen;
        JS_UNLOCK(&state->lock, cx);
#endif

        if (flags & ATOM_TMPSTR) {
            str = (flags & ATOM_NOCOPY)
                  ? js_NewString(cx, str->chars, str->length, 0)
                  : js_NewStringCopyN(cx, str->chars, str->length, 0);
            if (!str)
                return NULL;
            key = STRING_TO_JSVAL(str);
        } else {
            if (!JS_MakeStringImmutable(cx, str))
                return NULL;
        }

#ifdef JS_THREADSAFE
        JS_LOCK(&state->lock, cx);
        if (state->tablegen != gen) {
            hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
            if ((he = *hep) != NULL) {
                atom = (JSAtom *)he;
                if (flags & ATOM_NOCOPY)
                    str->chars = NULL;
                goto out;
            }
        }
#endif

        he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
        if (!he) {
            JS_ReportOutOfMemory(cx);
            atom = NULL;
            goto out;
        }
    }

    atom = (JSAtom *)he;
    atom->flags |= flags & (ATOM_PINNED | ATOM_INTERNED);
out:
    JS_UNLOCK(&state->lock,cx);
    return atom;
}
Beispiel #11
0
JSBool
js_obj_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
		jsval *rval)
{
    jschar *chars;
    size_t nchars;
    char *clazz, *prefix;
    JSString *str;

#if JS_HAS_OBJECT_LITERAL
    if (cx->version >= JSVERSION_1_2) {
	JSProperty *list, *prop;
	JSBool ok;
	char *comma, *idquote, *valquote;
	jsval id, val;
	JSString *idstr, *valstr;
#if JS_HAS_SHARP_VARS
	PRHashEntry *he;
#endif

	/* Early returns after this must unlock, or goto done with ok set. */
	JS_LOCK(cx);
	list = obj->map->props;

#if JS_HAS_SHARP_VARS
	he = js_EnterSharpObject(cx, obj, &chars);
	if (!he) {
	    JS_UNLOCK(cx);
	    return JS_FALSE;
	}
	if (IS_SHARP(he)) {	/* we didn't enter -- obj is already sharp */
	    JS_UNLOCK(cx);
	    nchars = js_strlen(chars);
	    goto make_string;
	}
	MAKE_SHARP(he);
#else
	/* Shut off recursion by temporarily clearing obj's property list. */
	obj->map->props = NULL;
	chars = NULL;
#endif
	ok = JS_TRUE;

	/* Allocate 2 + 1 for "{}" and the terminator. */
	if (!chars) {
	    chars = malloc((2 + 1) * sizeof(jschar));
	    nchars = 0;
	} else {
	    nchars = js_strlen(chars);
	    chars = realloc(chars, (nchars + 2 + 1) * sizeof(jschar));
	}
	if (!chars)
	    goto done;
	chars[nchars++] = '{';

	comma = NULL;

	for (prop = list; prop; prop = prop->next) {
	    if (!prop->symbols || !(prop->flags & JSPROP_ENUMERATE))
		continue;

	    /* Get strings for id and val and GC-root them via argv. */
	    id = js_IdToValue(sym_id(prop->symbols));
	    idstr = js_ValueToString(cx, id);
	    if (idstr)
		argv[0] = STRING_TO_JSVAL(idstr);
	    val = prop->object->slots[prop->slot];
	    valstr = js_ValueToString(cx, val);
	    if (!idstr || !valstr) {
		ok = JS_FALSE;
		goto done;
	    }
	    argv[1] = STRING_TO_JSVAL(valstr);

	    /* If id is a non-identifier string, it needs to be quoted. */
	    if (JSVAL_IS_STRING(id) && !js_IsIdentifier(idstr)) {
		idquote = "'";
		idstr = js_EscapeString(cx, idstr, *idquote);
		if (!idstr) {
		    ok = JS_FALSE;
		    goto done;
		}
		argv[0] = STRING_TO_JSVAL(idstr);
	    } else {
		idquote = NULL;
	    }

	    /* Same for val, except it can't be an identifier. */
	    if (JSVAL_IS_STRING(val)) {
		valquote = "\"";
		valstr = js_EscapeString(cx, valstr, *valquote);
		if (!valstr) {
		    ok = JS_FALSE;
		    goto done;
		}
		argv[1] = STRING_TO_JSVAL(valstr);
	    } else {
		valquote = NULL;
	    }

	    /* Allocate 1 + 1 at end for closing brace and terminating 0. */
	    chars = realloc(chars,
			    (nchars + (comma ? 2 : 0) +
			     (idquote ? 2 : 0) + idstr->length + 1 +
			     (valquote ? 2 : 0) + valstr->length +
			     1 + 1) * sizeof(jschar));
	    if (!chars)
		goto done;

	    if (comma) {
		chars[nchars++] = comma[0];
		chars[nchars++] = comma[1];
	    }
	    comma = ", ";

	    if (idquote)
		chars[nchars++] = *idquote;
	    js_strncpy(&chars[nchars], idstr->chars, idstr->length);
	    nchars += idstr->length;
	    if (idquote)
		chars[nchars++] = *idquote;

	    chars[nchars++] = ':';

	    if (valquote)
		chars[nchars++] = *valquote;
	    js_strncpy(&chars[nchars], valstr->chars, valstr->length);
	    nchars += valstr->length;
	    if (valquote)
		chars[nchars++] = *valquote;
	}

      done:
	if (chars) {
	    chars[nchars++] = '}';
	    chars[nchars] = 0;
	}
#if JS_HAS_SHARP_VARS
	js_LeaveSharpObject(cx);
#else
	/* Restore obj's property list before bailing on error. */
	obj->map->props = list;
#endif

	JS_UNLOCK(cx);
	if (!ok) {
	    if (chars)
		free(chars);
	    return ok;
	}
    } else
#endif /* JS_HAS_OBJECT_LITERAL */
    {
	clazz = obj->map->clasp->name;
	nchars = 9 + strlen(clazz);		/* 9 for "[object ]" */
	chars = malloc((nchars + 1) * sizeof(jschar));
	if (chars) {
	    prefix = "[object ";
	    nchars = 0;
	    while ((chars[nchars] = (jschar)*prefix) != 0)
		nchars++, prefix++;
	    while ((chars[nchars] = (jschar)*clazz) != 0)
		nchars++, clazz++;
	    chars[nchars++] = ']';
	    chars[nchars] = 0;
	}
    }

#if JS_HAS_SHARP_VARS
  make_string:
#endif
    if (!chars) {
	JS_ReportOutOfMemory(cx);
	return JS_FALSE;
    }
    str = js_NewString(cx, chars, nchars, 0);
    if (!str) {
	free(chars);
	return JS_FALSE;
    }
    *rval = STRING_TO_JSVAL(str);
    return JS_TRUE;
}