mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 04:27:37 +00:00
[INFER] Address array review comments, add back backedge table, bug 657412.
This commit is contained in:
parent
1bc79b5ebc
commit
8b1926a6bf
@ -51,21 +51,35 @@
|
||||
* getArrayLength(), setArrayLength().
|
||||
* - The number of element slots (capacity), gettable with
|
||||
* getDenseArrayCapacity().
|
||||
* - The array's initialized length, accessible with getDenseArrayInitializedLength().
|
||||
* - The array's initialized length, accessible with
|
||||
* getDenseArrayInitializedLength().
|
||||
*
|
||||
* In dense mode, holes in the array are represented by
|
||||
* MagicValue(JS_ARRAY_HOLE) invalid values. Elements between the initialized
|
||||
* length and the length property are left uninitialized, but are conceptually holes.
|
||||
* Arrays with no holes below the initialized length are "packed" arrays.
|
||||
* MagicValue(JS_ARRAY_HOLE) invalid values.
|
||||
*
|
||||
* NB: the capacity and length of a dense array are entirely unrelated! The
|
||||
* length may be greater than, less than, or equal to the capacity. The first
|
||||
* case may occur when the user writes "new Array(100), in which case the
|
||||
* length is 100 while the capacity remains 0 (indices below length and above
|
||||
* capacity must be treated as holes). See array_length_setter for another
|
||||
* explanation of how the first case may occur. When type inference is enabled,
|
||||
* the initialized length is always less than or equal to both the length and
|
||||
* capacity. Otherwise, the initialized length always equals the capacity.
|
||||
* explanation of how the first case may occur.
|
||||
*
|
||||
* The initialized length of a dense array specifies the number of elements
|
||||
* that have been initialized. All elements above the initialized length are
|
||||
* holes in the array, and the memory for all elements between the initialized
|
||||
* length and capacity is left uninitialized. When type inference is disabled,
|
||||
* the initialized length always equals the array's capacity. When inference is
|
||||
* enabled, the initialized length is some value less than or equal to both the
|
||||
* array's length and the array's capacity.
|
||||
*
|
||||
* With inference enabled, there is flexibility in exactly the value the
|
||||
* initialized length must hold, e.g. if an array has length 5, capacity 10,
|
||||
* completely empty, it is valid for the initialized length to be any value
|
||||
* between zero and 5, as long as the in memory values below the initialized
|
||||
* length have been initialized with a hole value. However, in such cases we
|
||||
* want to keep the initialized length as small as possible: if the array is
|
||||
* known to have no hole values below its initialized length, then it is a
|
||||
* "packed" array and can be accessed much faster by JIT code.
|
||||
*
|
||||
* Arrays are converted to use js_SlowArrayClass when any of these conditions
|
||||
* are met:
|
||||
@ -520,7 +534,7 @@ DeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index, bool strict)
|
||||
if (index <= jsuint(-1)) {
|
||||
jsuint idx = jsuint(index);
|
||||
if (idx < obj->getDenseArrayInitializedLength()) {
|
||||
obj->setDenseArrayNotPacked(cx);
|
||||
obj->markDenseArrayNotPacked(cx);
|
||||
obj->setDenseArrayElement(idx, MagicValue(JS_ARRAY_HOLE));
|
||||
if (!js_SuppressDeletedIndexProperties(cx, obj, idx, idx+1))
|
||||
return -1;
|
||||
@ -645,7 +659,7 @@ array_length_setter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value
|
||||
if (oldinit > newlen) {
|
||||
obj->setDenseArrayInitializedLength(newlen);
|
||||
if (!cx->typeInferenceEnabled())
|
||||
obj->backfillDenseArrayHoles();
|
||||
obj->backfillDenseArrayHoles(cx);
|
||||
}
|
||||
} else if (oldlen - newlen < (1 << 24)) {
|
||||
do {
|
||||
@ -938,7 +952,7 @@ array_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool
|
||||
}
|
||||
|
||||
if (js_IdIsIndex(id, &i) && i < obj->getDenseArrayInitializedLength()) {
|
||||
obj->setDenseArrayNotPacked(cx);
|
||||
obj->markDenseArrayNotPacked(cx);
|
||||
obj->setDenseArrayElement(i, MagicValue(JS_ARRAY_HOLE));
|
||||
}
|
||||
|
||||
@ -956,8 +970,8 @@ array_trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isDenseArray());
|
||||
|
||||
uint32 capacity = obj->getDenseArrayInitializedLength();
|
||||
MarkValueRange(trc, capacity, obj->getDenseArrayElements(), "element");
|
||||
uint32 initLength = obj->getDenseArrayInitializedLength();
|
||||
MarkValueRange(trc, initLength, obj->getDenseArrayElements(), "element");
|
||||
}
|
||||
|
||||
static JSBool
|
||||
@ -1048,7 +1062,7 @@ JSObject::makeDenseArraySlow(JSContext *cx)
|
||||
cx->markTypeObjectFlags(getType(),
|
||||
js::types::OBJECT_FLAG_NON_PACKED_ARRAY |
|
||||
js::types::OBJECT_FLAG_NON_DENSE_ARRAY);
|
||||
setDenseArrayNotPacked(cx);
|
||||
markDenseArrayNotPacked(cx);
|
||||
|
||||
/*
|
||||
* Save old map now, before calling InitScopeForObject. We'll have to undo
|
||||
@ -1062,7 +1076,7 @@ JSObject::makeDenseArraySlow(JSContext *cx)
|
||||
if (!InitScopeForObject(cx, this, &js_SlowArrayClass, getType(), kind))
|
||||
return false;
|
||||
|
||||
backfillDenseArrayHoles();
|
||||
backfillDenseArrayHoles(cx);
|
||||
|
||||
uint32 arrayCapacity = getDenseArrayCapacity();
|
||||
uint32 arrayInitialized = getDenseArrayInitializedLength();
|
||||
@ -1569,7 +1583,7 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const Value *vector
|
||||
if (cx->typeInferenceEnabled())
|
||||
obj->setDenseArrayInitializedLength(length);
|
||||
else
|
||||
obj->backfillDenseArrayHoles();
|
||||
obj->backfillDenseArrayHoles(cx);
|
||||
|
||||
bool hole = false;
|
||||
for (jsuint i = 0; i < length; i++) {
|
||||
@ -1577,7 +1591,7 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const Value *vector
|
||||
hole |= vector[i].isMagic(JS_ARRAY_HOLE);
|
||||
}
|
||||
if (hole)
|
||||
obj->setDenseArrayNotPacked(cx);
|
||||
obj->markDenseArrayNotPacked(cx);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1645,13 +1659,7 @@ array_reverse(JSContext *cx, uintN argc, Value *vp)
|
||||
}
|
||||
|
||||
/* Fill out the array's initialized length to its proper length. */
|
||||
jsuint initlen = obj->getDenseArrayInitializedLength();
|
||||
if (len > initlen) {
|
||||
JS_ASSERT(cx->typeInferenceEnabled());
|
||||
ClearValueRange(obj->getDenseArrayElements() + initlen, len - initlen, true);
|
||||
obj->setDenseArrayNotPacked(cx);
|
||||
obj->setDenseArrayInitializedLength(len);
|
||||
}
|
||||
obj->ensureDenseArrayInitializedLength(cx, len, 0);
|
||||
|
||||
uint32 lo = 0, hi = len - 1;
|
||||
for (; lo < hi; lo++, hi--) {
|
||||
@ -2230,8 +2238,6 @@ ArrayCompPushImpl(JSContext *cx, JSObject *obj, const Value &v)
|
||||
*/
|
||||
if (!obj->ensureSlots(cx, length + 1))
|
||||
return false;
|
||||
if (!cx->typeInferenceEnabled())
|
||||
obj->backfillDenseArrayHoles();
|
||||
}
|
||||
|
||||
if (cx->typeInferenceEnabled())
|
||||
@ -2680,7 +2686,7 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
|
||||
nobj->setType(aobj->getType());
|
||||
nobj->setArrayLength(cx, length);
|
||||
if (!aobj->isPackedDenseArray())
|
||||
nobj->setDenseArrayNotPacked(cx);
|
||||
nobj->markDenseArrayNotPacked(cx);
|
||||
vp->setObject(*nobj);
|
||||
if (argc == 0)
|
||||
return JS_TRUE;
|
||||
@ -2812,7 +2818,7 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
|
||||
return JS_FALSE;
|
||||
nobj->setType(type);
|
||||
if (!obj->isPackedDenseArray())
|
||||
nobj->setDenseArrayNotPacked(cx);
|
||||
nobj->markDenseArrayNotPacked(cx);
|
||||
vp->setObject(*nobj);
|
||||
return JS_TRUE;
|
||||
}
|
||||
@ -3500,13 +3506,13 @@ NewArray(JSContext *cx, jsuint length, JSObject *proto)
|
||||
|
||||
obj->setArrayLength(cx, length);
|
||||
|
||||
if (allocateCapacity) {
|
||||
if (!obj->ensureSlots(cx, length))
|
||||
return NULL;
|
||||
if (!cx->typeInferenceEnabled()) {
|
||||
obj->markDenseArrayNotPacked(cx);
|
||||
obj->backfillDenseArrayHoles(cx);
|
||||
}
|
||||
|
||||
if (!cx->typeInferenceEnabled())
|
||||
obj->backfillDenseArrayHoles();
|
||||
if (allocateCapacity && !obj->ensureSlots(cx, length))
|
||||
return NULL;
|
||||
|
||||
return obj;
|
||||
}
|
||||
@ -3751,7 +3757,7 @@ js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone)
|
||||
return JS_FALSE;
|
||||
|
||||
if (!obj->isPackedDenseArray())
|
||||
(*clone)->setDenseArrayNotPacked(cx);
|
||||
(*clone)->markDenseArrayNotPacked(cx);
|
||||
|
||||
/* The length will be set to the initlen, above, but length might be larger. */
|
||||
(*clone)->setArrayLength(cx, length);
|
||||
|
@ -75,7 +75,7 @@ JSObject::isPackedDenseArray()
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setDenseArrayNotPacked(JSContext *cx)
|
||||
JSObject::markDenseArrayNotPacked(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
if (flags & PACKED_ARRAY) {
|
||||
@ -84,33 +84,48 @@ JSObject::setDenseArrayNotPacked(JSContext *cx)
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::backfillDenseArrayHoles(JSContext *cx)
|
||||
{
|
||||
/* Ensure an array's elements are fully initialized. */
|
||||
ensureDenseArrayInitializedLength(cx, getDenseArrayCapacity(), 0);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::ensureDenseArrayInitializedLength(JSContext *cx, uint32 index, uint32 extra)
|
||||
{
|
||||
/*
|
||||
* Ensure that the array's contents have been initialized up to index, and
|
||||
* mark the elements through 'index + extra' as initialized in preparation
|
||||
* for a write.
|
||||
*/
|
||||
JS_ASSERT(index + extra <= capacity);
|
||||
if (initializedLength < index) {
|
||||
markDenseArrayNotPacked(cx);
|
||||
ClearValueRange(slots + initializedLength, index - initializedLength, true);
|
||||
}
|
||||
if (initializedLength < index + extra)
|
||||
initializedLength = index + extra;
|
||||
}
|
||||
|
||||
inline JSObject::EnsureDenseResult
|
||||
JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra)
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
|
||||
uintN currentCapacity = numSlots();
|
||||
uintN initLength = getDenseArrayInitializedLength();
|
||||
|
||||
/*
|
||||
* Don't take excessive slow paths when inference is disabled, due to
|
||||
* uninitialized slots between initializedLength and capacity.
|
||||
*/
|
||||
JS_ASSERT_IF(!cx->typeInferenceEnabled(), currentCapacity == initLength);
|
||||
JS_ASSERT_IF(!cx->typeInferenceEnabled(), currentCapacity == getDenseArrayInitializedLength());
|
||||
|
||||
uintN requiredCapacity;
|
||||
if (extra == 1) {
|
||||
/* Optimize for the common case. */
|
||||
if (index < initLength)
|
||||
return ED_OK;
|
||||
if (index < currentCapacity) {
|
||||
JS_ASSERT(cx->typeInferenceEnabled());
|
||||
if (index > initLength) {
|
||||
setDenseArrayNotPacked(cx);
|
||||
ClearValueRange(getDenseArrayElements() + initLength,
|
||||
index - initLength, true);
|
||||
}
|
||||
setDenseArrayInitializedLength(index + 1);
|
||||
ensureDenseArrayInitializedLength(cx, index, 1);
|
||||
return ED_OK;
|
||||
}
|
||||
requiredCapacity = index + 1;
|
||||
@ -124,16 +139,8 @@ JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra)
|
||||
/* Overflow. */
|
||||
return ED_SPARSE;
|
||||
}
|
||||
if (requiredCapacity <= initLength)
|
||||
return ED_OK;
|
||||
if (requiredCapacity <= currentCapacity) {
|
||||
JS_ASSERT(cx->typeInferenceEnabled());
|
||||
if (index > initLength) {
|
||||
ClearValueRange(getDenseArrayElements() + initLength,
|
||||
index - initLength, true);
|
||||
setDenseArrayNotPacked(cx);
|
||||
}
|
||||
setDenseArrayInitializedLength(requiredCapacity);
|
||||
ensureDenseArrayInitializedLength(cx, index, extra);
|
||||
return ED_OK;
|
||||
}
|
||||
}
|
||||
@ -149,17 +156,7 @@ JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra)
|
||||
if (!growSlots(cx, requiredCapacity))
|
||||
return ED_FAILED;
|
||||
|
||||
if (cx->typeInferenceEnabled()) {
|
||||
if (index > initLength) {
|
||||
setDenseArrayNotPacked(cx);
|
||||
ClearValueRange(getDenseArrayElements() + initLength,
|
||||
index - initLength, true);
|
||||
}
|
||||
setDenseArrayInitializedLength(requiredCapacity);
|
||||
} else {
|
||||
backfillDenseArrayHoles();
|
||||
}
|
||||
|
||||
ensureDenseArrayInitializedLength(cx, index, extra);
|
||||
return ED_OK;
|
||||
}
|
||||
|
||||
|
@ -145,6 +145,9 @@ JSCompartment::init(JSContext *cx)
|
||||
if (!regExpAllocator)
|
||||
return false;
|
||||
|
||||
if (!backEdgeTable.init())
|
||||
return false;
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
jaegerCompartment = rt->new_<mjit::JaegerCompartment>();
|
||||
if (!jaegerCompartment || !jaegerCompartment->Initialize())
|
||||
@ -643,3 +646,20 @@ JSCompartment::allocMathCache(JSContext *cx)
|
||||
js_ReportOutOfMemory(cx);
|
||||
return mathCache;
|
||||
}
|
||||
|
||||
size_t
|
||||
JSCompartment::backEdgeCount(jsbytecode *pc) const
|
||||
{
|
||||
if (BackEdgeMap::Ptr p = backEdgeTable.lookup(pc))
|
||||
return p->value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
JSCompartment::incBackEdgeCount(jsbytecode *pc)
|
||||
{
|
||||
if (BackEdgeMap::Ptr p = backEdgeTable.lookupWithDefault(pc, 0))
|
||||
return ++p->value;
|
||||
return 1; /* oom not reported by backEdgeTable, so ignore. */
|
||||
}
|
||||
|
@ -518,11 +518,21 @@ struct JS_FRIEND_API(JSCompartment) {
|
||||
|
||||
js::MathCache *allocMathCache(JSContext *cx);
|
||||
|
||||
typedef js::HashMap<jsbytecode*,
|
||||
size_t,
|
||||
js::DefaultHasher<jsbytecode*>,
|
||||
js::SystemAllocPolicy> BackEdgeMap;
|
||||
|
||||
BackEdgeMap backEdgeTable;
|
||||
|
||||
JSCompartment *thisForCtor() { return this; }
|
||||
public:
|
||||
js::MathCache *getMathCache(JSContext *cx) {
|
||||
return mathCache ? mathCache : allocMathCache(cx);
|
||||
}
|
||||
|
||||
size_t backEdgeCount(jsbytecode *pc) const;
|
||||
size_t incBackEdgeCount(jsbytecode *pc);
|
||||
};
|
||||
|
||||
#define JS_SCRIPTS_TO_GC(cx) ((cx)->compartment->scriptsToGC)
|
||||
|
@ -122,12 +122,19 @@ const size_t SLOTS_TO_THING_KIND_LIMIT = 17;
|
||||
|
||||
/* Get the best kind to use when making an object with the given slot count. */
|
||||
static inline FinalizeKind
|
||||
GetGCObjectKind(size_t numSlots)
|
||||
GetGCObjectKind(size_t numSlots, bool isArray = false)
|
||||
{
|
||||
extern FinalizeKind slotsToThingKind[];
|
||||
|
||||
if (numSlots >= SLOTS_TO_THING_KIND_LIMIT)
|
||||
return FINALIZE_OBJECT16;
|
||||
if (numSlots >= SLOTS_TO_THING_KIND_LIMIT) {
|
||||
/*
|
||||
* If the object will definitely want more than the maximum number of
|
||||
* fixed slots, use zero fixed slots for arrays and the maximum for
|
||||
* other objects. Arrays do not use their fixed slots anymore when
|
||||
* they have a slots array, while other objects will continue to do so.
|
||||
*/
|
||||
return isArray ? FINALIZE_OBJECT0 : FINALIZE_OBJECT16;
|
||||
}
|
||||
return slotsToThingKind[numSlots];
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,6 @@
|
||||
|
||||
using namespace js;
|
||||
using namespace js::gc;
|
||||
using namespace js::types;
|
||||
|
||||
static void iterator_finalize(JSContext *cx, JSObject *obj);
|
||||
static void iterator_trace(JSTracer *trc, JSObject *obj);
|
||||
|
@ -4356,8 +4356,9 @@ JSObject::allocSlots(JSContext *cx, size_t newcap)
|
||||
|
||||
if (isDenseArray()) {
|
||||
/* Copy over anything from the inline buffer. */
|
||||
memcpy(slots, fixedSlots(), oldcap * sizeof(Value));
|
||||
ClearValueRange(slots + oldcap, newcap - oldcap, true);
|
||||
memcpy(slots, fixedSlots(), getDenseArrayInitializedLength() * sizeof(Value));
|
||||
if (!cx->typeInferenceEnabled())
|
||||
backfillDenseArrayHoles(cx);
|
||||
} else {
|
||||
/* Clear out the new slots without copying. */
|
||||
ClearValueRange(slots, allocCount, false);
|
||||
@ -4413,8 +4414,11 @@ JSObject::growSlots(JSContext *cx, size_t newcap)
|
||||
slots = tmpslots;
|
||||
capacity = actualCapacity;
|
||||
|
||||
if (!isDenseArray()) {
|
||||
/* Initialize the additional slots we added. This is not required for dense arrays. */
|
||||
if (isDenseArray()) {
|
||||
if (!cx->typeInferenceEnabled())
|
||||
backfillDenseArrayHoles(cx);
|
||||
} else {
|
||||
/* Clear the new slots we added. */
|
||||
ClearValueRange(slots + oldAllocCount, allocCount - oldAllocCount, false);
|
||||
}
|
||||
|
||||
|
@ -851,6 +851,8 @@ struct JSObject : js::gc::Cell {
|
||||
inline uint32 getDenseArrayInitializedLength();
|
||||
inline void setDenseArrayLength(uint32 length);
|
||||
inline void setDenseArrayInitializedLength(uint32 length);
|
||||
inline void ensureDenseArrayInitializedLength(JSContext *cx, uintN index, uintN extra);
|
||||
inline void backfillDenseArrayHoles(JSContext *cx);
|
||||
inline js::Value* getDenseArrayElements();
|
||||
inline const js::Value &getDenseArrayElement(uintN idx);
|
||||
inline js::Value* addressOfDenseArrayElement(uintN idx);
|
||||
@ -858,11 +860,10 @@ struct JSObject : js::gc::Cell {
|
||||
inline void setDenseArrayElementWithType(JSContext *cx, uintN idx, const js::Value &val);
|
||||
inline void shrinkDenseArrayElements(JSContext *cx, uintN cap);
|
||||
inline bool denseArrayHasInlineSlots() const;
|
||||
inline void backfillDenseArrayHoles();
|
||||
|
||||
/* Packed information for this array. May be incorrect if !cx->typeInferenceEnabled(). */
|
||||
/* Packed information for this array. */
|
||||
inline bool isPackedDenseArray();
|
||||
inline void setDenseArrayNotPacked(JSContext *cx);
|
||||
inline void markDenseArrayNotPacked(JSContext *cx);
|
||||
|
||||
/*
|
||||
* ensureDenseArrayElements ensures that the dense array can hold at least
|
||||
|
@ -530,15 +530,6 @@ JSObject::denseArrayHasInlineSlots() const
|
||||
return slots == fixedSlots();
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::backfillDenseArrayHoles()
|
||||
{
|
||||
/* Only call this if !cx->typeInferenceEnabled(). */
|
||||
JS_ASSERT(isDenseArray());
|
||||
ClearValueRange(slots + initializedLength, capacity - initializedLength, true);
|
||||
initializedLength = capacity;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::callIsForEval() const
|
||||
{
|
||||
@ -895,18 +886,20 @@ JSObject::init(JSContext *cx, js::Class *aclasp, js::types::TypeObject *type,
|
||||
|
||||
/*
|
||||
* Fill the fixed slots with undefined if needed. This object must
|
||||
* already have its capacity filled in, as by js_NewGCObject.
|
||||
* already have its capacity filled in, as by js_NewGCObject. If inference
|
||||
* is disabled, NewArray will backfill holes up to the array's capacity
|
||||
* and unset the PACKED_ARRAY flag.
|
||||
*/
|
||||
slots = NULL;
|
||||
ClearValueRange(fixedSlots(), capacity, useHoles);
|
||||
if (useHoles) {
|
||||
slots = fixedSlots();
|
||||
flags |= PACKED_ARRAY;
|
||||
} else {
|
||||
ClearValueRange(fixedSlots(), capacity, useHoles);
|
||||
}
|
||||
|
||||
newType = NULL;
|
||||
JS_ASSERT(initializedLength == 0);
|
||||
initializedLength = 0;
|
||||
|
||||
setType(type);
|
||||
setParent(parent);
|
||||
@ -1564,7 +1557,7 @@ static inline gc::FinalizeKind
|
||||
GuessObjectGCKind(size_t numSlots, bool isArray)
|
||||
{
|
||||
if (numSlots)
|
||||
return gc::GetGCObjectKind(numSlots);
|
||||
return gc::GetGCObjectKind(numSlots, isArray);
|
||||
return isArray ? gc::FINALIZE_OBJECT8 : gc::FINALIZE_OBJECT4;
|
||||
}
|
||||
|
||||
|
@ -1202,8 +1202,9 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
|
||||
jitTraceICs[i].slowTraceHint = stubCode.locationOf(traceICs[i].slowTraceHint.get());
|
||||
#ifdef JS_TRACER
|
||||
uint32 hotloop = GetHotloop(cx);
|
||||
uint32 prevCount = cx->compartment->backEdgeCount(traceICs[i].jumpTarget);
|
||||
jitTraceICs[i].loopCounterStart = hotloop;
|
||||
jitTraceICs[i].loopCounter = hotloop;
|
||||
jitTraceICs[i].loopCounter = hotloop < prevCount ? 1 : hotloop - prevCount;
|
||||
#endif
|
||||
|
||||
stubCode.patch(traceICs[i].addrLabel, &jitTraceICs[i]);
|
||||
|
@ -107,11 +107,22 @@ CanMethodJITAtBranch(JSContext *cx, JSScript *script, StackFrame *fp, jsbytecode
|
||||
JITScriptStatus status = script->getJITStatus(fp->isConstructing());
|
||||
if (status == JITScript_Invalid)
|
||||
return Compile_Abort;
|
||||
if (status == JITScript_None &&
|
||||
!cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS) &&
|
||||
script->incUseCount() <= USES_BEFORE_COMPILE)
|
||||
{
|
||||
return Compile_Skipped;
|
||||
if (status == JITScript_None && !cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS)) {
|
||||
/*
|
||||
* Backedges are counted differently with type inference vs. with the
|
||||
* tracer. For inference, we use the script's use count, so that we can
|
||||
* easily reset the script's uses if we end up recompiling it. For the
|
||||
* tracer, we use the compartment's backedge table so that when
|
||||
* compiling trace ICs we will retain counts for each loop and respect
|
||||
* the HOTLOOP value when deciding to start recording traces.
|
||||
*/
|
||||
if (cx->typeInferenceEnabled()) {
|
||||
if (script->incUseCount() <= USES_BEFORE_COMPILE)
|
||||
return Compile_Skipped;
|
||||
} else {
|
||||
if (cx->compartment->incBackEdgeCount(pc) <= USES_BEFORE_COMPILE)
|
||||
return Compile_Skipped;
|
||||
}
|
||||
}
|
||||
if (status == JITScript_None)
|
||||
return TryCompile(cx, fp);
|
||||
|
Loading…
Reference in New Issue
Block a user