⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jsscope.c

📁 java script test programing source code
💻 C
📖 第 1 页 / 共 5 页
字号:
}/* * Called *without* the runtime lock held, this function acquires that lock * only when inserting a new child.  Thus there may be races to find or add * a node that result in duplicates.  We expect such races to be rare! */static JSScopeProperty *GetPropertyTreeChild(JSContext *cx, JSScopeProperty *parent,                     JSScopeProperty *child){    JSRuntime *rt;    JSPropertyTreeEntry *entry;    JSScopeProperty *sprop;    PropTreeKidsChunk *chunk;    uintN i;    rt = cx->runtime;    if (!parent) {        JS_LOCK_RUNTIME(rt);        entry = (JSPropertyTreeEntry *)            JS_DHashTableOperate(&rt->propertyTreeHash, child, JS_DHASH_ADD);        if (!entry)            goto out_of_memory;        sprop = entry->child;        if (sprop)            goto out;    } else {        /*         * Because chunks are appended at the end and never deleted except by         * the GC, we can search without taking the runtime lock.  We may miss         * a matching sprop added by another thread, and make a duplicate one,         * but that is an unlikely, therefore small, cost.  The property tree         * has extremely low fan-out below its root in popular embeddings with         * real-world workloads.         *         * If workload changes so as to increase fan-out significantly below         * the property tree root, we'll want to add another tag bit stored in         * parent->kids that indicates a JSDHashTable pointer.         */        entry = NULL;        sprop = parent->kids;        if (sprop) {            if (KIDS_IS_CHUNKY(sprop)) {                chunk = KIDS_TO_CHUNK(sprop);                do {                    for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) {                        sprop = chunk->kids[i];                        if (!sprop)                            goto not_found;                        if (SPROP_MATCH(sprop, child))                            return sprop;                    }                } while ((chunk = chunk->next) != NULL);            } else {                if (SPROP_MATCH(sprop, child))                    return sprop;            }        }    not_found:        JS_LOCK_RUNTIME(rt);    }    sprop = NewScopeProperty(rt);    if (!sprop)        goto out_of_memory;    sprop->id = child->id;    sprop->getter = child->getter;    sprop->setter = child->setter;    sprop->slot = child->slot;    sprop->attrs = child->attrs;    sprop->flags = child->flags;    sprop->shortid = child->shortid;    sprop->parent = sprop->kids = NULL;    if (!parent) {        entry->child = sprop;    } else {        if (!InsertPropertyTreeChild(rt, parent, sprop, NULL))            goto out_of_memory;    }out:    JS_UNLOCK_RUNTIME(rt);    return sprop;out_of_memory:    JS_UNLOCK_RUNTIME(rt);    JS_ReportOutOfMemory(cx);    return NULL;}#ifdef DEBUG_notbrendan#define CHECK_ANCESTOR_LINE(scope, sparse)                                    \    JS_BEGIN_MACRO                                                            \        if ((scope)->table) CheckAncestorLine(scope, sparse);                 \    JS_END_MACROstatic voidCheckAncestorLine(JSScope *scope, JSBool sparse){    uint32 size;    JSScopeProperty **spp, **start, **end, *ancestorLine, *sprop, *aprop;    uint32 entryCount, ancestorCount;    ancestorLine = SCOPE_LAST_PROP(scope);    if (ancestorLine)        JS_ASSERT(SCOPE_HAS_PROPERTY(scope, ancestorLine));    entryCount = 0;    size = SCOPE_CAPACITY(scope);    start = scope->table;    for (spp = start, end = start + size; spp < end; spp++) {        sprop = SPROP_FETCH(spp);        if (sprop) {            entryCount++;            for (aprop = ancestorLine; aprop; aprop = aprop->parent) {                if (aprop == sprop)                    break;            }            JS_ASSERT(aprop);        }    }    JS_ASSERT(entryCount == scope->entryCount);    ancestorCount = 0;    for (sprop = ancestorLine; sprop; sprop = sprop->parent) {        if (SCOPE_HAD_MIDDLE_DELETE(scope) &&            !SCOPE_HAS_PROPERTY(scope, sprop)) {            JS_ASSERT(sparse || (sprop->flags & SPROP_IS_DUPLICATE));            continue;        }        ancestorCount++;    }    JS_ASSERT(ancestorCount == scope->entryCount);}#else#define CHECK_ANCESTOR_LINE(scope, sparse) /* nothing */#endifstatic voidReportReadOnlyScope(JSContext *cx, JSScope *scope){    JSString *str;    str = js_ValueToString(cx, OBJECT_TO_JSVAL(scope->object));    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_READ_ONLY,                         str                         ? JS_GetStringBytes(str)                         : LOCKED_OBJ_GET_CLASS(scope->object)->name);}JSScopeProperty *js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,                    JSPropertyOp getter, JSPropertyOp setter, uint32 slot,                    uintN attrs, uintN flags, intN shortid){    JSScopeProperty **spp, *sprop, *overwriting, **spvec, **spp2, child;    uint32 size, splen, i;    int change;    JSTempValueRooter tvr;    JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, scope));    CHECK_ANCESTOR_LINE(scope, JS_TRUE);    /*     * You can't add properties to a sealed scope.  But note well that you can     * change property attributes in a sealed scope, even though that replaces     * a JSScopeProperty * in the scope's hash table -- but no id is added, so     * the scope remains sealed.     */    if (SCOPE_IS_SEALED(scope)) {        ReportReadOnlyScope(cx, scope);        return NULL;    }    /*     * Normalize stub getter and setter values for faster is-stub testing in     * the SPROP_CALL_[GS]ETTER macros.     */    if (getter == JS_PropertyStub)        getter = NULL;    if (setter == JS_PropertyStub)        setter = NULL;    /*     * Search for id in order to claim its entry, allocating a property tree     * node if one doesn't already exist for our parameters.     */    spp = js_SearchScope(scope, id, JS_TRUE);    sprop = overwriting = SPROP_FETCH(spp);    if (!sprop) {        /* Check whether we need to grow, if the load factor is >= .75. */        size = SCOPE_CAPACITY(scope);        if (scope->entryCount + scope->removedCount >= size - (size >> 2)) {            if (scope->removedCount >= size >> 2) {                METER(compresses);                change = 0;            } else {                METER(grows);                change = 1;            }            if (!ChangeScope(cx, scope, change) &&                scope->entryCount + scope->removedCount == size - 1) {                METER(addFailures);                return NULL;            }            spp = js_SearchScope(scope, id, JS_TRUE);            JS_ASSERT(!SPROP_FETCH(spp));        }    } else {        /* Property exists: js_SearchScope must have returned a valid entry. */        JS_ASSERT(!SPROP_IS_REMOVED(*spp));        /*         * If all property members match, this is a redundant add and we can         * return early.  If the caller wants to allocate a slot, but doesn't         * care which slot, copy sprop->slot into slot so we can match sprop,         * if all other members match.         */        if (!(attrs & JSPROP_SHARED) &&            slot == SPROP_INVALID_SLOT &&            SPROP_HAS_VALID_SLOT(sprop, scope)) {            slot = sprop->slot;        }        if (SPROP_MATCH_PARAMS_AFTER_ID(sprop, getter, setter, slot, attrs,                                        flags, shortid)) {            METER(redundantAdds);            return sprop;        }        /*         * Duplicate formal parameters require us to leave the old property         * on the ancestor line, so the decompiler can find it, even though         * its entry in scope->table is overwritten to point at a new property         * descending from the old one.  The SPROP_IS_DUPLICATE flag helps us         * cope with the consequent disparity between ancestor line height and         * scope->entryCount.         */        if (flags & SPROP_IS_DUPLICATE) {            sprop->flags |= SPROP_IS_DUPLICATE;        } else {            /*             * If we are clearing sprop to force an existing property to be             * overwritten (apart from a duplicate formal parameter), we must             * unlink it from the ancestor line at scope->lastProp, lazily if             * sprop is not lastProp.  And we must remove the entry at *spp,             * precisely so the lazy "middle delete" fixup code further below             * won't find sprop in scope->table, in spite of sprop being on             * the ancestor line.             *             * When we finally succeed in finding or creating a new sprop             * and storing its pointer at *spp, we'll use the |overwriting|             * local saved when we first looked up id to decide whether we're             * indeed creating a new entry, or merely overwriting an existing             * property.             */            if (sprop == SCOPE_LAST_PROP(scope)) {                do {                    SCOPE_REMOVE_LAST_PROP(scope);                    if (!SCOPE_HAD_MIDDLE_DELETE(scope))                        break;                    sprop = SCOPE_LAST_PROP(scope);                } while (sprop && !SCOPE_HAS_PROPERTY(scope, sprop));            } else if (!SCOPE_HAD_MIDDLE_DELETE(scope)) {                /*                 * If we have no hash table yet, we need one now.  The middle                 * delete code is simple-minded that way!                 */                if (!scope->table) {                    if (!CreateScopeTable(cx, scope, JS_TRUE))                        return NULL;                    spp = js_SearchScope(scope, id, JS_TRUE);                    sprop = overwriting = SPROP_FETCH(spp);                }                SCOPE_SET_MIDDLE_DELETE(scope);            }        }        /*         * If we fail later on trying to find or create a new sprop, we will         * goto fail_overwrite and restore *spp from |overwriting|.  Note that         * we don't bother to keep scope->removedCount in sync, because we'll         * fix up *spp and scope->entryCount shortly, no matter how control         * flow returns from this function.         */        if (scope->table)            SPROP_STORE_PRESERVING_COLLISION(spp, NULL);        scope->entryCount--;        CHECK_ANCESTOR_LINE(scope, JS_TRUE);        sprop = NULL;    }    if (!sprop) {        /*         * If properties were deleted from the middle of the list starting at         * scope->lastProp, we may need to fork the property tree and squeeze         * all deleted properties out of scope's ancestor line.  Otherwise we         * risk adding a node with the same id as a "middle" node, violating         * the rule that properties along an ancestor line have distinct ids         * (unless flagged SPROP_IS_DUPLICATE).         */        if (SCOPE_HAD_MIDDLE_DELETE(scope)) {            JS_ASSERT(scope->table);            CHECK_ANCESTOR_LINE(scope, JS_TRUE);            splen = scope->entryCount;            if (splen == 0) {                JS_ASSERT(scope->lastProp == NULL);            } else {                /*                 * Enumerate live entries in scope->table using a temporary                 * vector, by walking the (possibly sparse, due to deletions)                 * ancestor line from scope->lastProp.                 */                spvec = (JSScopeProperty **)                        JS_malloc(cx, SCOPE_TABLE_NBYTES(splen));                if (!spvec)                    goto fail_overwrite;                i = splen;                sprop = SCOPE_LAST_PROP(scope);                JS_ASSERT(sprop);                do {                    /*                     * NB: test SCOPE_GET_PROPERTY, not SCOPE_HAS_PROPERTY --                     * the latter insists that sprop->id maps to sprop, while                     * the former simply tests whether sprop->id is bound in                     * scope.  We must allow for duplicate formal parameters                     * along the ancestor line, and fork them as needed.                     */                    if (!SCOPE_GET_PROPERTY(scope, sprop->id))                        continue;                    JS_ASSERT(sprop != overwriting);                    if (i == 0) {                        /*                         * If our original splen estimate, scope->entryCount,                         * is less than the ancestor line height, there must                         * be duplicate formal parameters in this (function                         * object) scope.  Count remaining ancestors in order                         * to realloc spvec.                         */                        JSScopeProperty *tmp = sprop;                        do {                            if (SCOPE_GET_PROPERTY(scope, tmp->id))                                i++;                        } while ((tmp = tmp->parent) != NULL);                        spp2 = (JSScopeProperty **)                             JS_realloc(cx, spvec, SCOPE_TABLE_NBYTES(splen+i));                        if (!spp2) {                            JS_free(cx, spvec);                            goto fail_overwrite;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -