[JAEGER] Added monomorphic inline cache for reads of unbound globals.
This commit is contained in:
@@ -44,7 +44,9 @@
|
||||
#include "jslibmath.h"
|
||||
#include "Compiler.h"
|
||||
#include "StubCalls.h"
|
||||
#include "MonoIC.h"
|
||||
#include "assembler/jit/ExecutableAllocator.h"
|
||||
#include "assembler/assembler/LinkBuffer.h"
|
||||
#include "FrameState-inl.h"
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
@@ -70,7 +72,7 @@ NotCheckedSSE2;
|
||||
mjit::Compiler::Compiler(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeChain)
|
||||
: cx(cx), script(script), scopeChain(scopeChain), globalObj(scopeChain->getGlobal()), fun(fun),
|
||||
analysis(cx, script), jumpMap(NULL), frame(cx, script, masm),
|
||||
branchPatches(ContextAllocPolicy(cx)), stubcc(cx, *this, frame, script)
|
||||
branchPatches(ContextAllocPolicy(cx)), mics(ContextAllocPolicy(cx)), stubcc(cx, *this, frame, script)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -227,6 +229,24 @@ mjit::Compiler::finishThisUp()
|
||||
}
|
||||
}
|
||||
|
||||
if (mics.length()) {
|
||||
script->mics = (ic::MICInfo *)cx->calloc(sizeof(ic::MICInfo) * mics.length());
|
||||
if (!script->mics) {
|
||||
execPool->release();
|
||||
return Compile_Error;
|
||||
}
|
||||
}
|
||||
|
||||
JSC::LinkBuffer fullCode(result, masm.size() + stubcc.size());
|
||||
JSC::LinkBuffer stubCode(result + masm.size(), stubcc.size());
|
||||
for (size_t i = 0; i < mics.length(); i++) {
|
||||
script->mics[i].entry = fullCode.locationOf(mics[i].entry);
|
||||
script->mics[i].load = fullCode.locationOf(mics[i].load);
|
||||
script->mics[i].shape = fullCode.locationOf(mics[i].shapeVal);
|
||||
script->mics[i].stubCall = stubCode.locationOf(mics[i].call);
|
||||
script->mics[i].stubEntry = stubCode.locationOf(mics[i].stubEntry);
|
||||
}
|
||||
|
||||
/* Link fast and slow paths together. */
|
||||
stubcc.fixCrossJumps(result, masm.size(), masm.size() + stubcc.size());
|
||||
|
||||
@@ -838,12 +858,7 @@ mjit::Compiler::generateMethod()
|
||||
END_CASE(JSOP_GETARG)
|
||||
|
||||
BEGIN_CASE(JSOP_BINDGNAME)
|
||||
{
|
||||
if (script->compileAndGo && globalObj)
|
||||
frame.push(NonFunObjTag(*globalObj));
|
||||
else
|
||||
jsop_bindname(fullAtomIndex(PC));
|
||||
}
|
||||
jsop_bindgname();
|
||||
END_CASE(JSOP_BINDGNAME)
|
||||
|
||||
BEGIN_CASE(JSOP_SETARG)
|
||||
@@ -1078,9 +1093,7 @@ mjit::Compiler::generateMethod()
|
||||
|
||||
BEGIN_CASE(JSOP_GETGNAME)
|
||||
BEGIN_CASE(JSOP_CALLGNAME)
|
||||
prepareStubCall();
|
||||
stubCall(stubs::GetGlobalName, Uses(0), Defs(1));
|
||||
frame.pushSynced();
|
||||
jsop_getgname(fullAtomIndex(PC));
|
||||
if (op == JSOP_CALLGNAME)
|
||||
frame.push(NullTag());
|
||||
END_CASE(JSOP_GETGNAME)
|
||||
@@ -1774,3 +1787,92 @@ mjit::Compiler::jsop_eleminc(JSOp op, VoidStub stub)
|
||||
frame.pushSynced();
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_getgname_slow(uint32 index)
|
||||
{
|
||||
prepareStubCall();
|
||||
stubCall(stubs::GetGlobalName, Uses(0), Defs(1));
|
||||
frame.pushSynced();
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_bindgname()
|
||||
{
|
||||
if (script->compileAndGo && globalObj) {
|
||||
frame.push(NonFunObjTag(*globalObj));
|
||||
return;
|
||||
}
|
||||
|
||||
/* :TODO: this is slower than it needs to be. */
|
||||
prepareStubCall();
|
||||
stubCall(stubs::BindGlobalName, Uses(0), Defs(1));
|
||||
frame.takeReg(Registers::ReturnReg);
|
||||
frame.pushTypedPayload(JSVAL_MASK32_NONFUNOBJ, Registers::ReturnReg);
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_getgname(uint32 index)
|
||||
{
|
||||
#if ENABLE_MIC
|
||||
jsop_bindgname();
|
||||
|
||||
FrameEntry *fe = frame.peek(-1);
|
||||
JS_ASSERT(fe->isTypeKnown() && fe->getTypeTag() == JSVAL_MASK32_NONFUNOBJ);
|
||||
|
||||
MICGenInfo mic;
|
||||
RegisterID objReg;
|
||||
Jump shapeGuard;
|
||||
|
||||
mic.entry = masm.label();
|
||||
if (fe->isConstant()) {
|
||||
JSObject *obj = &fe->getValue().asObject();
|
||||
frame.pop();
|
||||
JS_ASSERT(obj->isNative());
|
||||
|
||||
JSObjectMap *map = obj->map;
|
||||
objReg = frame.allocReg();
|
||||
|
||||
masm.load32FromImm(&map->shape, objReg);
|
||||
shapeGuard = masm.branchPtrWithPatch(Assembler::NotEqual, objReg, mic.shapeVal);
|
||||
masm.move(ImmPtr(obj), objReg);
|
||||
} else {
|
||||
objReg = frame.ownRegForData(fe);
|
||||
frame.pop();
|
||||
RegisterID reg = frame.allocReg();
|
||||
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, map)), reg);
|
||||
masm.load32(Address(reg, offsetof(JSObjectMap, shape)), reg);
|
||||
shapeGuard = masm.branchPtrWithPatch(Assembler::NotEqual, reg, mic.shapeVal);
|
||||
frame.freeReg(reg);
|
||||
}
|
||||
stubcc.linkExit(shapeGuard);
|
||||
|
||||
stubcc.leave();
|
||||
stubcc.masm.move(Imm32(mics.length()), Registers::ArgReg1);
|
||||
mic.stubEntry = stubcc.masm.label();
|
||||
mic.call = stubcc.call(ic::GetGlobalName);
|
||||
|
||||
/* Garbage value. */
|
||||
uint32 slot = 1 << 24;
|
||||
|
||||
/*
|
||||
* Ensure at least one register is available.
|
||||
* This is necessary so the implicit push below does not change the
|
||||
* expected instruction ordering. :FIXME: this is stupid
|
||||
*/
|
||||
frame.freeReg(frame.allocReg());
|
||||
|
||||
mic.load = masm.label();
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
|
||||
Address address(objReg, slot);
|
||||
frame.freeReg(objReg);
|
||||
frame.push(address);
|
||||
|
||||
stubcc.rejoin(1);
|
||||
|
||||
mics.append(mic);
|
||||
#else
|
||||
jsop_getgname_slow(index);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user