mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Try to flush the instruction/data cache less frequently (bug 781510, r=dvander)
This commit is contained in:
parent
c51e209ff8
commit
3bebbbdabc
@ -127,7 +127,8 @@ IonCompartment::IonCompartment()
|
||||
bailoutHandler_(NULL),
|
||||
argumentsRectifier_(NULL),
|
||||
invalidator_(NULL),
|
||||
functionWrappers_(NULL)
|
||||
functionWrappers_(NULL),
|
||||
flusher_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
@ -682,6 +683,7 @@ IonScript::toggleBarriers(bool enabled)
|
||||
void
|
||||
IonScript::purgeCaches()
|
||||
{
|
||||
AutoFlushCache afc("purgeCaches");
|
||||
for (size_t i = 0; i < numCaches(); i++)
|
||||
getCache(i).reset();
|
||||
}
|
||||
@ -689,6 +691,7 @@ IonScript::purgeCaches()
|
||||
void
|
||||
ion::ToggleBarriers(JSCompartment *comp, bool needs)
|
||||
{
|
||||
AutoFlushCache afc("ToggleBarriers");
|
||||
for (gc::CellIterUnderGC i(comp, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (script->hasIonScript())
|
||||
@ -883,6 +886,8 @@ IonCompile(JSContext *cx, JSScript *script, JSFunction *fun, jsbytecode *osrPc,
|
||||
if (!oracle.init(cx, script))
|
||||
return false;
|
||||
|
||||
AutoFlushCache afc("IonCompile");
|
||||
|
||||
types::AutoEnterCompilation enterCompiler(cx, types::AutoEnterCompilation::Ion);
|
||||
enterCompiler.init(script, false, 0);
|
||||
AutoCompilerRoots roots(script->compartment()->rt);
|
||||
@ -1378,6 +1383,7 @@ ion::InvalidateAll(FreeOp *fop, JSCompartment *c)
|
||||
{
|
||||
for (IonActivationIterator iter(fop->runtime()); iter.more(); ++iter) {
|
||||
if (iter.activation()->compartment() == c) {
|
||||
AutoFlushCache afc ("InvalidateAll", c->ionCompartment());
|
||||
IonSpew(IonSpew_Invalidate, "Invalidating all frames for GC");
|
||||
InvalidateActivation(fop, iter.top(), true);
|
||||
}
|
||||
@ -1390,6 +1396,8 @@ ion::Invalidate(types::TypeCompartment &types, FreeOp *fop,
|
||||
const Vector<types::RecompileInfo> &invalid, bool resetUses)
|
||||
{
|
||||
IonSpew(IonSpew_Invalidate, "Start invalidation.");
|
||||
AutoFlushCache afc ("Invalidate");
|
||||
|
||||
// Add an invalidation reference to all invalidated IonScripts to indicate
|
||||
// to the traversal which frames have been invalidated.
|
||||
bool anyInvalidation = false;
|
||||
@ -1517,6 +1525,30 @@ ion::UsesBeforeIonRecompile(JSScript *script, jsbytecode *pc)
|
||||
// Note that we use +1 to prefer non-OSR over OSR.
|
||||
return minUses + (loop->depth + 1) * 100;
|
||||
}
|
||||
void
|
||||
AutoFlushCache::updateTop(uintptr_t p, size_t len)
|
||||
{
|
||||
GetIonContext()->compartment->ionCompartment()->flusher()->update(p, len);
|
||||
}
|
||||
|
||||
AutoFlushCache::AutoFlushCache(const char *nonce, IonCompartment *comp)
|
||||
: start_(NULL), stop_(NULL), name_(nonce), used_(false)
|
||||
{
|
||||
if (comp == NULL) {
|
||||
if (CurrentIonContext() != NULL)
|
||||
comp = GetIonContext()->compartment->ionCompartment();
|
||||
}
|
||||
// If a compartment isn't available, then be a nop, nobody will ever see this flusher
|
||||
if (comp) {
|
||||
if (comp->flusher())
|
||||
IonSpew(IonSpew_CacheFlush, "<%s ", nonce);
|
||||
else
|
||||
IonSpewCont(IonSpew_CacheFlush, "<%s ", nonce);
|
||||
comp->setFlusher(this);
|
||||
} else {
|
||||
IonSpew(IonSpew_CacheFlush, "<%s DEAD>\n", nonce);
|
||||
}
|
||||
myCompartment_ = comp;
|
||||
}
|
||||
int js::ion::LabelBase::id_count = 0;
|
||||
|
||||
|
@ -178,6 +178,7 @@ enum MethodStatus
|
||||
// of the Ion compiler. It points to a temporary allocator and the active
|
||||
// JSContext, either of which may be NULL, and the active compartment, which
|
||||
// will not be NULL.
|
||||
|
||||
class IonContext
|
||||
{
|
||||
public:
|
||||
@ -202,6 +203,7 @@ bool InitializeIon();
|
||||
|
||||
// Get and set the current Ion context.
|
||||
IonContext *GetIonContext();
|
||||
|
||||
bool SetIonContext(IonContext *ctx);
|
||||
|
||||
MethodStatus CanEnterAtBranch(JSContext *cx, JSScript *script,
|
||||
|
@ -293,6 +293,7 @@ TryAttachNativeStub(JSContext *cx, IonCacheGetProperty &cache, HandleObject obj,
|
||||
bool
|
||||
js::ion::GetPropertyCache(JSContext *cx, size_t cacheIndex, HandleObject obj, MutableHandleValue vp)
|
||||
{
|
||||
AutoFlushCache afc ("GetPropertyCache");
|
||||
JSScript *topScript = GetTopIonJSScript(cx);
|
||||
IonScript *ion = topScript->ionScript();
|
||||
|
||||
@ -611,6 +612,8 @@ bool
|
||||
js::ion::SetPropertyCache(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue value,
|
||||
bool isSetName)
|
||||
{
|
||||
AutoFlushCache afc ("SetPropertyCache");
|
||||
|
||||
IonScript *ion = GetTopIonJSScript(cx)->ion;
|
||||
IonCacheSetProperty &cache = ion->getCache(cacheIndex).toSetProperty();
|
||||
RootedPropertyName name(cx, cache.name());
|
||||
@ -781,6 +784,8 @@ bool
|
||||
js::ion::GetElementCache(JSContext *cx, size_t cacheIndex, JSObject *obj, HandleValue idval,
|
||||
MutableHandleValue res)
|
||||
{
|
||||
AutoFlushCache afc ("GetElementCache");
|
||||
|
||||
IonScript *ion = GetTopIonJSScript(cx)->ionScript();
|
||||
|
||||
IonCacheGetElement &cache = ion->getCache(cacheIndex).toGetElement();
|
||||
@ -994,6 +999,8 @@ IsCacheableScopeChain(JSObject *scopeChain, JSObject *holder)
|
||||
JSObject *
|
||||
js::ion::BindNameCache(JSContext *cx, size_t cacheIndex, HandleObject scopeChain)
|
||||
{
|
||||
AutoFlushCache afc ("BindNameCache");
|
||||
|
||||
IonScript *ion = GetTopIonJSScript(cx)->ionScript();
|
||||
IonCacheBindName &cache = ion->getCache(cacheIndex).toBindName();
|
||||
HandlePropertyName name = cache.name();
|
||||
@ -1126,6 +1133,8 @@ IsCacheableName(JSContext *cx, HandleObject scopeChain, HandleObject obj, Handle
|
||||
bool
|
||||
js::ion::GetNameCache(JSContext *cx, size_t cacheIndex, HandleObject scopeChain, MutableHandleValue vp)
|
||||
{
|
||||
AutoFlushCache afc ("GetNameCache");
|
||||
|
||||
IonScript *ion = GetTopIonJSScript(cx)->ionScript();
|
||||
|
||||
IonCacheName &cache = ion->getCache(cacheIndex).toName();
|
||||
|
@ -389,6 +389,24 @@ struct IonScript
|
||||
|
||||
struct VMFunction;
|
||||
|
||||
class IonCompartment;
|
||||
|
||||
struct AutoFlushCache {
|
||||
|
||||
private:
|
||||
uintptr_t start_;
|
||||
uintptr_t stop_;
|
||||
const char *name_;
|
||||
IonCompartment *myCompartment_;
|
||||
bool used_;
|
||||
|
||||
public:
|
||||
void update(uintptr_t p, size_t len);
|
||||
static void updateTop(uintptr_t p, size_t len);
|
||||
~AutoFlushCache();
|
||||
AutoFlushCache(const char * nonce, IonCompartment *comp = NULL);
|
||||
};
|
||||
|
||||
} // namespace ion
|
||||
|
||||
namespace gc {
|
||||
|
@ -55,6 +55,9 @@ class IonCompartment
|
||||
// Map VMFunction addresses to the IonCode of the wrapper.
|
||||
VMWrapperMap *functionWrappers_;
|
||||
|
||||
// Keep track of memoryregions that are going to be flushed.
|
||||
js::ion::AutoFlushCache *flusher_;
|
||||
|
||||
private:
|
||||
IonCode *generateEnterJIT(JSContext *cx);
|
||||
IonCode *generateReturnError(JSContext *cx);
|
||||
@ -139,6 +142,14 @@ class IonCompartment
|
||||
}
|
||||
return preBarrier_;
|
||||
}
|
||||
AutoFlushCache *flusher() {
|
||||
return flusher_;
|
||||
}
|
||||
void setFlusher(AutoFlushCache *fl) {
|
||||
if (!flusher_ || !fl)
|
||||
flusher_ = fl;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class BailoutClosure;
|
||||
|
@ -185,6 +185,7 @@ ion::CheckLogging()
|
||||
" osi Invalidation\n"
|
||||
" safepoints Safepoints\n"
|
||||
" pools Literal Pools (ARM only for now)\n"
|
||||
" cacheflush Instruction Cache flushes (ARM only for now)\n"
|
||||
" logs C1 and JSON visualization logging\n"
|
||||
" all Everything\n"
|
||||
"\n"
|
||||
|
@ -49,7 +49,9 @@ namespace ion {
|
||||
/* Debug info about safepoints */ \
|
||||
_(Safepoints) \
|
||||
/* Debug info about Pools*/ \
|
||||
_(Pools)
|
||||
_(Pools) \
|
||||
/* Debug info about the I$ */ \
|
||||
_(CacheFlush)
|
||||
|
||||
|
||||
enum IonSpewChannel {
|
||||
|
@ -34,10 +34,11 @@ InvokeFunction(JSContext *cx, JSFunction *fun, uint32 argc, Value *argv, Value *
|
||||
|
||||
// In order to prevent massive bouncing between Ion and JM, see if we keep
|
||||
// hitting functions that are uncompilable.
|
||||
|
||||
|
||||
if (fun->isInterpreted() && !fun->script()->canIonCompile()) {
|
||||
JSScript *script = GetTopIonJSScript(cx);
|
||||
if (script->hasIonScript() && ++script->ion->slowCallCount >= js_IonOptions.slowCallLimit) {
|
||||
AutoFlushCache afc("InvokeFunction");
|
||||
Invalidate(cx, script, false);
|
||||
|
||||
// Finally, poison the script so we don't try to run it again
|
||||
|
@ -8,9 +8,10 @@
|
||||
#include "Assembler-arm.h"
|
||||
#include "MacroAssembler-arm.h"
|
||||
#include "gc/Marking.h"
|
||||
|
||||
#include "jsutil.h"
|
||||
#include "assembler/jit/ExecutableAllocator.h"
|
||||
|
||||
#include "jscompartment.h"
|
||||
#include "ion/IonCompartment.h"
|
||||
using namespace js;
|
||||
using namespace js::ion;
|
||||
|
||||
@ -466,8 +467,7 @@ Assembler::executableCopy(uint8 *buffer)
|
||||
{
|
||||
JS_ASSERT(isFinished);
|
||||
m_buffer.executableCopy(buffer);
|
||||
|
||||
JSC::ExecutableAllocator::cacheFlush(buffer, m_buffer.size());
|
||||
AutoFlushCache::updateTop((uintptr_t)buffer, m_buffer.size());
|
||||
}
|
||||
|
||||
void
|
||||
@ -2158,21 +2158,25 @@ Assembler::getBranchOffset(const Instruction *i_)
|
||||
return 0;
|
||||
}
|
||||
void
|
||||
Assembler::retargetNearBranch(Instruction *i, int offset)
|
||||
Assembler::retargetNearBranch(Instruction *i, int offset, bool final)
|
||||
{
|
||||
Assembler::Condition c;
|
||||
i->extractCond(&c);
|
||||
retargetNearBranch(i, offset, c);
|
||||
retargetNearBranch(i, offset, c, final);
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::retargetNearBranch(Instruction *i, int offset, Condition cond)
|
||||
Assembler::retargetNearBranch(Instruction *i, int offset, Condition cond, bool final)
|
||||
{
|
||||
// Retargeting calls is totally unsupported!
|
||||
JS_ASSERT_IF(i->is<InstBranchImm>(), i->is<InstBImm>());
|
||||
new (i) InstBImm(BOffImm(offset), cond);
|
||||
// Flush the cache, since an instruction was overwritten
|
||||
JSC::ExecutableAllocator::cacheFlush(i, 4);
|
||||
if (final) {
|
||||
AutoFlushCache::updateTop(uintptr_t(i), 4);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
@ -2181,7 +2185,7 @@ Assembler::retargetFarBranch(Instruction *i, uint8 **slot, uint8 *dest, Conditio
|
||||
int32 offset = reinterpret_cast<uint8*>(slot) - reinterpret_cast<uint8*>(i);
|
||||
if (!i->is<InstLDR>()) {
|
||||
new (i) InstLDR(Offset, pc, DTRAddr(pc, DtrOffImm(offset - 8)), cond);
|
||||
JSC::ExecutableAllocator::cacheFlush(i, 4);
|
||||
AutoFlushCache::updateTop(uintptr_t(i), 4);
|
||||
}
|
||||
*slot = dest;
|
||||
|
||||
@ -2269,7 +2273,9 @@ Assembler::patchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall
|
||||
uint8 *dest = toCall.raw();
|
||||
new (inst) InstBLImm(BOffImm(dest - (uint8*)inst) , Always);
|
||||
// Ensure everyone sees the code that was just written into memory.
|
||||
JSC::ExecutableAllocator::cacheFlush(inst, sizeof(uint32));
|
||||
|
||||
AutoFlushCache::updateTop(uintptr_t(inst), 4);
|
||||
|
||||
}
|
||||
void
|
||||
Assembler::patchDataWithValueCheck(CodeLocationLabel label, ImmWord newValue, ImmWord expectedValue)
|
||||
@ -2281,7 +2287,9 @@ Assembler::patchDataWithValueCheck(CodeLocationLabel label, ImmWord newValue, Im
|
||||
const uint32 *val = getPtr32Target(&iter, &dest, &rs);
|
||||
JS_ASSERT((uint32)val == expectedValue.value);
|
||||
reinterpret_cast<MacroAssemblerARM*>(dummy)->ma_movPatchable(Imm32(newValue.value), dest, Always, rs, ptr);
|
||||
JSC::ExecutableAllocator::cacheFlush(ptr, sizeof(uintptr_t)*2);
|
||||
|
||||
AutoFlushCache::updateTop(uintptr_t(ptr), 4);
|
||||
AutoFlushCache::updateTop(uintptr_t(ptr->next()), 4);
|
||||
}
|
||||
|
||||
// This just stomps over memory with 32 bits of raw data. Its purpose is to
|
||||
@ -2404,8 +2412,7 @@ Assembler::ToggleToJmp(CodeLocationLabel inst_)
|
||||
// Zero bits 20-27, then set 24-27 to be correct for a branch.
|
||||
// 20-23 will be party of the B's immediate, and should be 0.
|
||||
*ptr = (*ptr & ~(0xff << 20)) | (0xa0 << 20);
|
||||
|
||||
JSC::ExecutableAllocator::cacheFlush(ptr, sizeof(Instruction));
|
||||
AutoFlushCache::updateTop((uintptr_t)ptr, 4);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2428,7 +2435,51 @@ Assembler::ToggleToCmp(CodeLocationLabel inst_)
|
||||
// Zero out bits 20-27, then set them to be correct for a compare.
|
||||
*ptr = (*ptr & ~(0xff << 20)) | (0x35 << 20);
|
||||
|
||||
JSC::ExecutableAllocator::cacheFlush(ptr, sizeof(Instruction));
|
||||
AutoFlushCache::updateTop((uintptr_t)ptr, 4);
|
||||
}
|
||||
|
||||
void
|
||||
AutoFlushCache::update(uintptr_t newStart, size_t len)
|
||||
{
|
||||
uintptr_t newStop = newStart + len;
|
||||
used_ = true;
|
||||
static int count = 0;
|
||||
if (start_ == NULL) {
|
||||
IonSpewCont(IonSpew_CacheFlush, ".");
|
||||
start_ = newStart;
|
||||
stop_ = newStop;
|
||||
return;
|
||||
}
|
||||
|
||||
if (newStop < start_ - 4096 || newStart > stop_ + 4096) {
|
||||
// If this would add too many pages to the range, bail and just do the flush now.
|
||||
IonSpewCont(IonSpew_CacheFlush, "*");
|
||||
JSC::ExecutableAllocator::cacheFlush((void*)newStart, len);
|
||||
return;
|
||||
}
|
||||
start_ = Min(start_, newStart);
|
||||
stop_ = Max(stop_, newStop);
|
||||
IonSpewCont(IonSpew_CacheFlush, ".");
|
||||
}
|
||||
|
||||
AutoFlushCache::~AutoFlushCache()
|
||||
{
|
||||
if (!myCompartment_)
|
||||
return;
|
||||
|
||||
IonSpewCont(IonSpew_CacheFlush, ">", name_);
|
||||
if (myCompartment_->flusher() == this) {
|
||||
IonSpewFin(IonSpew_CacheFlush);
|
||||
myCompartment_->setFlusher(NULL);
|
||||
}
|
||||
if (!used_) {
|
||||
return;
|
||||
}
|
||||
if (start_ != NULL) {
|
||||
JSC::ExecutableAllocator::cacheFlush((void*)start_, (size_t)(stop_ - start_ + sizeof(Instruction)));
|
||||
} else {
|
||||
JSC::ExecutableAllocator::cacheFlush(NULL, 0xff000000);
|
||||
}
|
||||
|
||||
}
|
||||
Assembler *Assembler::dummy = NULL;
|
||||
|
@ -1026,7 +1026,7 @@ void
|
||||
PatchJump(CodeLocationJump &jump_, CodeLocationLabel label);
|
||||
class InstructionIterator;
|
||||
class Assembler;
|
||||
typedef js::ion::AssemblerBufferWithConstantPool<16, 4, Instruction, Assembler, 1> ARMBuffer;
|
||||
typedef js::ion::AssemblerBufferWithConstantPool<1024, 4, Instruction, Assembler, 1> ARMBuffer;
|
||||
|
||||
class Assembler
|
||||
{
|
||||
@ -1649,8 +1649,8 @@ class Assembler
|
||||
// this should return a BOffImm, but I didn't want to require everyplace that used the
|
||||
// AssemblerBuffer to make that class.
|
||||
static ptrdiff_t getBranchOffset(const Instruction *i);
|
||||
static void retargetNearBranch(Instruction *i, int offset, Condition cond);
|
||||
static void retargetNearBranch(Instruction *i, int offset);
|
||||
static void retargetNearBranch(Instruction *i, int offset, Condition cond, bool final = true);
|
||||
static void retargetNearBranch(Instruction *i, int offset, bool final = true);
|
||||
static void retargetFarBranch(Instruction *i, uint8 **slot, uint8 *dest, Condition cond);
|
||||
|
||||
static void writePoolHeader(uint8 *start, Pool *p, bool isNatural);
|
||||
@ -1669,6 +1669,7 @@ class Assembler
|
||||
}
|
||||
static uint8 *nextInstruction(uint8 *instruction, uint32 *count = NULL);
|
||||
// Toggle a jmp or cmp emitted by toggledJump().
|
||||
|
||||
static void ToggleToJmp(CodeLocationLabel inst_);
|
||||
static void ToggleToCmp(CodeLocationLabel inst_);
|
||||
|
||||
|
@ -72,6 +72,8 @@ struct EnterJITStack
|
||||
IonCode *
|
||||
IonCompartment::generateEnterJIT(JSContext *cx)
|
||||
{
|
||||
AutoFlushCache afc("GenerateEnterJIT", cx->compartment->ionCompartment());
|
||||
|
||||
const Register reg_code = r0;
|
||||
const Register reg_argc = r1;
|
||||
const Register reg_argv = r2;
|
||||
|
@ -489,6 +489,7 @@ class CodeLocationLabel
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace ion
|
||||
} // namespace js
|
||||
|
||||
|
@ -129,3 +129,16 @@ AssemblerX86Shared::InvertCondition(Condition cond)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AutoFlushCache::update(uintptr_t newStart, size_t len)
|
||||
{
|
||||
}
|
||||
|
||||
AutoFlushCache::~AutoFlushCache()
|
||||
{
|
||||
if (!myCompartment_)
|
||||
return;
|
||||
|
||||
if (myCompartment_->flusher() == this)
|
||||
myCompartment_->setFlusher(NULL);
|
||||
}
|
||||
|
@ -935,7 +935,7 @@ struct AssemblerBufferWithConstantPool : public AssemblerBuffer<SliceSize, Inst>
|
||||
}
|
||||
// Can't assert anything here, since the first pool may be after the target.
|
||||
}
|
||||
Asm::retargetNearBranch(i, offset);
|
||||
Asm::retargetNearBranch(i, offset, false);
|
||||
}
|
||||
|
||||
// Mark the next instruction as a valid guard. This means we can place a pool here.
|
||||
|
@ -5478,9 +5478,11 @@ PurgeJITCaches(JSCompartment *c)
|
||||
}
|
||||
|
||||
#ifdef JS_ION
|
||||
/* Discard Ion caches. */
|
||||
|
||||
/* Discard Ion caches. */
|
||||
if (script->hasIonScript())
|
||||
script->ion->purgeCaches();
|
||||
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user