зеркало из https://github.com/mozilla/gecko-dev.git
Back out incorrect patch for bug 497789 (r=jorendorff).
This commit is contained in:
Родитель
9ed1b5714e
Коммит
e4eb26eec9
|
@ -115,10 +115,12 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj,
|
|||
JSPropertyCache *cache;
|
||||
jsbytecode *pc;
|
||||
JSScope *scope;
|
||||
jsuword kshape, vshape;
|
||||
jsuword kshape, vshape, khash;
|
||||
JSOp op;
|
||||
const JSCodeSpec *cs;
|
||||
jsuword vword;
|
||||
ptrdiff_t pcoff;
|
||||
JSAtom *atom;
|
||||
JSPropCacheEntry *entry;
|
||||
|
||||
JS_ASSERT(!cx->runtime->gcRunning);
|
||||
|
@ -311,11 +313,19 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj,
|
|||
vshape = scope->shape;
|
||||
}
|
||||
|
||||
khash = PROPERTY_CACHE_HASH_PC(pc, kshape);
|
||||
if (obj == pobj) {
|
||||
JS_ASSERT(scopeIndex == 0 && protoIndex == 0);
|
||||
JS_ASSERT(OBJ_SCOPE(obj)->object == obj);
|
||||
JS_ASSERT(kshape != 0);
|
||||
} else {
|
||||
if (op == JSOP_LENGTH) {
|
||||
atom = cx->runtime->atomState.lengthAtom;
|
||||
} else {
|
||||
pcoff = (JOF_TYPE(cs->format) == JOF_SLOTATOM) ? SLOTNO_LEN : 0;
|
||||
GET_ATOM_FROM_BYTECODE(cx->fp->script, pc, pcoff, atom);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (scopeIndex == 0) {
|
||||
JS_ASSERT(protoIndex != 0);
|
||||
|
@ -324,6 +334,12 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj,
|
|||
#endif
|
||||
|
||||
if (scopeIndex != 0 || protoIndex != 1) {
|
||||
khash = PROPERTY_CACHE_HASH_ATOM(atom, obj, pobj);
|
||||
PCMETER(if (PCVCAP_TAG(cache->table[khash].vcap) <= 1)
|
||||
cache->pcrecycles++);
|
||||
pc = (jsbytecode *) atom;
|
||||
kshape = (jsuword) obj;
|
||||
|
||||
/*
|
||||
* Make sure that a later shadowing assignment will enter
|
||||
* PurgeProtoChain and invalidate this entry, bug 479198.
|
||||
|
@ -338,7 +354,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj,
|
|||
}
|
||||
}
|
||||
|
||||
entry = &cache->table[PROPERTY_CACHE_HASH_PC(pc, kshape)];
|
||||
entry = &cache->table[khash];
|
||||
PCMETER(PCVAL_IS_NULL(entry->vword) || cache->recycles++);
|
||||
entry->kpc = pc;
|
||||
entry->kshape = kshape;
|
||||
|
@ -357,41 +373,42 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj,
|
|||
return entry;
|
||||
}
|
||||
|
||||
static inline JS_REQUIRES_STACK JSAtom *
|
||||
GetAtomFromBytecode(JSContext *cx, jsbytecode *pc, JSOp op, const JSCodeSpec *cs)
|
||||
{
|
||||
if (op == JSOP_LENGTH)
|
||||
return cx->runtime->atomState.lengthAtom;
|
||||
|
||||
ptrdiff_t pcoff = (JOF_TYPE(cs->format) == JOF_SLOTATOM) ? SLOTNO_LEN : 0;
|
||||
JSAtom *atom;
|
||||
GET_ATOM_FROM_BYTECODE(cx->fp->script, pc, pcoff, atom);
|
||||
return atom;
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK JSAtom *
|
||||
js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc,
|
||||
JSObject **objp, JSObject **pobjp,
|
||||
JSPropCacheEntry *entry)
|
||||
JSPropCacheEntry **entryp)
|
||||
{
|
||||
JSOp op;
|
||||
const JSCodeSpec *cs;
|
||||
ptrdiff_t pcoff;
|
||||
JSAtom *atom;
|
||||
JSObject *obj, *pobj, *tmp;
|
||||
JSPropCacheEntry *entry;
|
||||
uint32 vcap;
|
||||
|
||||
JS_ASSERT(uintN((cx->fp->imacpc ? cx->fp->imacpc : pc) - cx->fp->script->code)
|
||||
< cx->fp->script->length);
|
||||
|
||||
JSOp op = js_GetOpcode(cx, cx->fp->script, pc);
|
||||
const JSCodeSpec *cs = &js_CodeSpec[op];
|
||||
op = js_GetOpcode(cx, cx->fp->script, pc);
|
||||
cs = &js_CodeSpec[op];
|
||||
if (op == JSOP_LENGTH) {
|
||||
atom = cx->runtime->atomState.lengthAtom;
|
||||
} else {
|
||||
pcoff = (JOF_TYPE(cs->format) == JOF_SLOTATOM) ? SLOTNO_LEN : 0;
|
||||
GET_ATOM_FROM_BYTECODE(cx->fp->script, pc, pcoff, atom);
|
||||
}
|
||||
|
||||
obj = *objp;
|
||||
JS_ASSERT(OBJ_IS_NATIVE(obj));
|
||||
entry = &JS_PROPERTY_CACHE(cx).table[PROPERTY_CACHE_HASH_ATOM(atom, obj, NULL)];
|
||||
*entryp = entry;
|
||||
vcap = entry->vcap;
|
||||
|
||||
if (entry->kpc != pc) {
|
||||
PCMETER(JS_PROPERTY_CACHE(cx).kpcmisses++);
|
||||
if (entry->kpc != (jsbytecode *) atom) {
|
||||
PCMETER(JS_PROPERTY_CACHE(cx).idmisses++);
|
||||
|
||||
JSAtom *atom = GetAtomFromBytecode(cx, pc, op, cs);
|
||||
#ifdef DEBUG_notme
|
||||
entry = &JS_PROPERTY_CACHE(cx).table[PROPERTY_CACHE_HASH_PC(pc, OBJ_SHAPE(obj))];
|
||||
fprintf(stderr,
|
||||
"id miss for %s from %s:%u"
|
||||
" (pc %u, kpc %u, kshape %u, shape %u)\n",
|
||||
|
@ -410,15 +427,11 @@ js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc,
|
|||
return atom;
|
||||
}
|
||||
|
||||
if (entry->kshape != OBJ_SHAPE(obj)) {
|
||||
PCMETER(JS_PROPERTY_CACHE(cx).kshmisses++);
|
||||
return GetAtomFromBytecode(cx, pc, op, cs);
|
||||
if (entry->kshape != (jsuword) obj) {
|
||||
PCMETER(JS_PROPERTY_CACHE(cx).komisses++);
|
||||
return atom;
|
||||
}
|
||||
|
||||
/*
|
||||
* PROPERTY_CACHE_TEST handles only the direct and immediate-prototype hit
|
||||
* cases, all others go here.
|
||||
*/
|
||||
pobj = obj;
|
||||
|
||||
if (JOF_MODE(cs->format) == JOF_NAME) {
|
||||
|
@ -443,7 +456,6 @@ js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc,
|
|||
|
||||
if (JS_LOCK_OBJ_IF_SHAPE(cx, pobj, PCVCAP_SHAPE(vcap))) {
|
||||
#ifdef DEBUG
|
||||
JSAtom *atom = GetAtomFromBytecode(cx, pc, op, cs);
|
||||
jsid id = ATOM_TO_JSID(atom);
|
||||
|
||||
CHECK_FOR_STRING_INDEX(id);
|
||||
|
@ -455,7 +467,7 @@ js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc,
|
|||
}
|
||||
|
||||
PCMETER(JS_PROPERTY_CACHE(cx).vcmisses++);
|
||||
return GetAtomFromBytecode(cx, pc, op, cs);
|
||||
return atom;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -510,6 +522,7 @@ js_PurgePropertyCache(JSContext *cx, JSPropertyCache *cache)
|
|||
P(noprotos);
|
||||
P(longchains);
|
||||
P(recycles);
|
||||
P(pcrecycles);
|
||||
P(tests);
|
||||
P(pchits);
|
||||
P(protopchits);
|
||||
|
@ -522,8 +535,8 @@ js_PurgePropertyCache(JSContext *cx, JSPropertyCache *cache)
|
|||
P(setpcmisses);
|
||||
P(slotchanges);
|
||||
P(setmisses);
|
||||
P(kpcmisses);
|
||||
P(kshmisses);
|
||||
P(idmisses);
|
||||
P(komisses);
|
||||
P(vcmisses);
|
||||
P(misses);
|
||||
P(flushes);
|
||||
|
@ -556,8 +569,9 @@ js_PurgePropertyCacheForScript(JSContext *cx, JSScript *script)
|
|||
entry++) {
|
||||
if (JS_UPTRDIFF(entry->kpc, script->code) < script->length) {
|
||||
entry->kpc = NULL;
|
||||
entry->kshape = 0;
|
||||
#ifdef DEBUG
|
||||
entry->kshape = entry->vcap = entry->vword = 0;
|
||||
entry->vcap = entry->vword = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -4796,7 +4810,7 @@ js_Interpret(JSContext *cx)
|
|||
}
|
||||
|
||||
atom = js_FullTestPropertyCache(cx, regs.pc, &obj, &obj2,
|
||||
entry);
|
||||
&entry);
|
||||
if (atom) {
|
||||
PCMETER(cache->misses++);
|
||||
PCMETER(cache->setmisses++);
|
||||
|
|
|
@ -217,6 +217,9 @@ typedef struct JSInlineFrame {
|
|||
#define PROPERTY_CACHE_HASH_PC(pc,kshape) \
|
||||
PROPERTY_CACHE_HASH(pc, kshape)
|
||||
|
||||
#define PROPERTY_CACHE_HASH_ATOM(atom,obj,pobj) \
|
||||
PROPERTY_CACHE_HASH((jsuword)(atom) >> 2, OBJ_SHAPE(obj))
|
||||
|
||||
/*
|
||||
* Property cache value capability macros.
|
||||
*/
|
||||
|
@ -279,6 +282,8 @@ typedef struct JSPropertyCache {
|
|||
uint32 noprotos; /* resolve-returned non-proto pobj */
|
||||
uint32 longchains; /* overlong scope and/or proto chain */
|
||||
uint32 recycles; /* cache entries recycled by fills */
|
||||
uint32 pcrecycles; /* pc-keyed entries recycled by atom-
|
||||
keyed fills */
|
||||
uint32 tests; /* cache probes */
|
||||
uint32 pchits; /* fast-path polymorphic op hits */
|
||||
uint32 protopchits; /* pchits hitting immediate prototype */
|
||||
|
@ -292,8 +297,8 @@ typedef struct JSPropertyCache {
|
|||
uint32 slotchanges; /* clasp->reserveSlots result variance-
|
||||
induced slot changes */
|
||||
uint32 setmisses; /* JSOP_SET{NAME,PROP} total misses */
|
||||
uint32 kpcmisses; /* slow-path key pc misses */
|
||||
uint32 kshmisses; /* slow-path key shape misses */
|
||||
uint32 idmisses; /* slow-path key id == atom misses */
|
||||
uint32 komisses; /* slow-path key object misses */
|
||||
uint32 vcmisses; /* value capability misses */
|
||||
uint32 misses; /* cache misses */
|
||||
uint32 flushes; /* cache flushes */
|
||||
|
@ -375,6 +380,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj,
|
|||
if (entry->kpc == pc && entry->kshape == kshape_) { \
|
||||
JSObject *tmp_; \
|
||||
pobj = obj; \
|
||||
JS_ASSERT(PCVCAP_TAG(entry->vcap) <= 1); \
|
||||
if (PCVCAP_TAG(entry->vcap) == 1 && \
|
||||
(tmp_ = OBJ_GET_PROTO(cx, pobj)) != NULL && \
|
||||
OBJ_IS_NATIVE(tmp_)) { \
|
||||
|
@ -382,7 +388,6 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj,
|
|||
} \
|
||||
\
|
||||
if (JS_LOCK_OBJ_IF_SHAPE(cx, pobj, PCVCAP_SHAPE(entry->vcap))) { \
|
||||
JS_ASSERT(PCVCAP_TAG(entry->vcap) <= 1); \
|
||||
PCMETER(cache_->pchits++); \
|
||||
PCMETER(!PCVCAP_TAG(entry->vcap) || cache_->protopchits++); \
|
||||
pobj = OBJ_SCOPE(pobj)->object; \
|
||||
|
@ -390,7 +395,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj,
|
|||
break; \
|
||||
} \
|
||||
} \
|
||||
atom = js_FullTestPropertyCache(cx, pc, &obj, &pobj, entry); \
|
||||
atom = js_FullTestPropertyCache(cx, pc, &obj, &pobj, &entry); \
|
||||
if (atom) \
|
||||
PCMETER(cache_->misses++); \
|
||||
} while (0)
|
||||
|
@ -398,7 +403,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj,
|
|||
extern JS_REQUIRES_STACK JSAtom *
|
||||
js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc,
|
||||
JSObject **objp, JSObject **pobjp,
|
||||
JSPropCacheEntry *entry);
|
||||
JSPropCacheEntry **entryp);
|
||||
|
||||
/* The property cache does not need a destructor. */
|
||||
#define js_FinishPropertyCache(cache) ((void) 0)
|
||||
|
|
|
@ -110,12 +110,8 @@ js_GetMutableScope(JSContext *cx, JSObject *obj)
|
|||
static void
|
||||
InitMinimalScope(JSContext *cx, JSScope *scope)
|
||||
{
|
||||
JSObject *obj = scope->object;
|
||||
js_LeaveTraceIfGlobalObject(cx, obj);
|
||||
|
||||
JSObject *proto = OBJ_GET_PROTO(cx, obj);
|
||||
scope->shape = (proto && OBJ_IS_NATIVE(proto)) ? OBJ_SHAPE(proto) : 0;
|
||||
|
||||
js_LeaveTraceIfGlobalObject(cx, scope->object);
|
||||
scope->shape = 0;
|
||||
scope->hashShift = JS_DHASH_BITS - MIN_SCOPE_SIZE_LOG2;
|
||||
scope->entryCount = scope->removedCount = 0;
|
||||
scope->table = NULL;
|
||||
|
@ -1022,7 +1018,7 @@ js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
|
|||
uintN attrs, uintN flags, intN shortid)
|
||||
{
|
||||
JSScopeProperty **spp, *sprop, *overwriting, **spvec, **spp2, child;
|
||||
uintN size, splen, i;
|
||||
uint32 size, splen, i;
|
||||
int change;
|
||||
JSTempValueRooter tvr;
|
||||
|
||||
|
@ -1202,25 +1198,19 @@ js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
|
|||
* sprop, while the former simply tests whether sprop->id
|
||||
* is bound in scope.
|
||||
*/
|
||||
if (SCOPE_GET_PROPERTY(scope, sprop->id)) {
|
||||
JS_ASSERT(sprop != overwriting);
|
||||
spvec[--i] = sprop;
|
||||
}
|
||||
sprop = sprop->parent;
|
||||
} while (i != 0);
|
||||
if (!SCOPE_GET_PROPERTY(scope, sprop->id))
|
||||
continue;
|
||||
|
||||
JSObject *proto = OBJ_GET_PROTO(cx, scope->object);
|
||||
if (proto && OBJ_IS_NATIVE(proto))
|
||||
sprop = OBJ_SCOPE(proto)->lastProp;
|
||||
JS_ASSERT(sprop != overwriting);
|
||||
JS_ASSERT(i != 0);
|
||||
spvec[--i] = sprop;
|
||||
} while ((sprop = sprop->parent) != NULL);
|
||||
JS_ASSERT(i == 0);
|
||||
|
||||
/*
|
||||
* Now loop forward through spvec, forking the property tree
|
||||
* whenever we see a "parent gap" due to deletions from scope.
|
||||
*
|
||||
* NB: sprop is null on first entry to the loop body only for
|
||||
* Object.prototype or an object orphaned from it by having its
|
||||
* __proto__ set to null (or via ES5 Object.create with a null
|
||||
* proto parameter).
|
||||
* NB: sprop is null on first entry to the loop body.
|
||||
*/
|
||||
do {
|
||||
if (spvec[i]->parent == sprop) {
|
||||
|
|
|
@ -7450,17 +7450,33 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2
|
|||
JS_ASSERT(cx->requestDepth);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Guard on the shape of the directly accessed native object, unless it's
|
||||
* the global object whose shape can't change on trace.
|
||||
*/
|
||||
if (aobj != globalObj) {
|
||||
LIns* shape_ins = addName(lir->insLoad(LIR_ld, map_ins, offsetof(JSScope, shape)),
|
||||
"shape");
|
||||
guard(true,
|
||||
addName(lir->ins2i(LIR_eq, shape_ins, entry->kshape),
|
||||
"guard(kshape)(test_property_cache)"),
|
||||
BRANCH_EXIT);
|
||||
// Emit guard(s), common code for both hit and miss cases.
|
||||
// Check for first-level cache hit and guard on kshape if possible.
|
||||
// Otherwise guard on key object exact match.
|
||||
if (PCVCAP_TAG(entry->vcap) <= 1) {
|
||||
if (aobj != globalObj) {
|
||||
LIns* shape_ins = addName(lir->insLoad(LIR_ld, map_ins, offsetof(JSScope, shape)),
|
||||
"shape");
|
||||
guard(true, addName(lir->ins2i(LIR_eq, shape_ins, entry->kshape), "guard(kshape)(test_property_cache)"),
|
||||
BRANCH_EXIT);
|
||||
}
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
JSOp op = js_GetOpcode(cx, cx->fp->script, pc);
|
||||
JSAtom *pcatom;
|
||||
if (op == JSOP_LENGTH) {
|
||||
pcatom = cx->runtime->atomState.lengthAtom;
|
||||
} else {
|
||||
ptrdiff_t pcoff = (JOF_TYPE(js_CodeSpec[op].format) == JOF_SLOTATOM) ? SLOTNO_LEN : 0;
|
||||
GET_ATOM_FROM_BYTECODE(cx->fp->script, pc, pcoff, pcatom);
|
||||
}
|
||||
JS_ASSERT(entry->kpc == (jsbytecode *) pcatom);
|
||||
JS_ASSERT(entry->kshape == jsuword(aobj));
|
||||
#endif
|
||||
if (aobj != globalObj && !obj_ins->isconstp()) {
|
||||
guard(true, addName(lir->ins2i(LIR_eq, obj_ins, entry->kshape), "guard(kobj)"),
|
||||
BRANCH_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
// For any hit that goes up the scope and/or proto chains, we will need to
|
||||
|
|
Загрузка…
Ссылка в новой задаче