JSAtomListElement * js_IndexAtom(JSContext *cx, JSAtom *atom, JSAtomList *al) { JSAtomListElement *ale, *ale2, *next; JSHashEntry **hep; ATOM_LIST_LOOKUP(ale, hep, al, atom); if (!ale) { if (al->count < 10) { /* Few enough for linear search, no hash table needed. */ JS_ASSERT(!al->table); ale = (JSAtomListElement *)js_alloc_temp_entry(cx, atom); if (!ale) return NULL; ALE_SET_ATOM(ale, atom); ALE_SET_NEXT(ale, al->list); al->list = ale; } else { /* We want to hash. Have we already made a hash table? */ if (!al->table) { /* No hash table yet, so hep had better be null! */ JS_ASSERT(!hep); al->table = JS_NewHashTable(al->count + 1, js_hash_atom_ptr, JS_CompareValues, JS_CompareValues, &temp_alloc_ops, cx); if (!al->table) return NULL; /* * Set ht->nentries explicitly, because we are moving entries * from al to ht, not calling JS_HashTable(Raw|)Add. */ al->table->nentries = al->count; /* Insert each ale on al->list into the new hash table. */ for (ale2 = al->list; ale2; ale2 = next) { next = ALE_NEXT(ale2); ale2->entry.keyHash = ALE_ATOM(ale2)->number; hep = JS_HashTableRawLookup(al->table, ale2->entry.keyHash, ale2->entry.key); ALE_SET_NEXT(ale2, *hep); *hep = &ale2->entry; } al->list = NULL; /* Set hep for insertion of atom's ale, immediately below. */ hep = JS_HashTableRawLookup(al->table, atom->number, atom); } /* Finally, add an entry for atom into the hash bucket at hep. */ ale = (JSAtomListElement *) JS_HashTableRawAdd(al->table, hep, atom->number, atom, NULL); if (!ale) return NULL; } ALE_SET_INDEX(ale, al->count++); } return ale; }
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; }
/* * Remove the mapping of a JS object from the hash table that maps JS objects * to Java objects. This is called from the finalizer of an instance of * netscape.javascript.JSObject. */ JSBool jsj_remove_js_obj_reflection_from_hashtable(JSContext *cx, JSObject *js_obj) { JSHashEntry *he, **hep; JSBool success = JS_FALSE; #ifdef JSJ_THREADSAFE PR_EnterMonitor(js_obj_reflections_monitor); #endif /* Get the hash-table entry for this wrapper object */ hep = JS_HashTableRawLookup(js_obj_reflections, (JSHashNumber)js_obj, js_obj); he = *hep; JS_ASSERT(he); if (he) { /* Tell the JS GC that Java no longer keeps a reference to this JS object. */ success = JS_RemoveRoot(cx, (void *)&he->key); JS_HashTableRawRemove(js_obj_reflections, hep, he); } #ifdef JSJ_THREADSAFE PR_ExitMonitor(js_obj_reflections_monitor); #endif return success; }
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; }
JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **&hep, JSHashNumber keyHash, const void *key, void *value) { uint32 n; JSHashEntry *he; /* Grow the table if it is overloaded */ n = NBUCKETS(ht); if (ht->nentries >= OVERLOADED(n)) { if (!Resize(ht, ht->shift - 1)) return NULL; #ifdef JS_HASHMETER ht->ngrows++; #endif hep = JS_HashTableRawLookup(ht, keyHash, key); } /* Make a new key value entry */ he = ht->allocOps->allocEntry(ht->allocPriv, key); if (!he) return NULL; he->keyHash = keyHash; he->key = key; he->value = value; he->next = *hep; *hep = he; ht->nentries++; return he; }
JS_HashTableLookup(JSHashTable *ht, const void *key) { JSHashNumber keyHash; JSHashEntry *he, **hep; keyHash = ht->keyHash(key); hep = JS_HashTableRawLookup(ht, keyHash, key); if ((he = *hep) != NULL) { return he->value; } return NULL; }
JS_HashTableRemove(JSHashTable *ht, const void *key) { JSHashNumber keyHash; JSHashEntry *he, **hep; keyHash = ht->keyHash(key); hep = JS_HashTableRawLookup(ht, keyHash, key); if ((he = *hep) == NULL) return JS_FALSE; /* Hit; remove element */ JS_HashTableRawRemove(ht, hep, he); return JS_TRUE; }
JS_HashTableAdd(JSHashTable *ht, const void *key, void *value) { JSHashNumber keyHash; JSHashEntry *he, **hep; keyHash = ht->keyHash(key); hep = JS_HashTableRawLookup(ht, keyHash, key); if ((he = *hep) != NULL) { /* Hit; see if values match */ if (ht->valueCompare(he->value, value)) { /* key,value pair is already present in table */ return he; } if (he->value) ht->allocOps->freeEntry(ht->allocPriv, he, HT_FREE_VALUE); he->value = value; return he; } return JS_HashTableRawAdd(ht, hep, keyHash, key, value); }
JSAtomListElement * JSAtomList::rawLookup(JSAtom *atom, JSHashEntry **&hep) { JSAtomListElement *ale; if (table) { hep = JS_HashTableRawLookup(table, ATOM_HASH(atom), atom); ale = *hep ? (JSAtomListElement *) *hep : NULL; } else { JSHashEntry **alep = &list; hep = NULL; while ((ale = (JSAtomListElement *)*alep) != NULL) { if (ALE_ATOM(ale) == atom) { /* Hit, move atom's element to the front of the list. */ *alep = ale->entry.next; ale->entry.next = list; list = &ale->entry; break; } alep = &ale->entry.next; } } return ale; }
JSAtomListElement * JSAtomList::add(JSCompiler *jsc, JSAtom *atom, AddHow how) { JS_ASSERT(!set); JSAtomListElement *ale, *ale2, *next; JSHashEntry **hep; ale = rawLookup(atom, hep); if (!ale || how != UNIQUE) { if (count < ATOM_LIST_HASH_THRESHOLD && !table) { /* Few enough for linear search and no hash table yet needed. */ ale = (JSAtomListElement *)js_alloc_temp_entry(jsc, atom); if (!ale) return NULL; ALE_SET_ATOM(ale, atom); if (how == HOIST) { ale->entry.next = NULL; hep = (JSHashEntry **) &list; while (*hep) hep = &(*hep)->next; *hep = &ale->entry; } else { ale->entry.next = list; list = &ale->entry; } } else { /* * We should hash, or else we already are hashing, but count was * reduced by JSAtomList::rawRemove below ATOM_LIST_HASH_THRESHOLD. * Check whether we should create the table. */ if (!table) { /* No hash table yet, so hep had better be null! */ JS_ASSERT(!hep); table = JS_NewHashTable(count + 1, js_hash_atom_ptr, JS_CompareValues, JS_CompareValues, &temp_alloc_ops, jsc); if (!table) return NULL; /* * Set ht->nentries explicitly, because we are moving entries * from list to ht, not calling JS_HashTable(Raw|)Add. */ table->nentries = count; /* * Insert each ale on list into the new hash table. Append to * the hash chain rather than inserting at the bucket head, to * preserve order among entries with the same key. */ for (ale2 = (JSAtomListElement *)list; ale2; ale2 = next) { next = ALE_NEXT(ale2); ale2->entry.keyHash = ATOM_HASH(ALE_ATOM(ale2)); hep = JS_HashTableRawLookup(table, ale2->entry.keyHash, ale2->entry.key); while (*hep) hep = &(*hep)->next; *hep = &ale2->entry; ale2->entry.next = NULL; } list = NULL; /* Set hep for insertion of atom's ale, immediately below. */ hep = JS_HashTableRawLookup(table, ATOM_HASH(atom), atom); } /* Finally, add an entry for atom into the hash bucket at hep. */ ale = (JSAtomListElement *) JS_HashTableRawAdd(table, hep, ATOM_HASH(atom), atom, NULL); if (!ale) return NULL; /* * If hoisting, move ale to the end of its chain after we called * JS_HashTableRawAdd, since RawAdd may have grown the table and * then recomputed hep to refer to the pointer to the first entry * with the given key. */ if (how == HOIST && ale->entry.next) { JS_ASSERT(*hep == &ale->entry); *hep = ale->entry.next; ale->entry.next = NULL; do { hep = &(*hep)->next; } while (*hep); *hep = &ale->entry; } } ALE_SET_INDEX(ale, count++); } return ale; }
jobject jsj_WrapJSObject(JSContext *cx, JNIEnv *jEnv, JSObject *js_obj) { jobject java_wrapper_obj; JSHashEntry *he, **hep; java_wrapper_obj = NULL; #ifdef JSJ_THREADSAFE PR_EnterMonitor(js_obj_reflections_monitor); #endif /* First, look in the hash table for an existing reflection of the same JavaScript object. If one is found, return it. */ hep = JS_HashTableRawLookup(js_obj_reflections, (JSHashNumber)js_obj, js_obj); /* If the same JSObject is reflected into Java more than once then we should return the same Java object, both for efficiency and so that the '==' operator works as expected in Java when comparing two JSObjects. However, it is not possible to hold a reference to a Java object without inhibiting GC of that object, at least not in a portable way, i.e. a weak reference. So, for now, JSObject identity is broken. */ he = *hep; if (he) { java_wrapper_obj = (jobject)he->value; JS_ASSERT(java_wrapper_obj); if (java_wrapper_obj) goto done; } /* No existing reflection found, so create a new Java object that wraps the JavaScript object by storing its address in a private integer field. */ #ifndef OJI java_wrapper_obj = (*jEnv)->NewObject(jEnv, njJSObject, njJSObject_JSObject, (jint)js_obj); #else if (JSJ_callbacks && JSJ_callbacks->get_java_wrapper != NULL) { java_wrapper_obj = JSJ_callbacks->get_java_wrapper(jEnv, (jint)handle); } #endif /*! OJI */ if (!java_wrapper_obj) { jsj_UnexpectedJavaError(cx, jEnv, "Couldn't create new instance of " "netscape.javascript.JSObject"); goto done; } /* Add the new reflection to the hash table. */ he = JS_HashTableRawAdd(js_obj_reflections, hep, (JSHashNumber)js_obj, js_obj, java_wrapper_obj); if (he) { /* Tell the JavaScript GC about this object since the only reference to it may be in Java-land. */ JS_AddNamedRoot(cx, (void*)&he->key, "&he->key"); } else { JS_ReportOutOfMemory(cx); /* No need to delete java_wrapper_obj because Java GC will reclaim it */ java_wrapper_obj = NULL; } /* * Release local reference to wrapper object, since some JVMs seem reticent * about collecting it otherwise. */ /* FIXME -- beard: this seems to make calls into Java with JSObject's fail. */ /* We should really be creating a global ref if we are putting it in a hash table. */ /* (*jEnv)->DeleteLocalRef(jEnv, java_wrapper_obj); */ done: #ifdef JSJ_THREADSAFE PR_ExitMonitor(js_obj_reflections_monitor); #endif return java_wrapper_obj; }
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; }