mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-28 12:45:27 +00:00
Bug 620141 - eval cache should key based on calling script and pc, not calling function. r=jorendorff.
This commit is contained in:
parent
e4f225bcbe
commit
b418bd08f8
@ -50,15 +50,16 @@ IsEvalCacheCandidate(RawScript script)
|
||||
EvalCacheHashPolicy::hash(const EvalCacheLookup &l)
|
||||
{
|
||||
return AddToHash(HashString(l.str->chars(), l.str->length()),
|
||||
l.caller.get(),
|
||||
l.staticLevel,
|
||||
l.callerScript.get(),
|
||||
l.version,
|
||||
l.compartment);
|
||||
l.pc);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
EvalCacheHashPolicy::match(RawScript script, const EvalCacheLookup &l)
|
||||
EvalCacheHashPolicy::match(const EvalCacheEntry &cacheEntry, const EvalCacheLookup &l)
|
||||
{
|
||||
JSScript *script = cacheEntry.script;
|
||||
|
||||
JS_ASSERT(IsEvalCacheCandidate(script));
|
||||
|
||||
// Get the source string passed for safekeeping in the atom map
|
||||
@ -66,10 +67,9 @@ EvalCacheHashPolicy::match(RawScript script, const EvalCacheLookup &l)
|
||||
JSAtom *keyStr = script->atoms[0];
|
||||
|
||||
return EqualStrings(keyStr, l.str) &&
|
||||
script->getCallerFunction() == l.caller &&
|
||||
script->staticLevel == l.staticLevel &&
|
||||
cacheEntry.callerScript == l.callerScript &&
|
||||
script->getVersion() == l.version &&
|
||||
script->compartment() == l.compartment;
|
||||
cacheEntry.pc == l.pc;
|
||||
}
|
||||
|
||||
// There are two things we want to do with each script executed in EvalKernel:
|
||||
@ -100,23 +100,23 @@ class EvalScriptGuard
|
||||
CallDestroyScriptHook(cx_->runtime->defaultFreeOp(), script_);
|
||||
script_->isActiveEval = false;
|
||||
script_->isCachedEval = true;
|
||||
EvalCacheEntry cacheEntry = {script_, lookup_.callerScript, lookup_.pc};
|
||||
lookup_.str = lookupStr_;
|
||||
if (lookup_.str && IsEvalCacheCandidate(script_))
|
||||
cx_->runtime->evalCache.relookupOrAdd(p_, lookup_, script_);
|
||||
cx_->runtime->evalCache.relookupOrAdd(p_, lookup_, cacheEntry);
|
||||
}
|
||||
}
|
||||
|
||||
void lookupInEvalCache(JSLinearString *str, JSFunction *caller, unsigned staticLevel)
|
||||
void lookupInEvalCache(JSLinearString *str, JSScript *callerScript, jsbytecode *pc)
|
||||
{
|
||||
lookupStr_ = str;
|
||||
lookup_.str = str;
|
||||
lookup_.caller = caller;
|
||||
lookup_.staticLevel = staticLevel;
|
||||
lookup_.callerScript = callerScript;
|
||||
lookup_.version = cx_->findVersion();
|
||||
lookup_.compartment = cx_->compartment;
|
||||
lookup_.pc = pc;
|
||||
p_ = cx_->runtime->evalCache.lookupForAdd(lookup_);
|
||||
if (p_) {
|
||||
script_ = *p_;
|
||||
script_ = p_->script;
|
||||
cx_->runtime->evalCache.remove(p_);
|
||||
CallNewScriptHook(cx_, script_, NullPtr());
|
||||
script_->isCachedEval = false;
|
||||
@ -205,9 +205,10 @@ enum EvalType { DIRECT_EVAL = EXECUTE_DIRECT_EVAL, INDIRECT_EVAL = EXECUTE_INDIR
|
||||
// On success, store the completion value in call.rval and return true.
|
||||
static bool
|
||||
EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFramePtr caller,
|
||||
HandleObject scopeobj)
|
||||
HandleObject scopeobj, jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT((evalType == INDIRECT_EVAL) == !caller);
|
||||
JS_ASSERT((evalType == INDIRECT_EVAL) == !pc);
|
||||
JS_ASSERT_IF(evalType == INDIRECT_EVAL, scopeobj->isGlobal());
|
||||
AssertInnerizedScopeChain(cx, *scopeobj);
|
||||
|
||||
@ -273,7 +274,7 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFrame
|
||||
EvalScriptGuard esg(cx);
|
||||
|
||||
if (evalType == DIRECT_EVAL && caller.isNonEvalFunctionFrame())
|
||||
esg.lookupInEvalCache(stableStr, caller.fun(), staticLevel);
|
||||
esg.lookupInEvalCache(stableStr, callerScript, pc);
|
||||
|
||||
if (!esg.foundScript()) {
|
||||
unsigned lineno;
|
||||
@ -306,7 +307,7 @@ bool
|
||||
js::DirectEvalFromIon(JSContext *cx,
|
||||
HandleObject scopeobj, HandleScript callerScript,
|
||||
HandleValue thisValue, HandleString str,
|
||||
MutableHandleValue vp)
|
||||
jsbytecode *pc, MutableHandleValue vp)
|
||||
{
|
||||
AssertInnerizedScopeChain(cx, *scopeobj);
|
||||
|
||||
@ -336,7 +337,7 @@ js::DirectEvalFromIon(JSContext *cx,
|
||||
// Ion will not perform cross compartment direct eval calls.
|
||||
JSPrincipals *principals = cx->compartment->principals;
|
||||
|
||||
esg.lookupInEvalCache(stableStr, callerScript->function(), staticLevel);
|
||||
esg.lookupInEvalCache(stableStr, callerScript, pc);
|
||||
|
||||
if (!esg.foundScript()) {
|
||||
unsigned lineno;
|
||||
@ -399,23 +400,26 @@ js::IndirectEval(JSContext *cx, unsigned argc, Value *vp)
|
||||
return false;
|
||||
|
||||
Rooted<GlobalObject*> global(cx, &args.callee().global());
|
||||
return EvalKernel(cx, args, INDIRECT_EVAL, NullFramePtr(), global);
|
||||
return EvalKernel(cx, args, INDIRECT_EVAL, NullFramePtr(), global, NULL);
|
||||
}
|
||||
|
||||
bool
|
||||
js::DirectEval(JSContext *cx, const CallArgs &args)
|
||||
{
|
||||
// Direct eval can assume it was called from an interpreted frame.
|
||||
StackFrame *caller = cx->fp();
|
||||
JS_ASSERT(IsBuiltinEvalForScope(caller->scopeChain(), args.calleev()));
|
||||
JS_ASSERT(JSOp(*cx->regs().pc) == JSOP_EVAL);
|
||||
JS_ASSERT_IF(caller->isFunctionFrame(),
|
||||
caller->compartment() == caller->callee().compartment());
|
||||
// Direct eval can assume it was called from an interpreted or baseline frame.
|
||||
ScriptFrameIter iter(cx);
|
||||
AbstractFramePtr caller = iter.abstractFramePtr();
|
||||
|
||||
JS_ASSERT(IsBuiltinEvalForScope(caller.scopeChain(), args.calleev()));
|
||||
JS_ASSERT(JSOp(*iter.pc()) == JSOP_EVAL);
|
||||
JS_ASSERT_IF(caller.isFunctionFrame(),
|
||||
caller.compartment() == caller.callee().compartment());
|
||||
|
||||
if (!WarnOnTooManyArgs(cx, args))
|
||||
return false;
|
||||
|
||||
return EvalKernel(cx, args, DIRECT_EVAL, caller, caller->scopeChain());
|
||||
RootedObject scopeChain(cx, caller.scopeChain());
|
||||
return EvalKernel(cx, args, DIRECT_EVAL, caller, scopeChain, iter.pc());
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -31,7 +31,7 @@ extern bool
|
||||
DirectEvalFromIon(JSContext *cx,
|
||||
HandleObject scopeObj, HandleScript callerScript,
|
||||
HandleValue thisValue, HandleString str,
|
||||
MutableHandleValue vp);
|
||||
jsbytecode * pc, MutableHandleValue vp);
|
||||
|
||||
// True iff 'v' is the built-in eval function for the global object that
|
||||
// corresponds to 'scopeChain'.
|
||||
|
@ -1711,7 +1711,7 @@ CodeGenerator::visitFilterArguments(LFilterArguments *lir)
|
||||
}
|
||||
|
||||
typedef bool (*DirectEvalFn)(JSContext *, HandleObject, HandleScript, HandleValue, HandleString,
|
||||
MutableHandleValue);
|
||||
jsbytecode *, MutableHandleValue);
|
||||
static const VMFunction DirectEvalInfo = FunctionInfo<DirectEvalFn>(DirectEvalFromIon);
|
||||
|
||||
bool
|
||||
@ -1720,6 +1720,7 @@ CodeGenerator::visitCallDirectEval(LCallDirectEval *lir)
|
||||
Register scopeChain = ToRegister(lir->getScopeChain());
|
||||
Register string = ToRegister(lir->getString());
|
||||
|
||||
pushArg(ImmWord(lir->mir()->pc()));
|
||||
pushArg(string);
|
||||
pushArg(ToValue(lir, LCallDirectEval::ThisValueInput));
|
||||
pushArg(ImmGCPtr(gen->info().script()));
|
||||
|
@ -3301,7 +3301,7 @@ IonBuilder::getInlineableGetPropertyCache(CallInfo &callInfo)
|
||||
}
|
||||
|
||||
MPolyInlineDispatch *
|
||||
IonBuilder::makePolyInlineDispatch(JSContext *cx, CallInfo &callInfo,
|
||||
IonBuilder::makePolyInlineDispatch(JSContext *cx, CallInfo &callInfo,
|
||||
MGetPropertyCache *getPropCache, MBasicBlock *bottom,
|
||||
Vector<MDefinition *, 8, IonAllocPolicy> &retvalDefns)
|
||||
{
|
||||
@ -3927,7 +3927,7 @@ IonBuilder::jsop_funcall(uint32_t argc)
|
||||
current->push(pass);
|
||||
} else {
|
||||
// |this| becomes implicit in the call.
|
||||
argc -= 1;
|
||||
argc -= 1;
|
||||
}
|
||||
|
||||
// Call without inlining.
|
||||
@ -4360,7 +4360,7 @@ AdjustTypeBarrierForDOMCall(const JSJitInfo* jitinfo, types::StackTypeSet *types
|
||||
|
||||
if (jitinfo->returnType != types->getKnownTypeTag())
|
||||
return barrier;
|
||||
|
||||
|
||||
// No need for a barrier if we're already expecting the type we'll produce.
|
||||
return NULL;
|
||||
}
|
||||
@ -4478,7 +4478,7 @@ IonBuilder::jsop_eval(uint32_t argc)
|
||||
MInstruction *filterArguments = MFilterArguments::New(string);
|
||||
current->add(filterArguments);
|
||||
|
||||
MInstruction *ins = MCallDirectEval::New(scopeChain, string, thisValue);
|
||||
MInstruction *ins = MCallDirectEval::New(scopeChain, string, thisValue, pc);
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
|
||||
|
@ -1495,7 +1495,9 @@ class MCallDirectEval
|
||||
public MixPolicy<ObjectPolicy<0>, MixPolicy<StringPolicy<1>, BoxPolicy<2> > >
|
||||
{
|
||||
protected:
|
||||
MCallDirectEval(MDefinition *scopeChain, MDefinition *string, MDefinition *thisValue)
|
||||
MCallDirectEval(MDefinition *scopeChain, MDefinition *string, MDefinition *thisValue,
|
||||
jsbytecode *pc)
|
||||
: pc_(pc)
|
||||
{
|
||||
setOperand(0, scopeChain);
|
||||
setOperand(1, string);
|
||||
@ -1507,8 +1509,9 @@ class MCallDirectEval
|
||||
INSTRUCTION_HEADER(CallDirectEval)
|
||||
|
||||
static MCallDirectEval *
|
||||
New(MDefinition *scopeChain, MDefinition *string, MDefinition *thisValue) {
|
||||
return new MCallDirectEval(scopeChain, string, thisValue);
|
||||
New(MDefinition *scopeChain, MDefinition *string, MDefinition *thisValue,
|
||||
jsbytecode *pc) {
|
||||
return new MCallDirectEval(scopeChain, string, thisValue, pc);
|
||||
}
|
||||
|
||||
MDefinition *getScopeChain() const {
|
||||
@ -1521,9 +1524,16 @@ class MCallDirectEval
|
||||
return getOperand(2);
|
||||
}
|
||||
|
||||
jsbytecode *pc() const {
|
||||
return pc_;
|
||||
}
|
||||
|
||||
TypePolicy *typePolicy() {
|
||||
return this;
|
||||
}
|
||||
|
||||
private:
|
||||
jsbytecode *pc_;
|
||||
};
|
||||
|
||||
class MBinaryInstruction : public MAryInstruction<2>
|
||||
@ -1852,7 +1862,7 @@ class MUnbox : public MUnaryInstruction
|
||||
JS_ASSERT(ins->type() == MIRType_Value);
|
||||
JS_ASSERT(type == MIRType_Boolean ||
|
||||
type == MIRType_Int32 ||
|
||||
type == MIRType_Double ||
|
||||
type == MIRType_Double ||
|
||||
type == MIRType_String ||
|
||||
type == MIRType_Object);
|
||||
|
||||
|
@ -274,6 +274,7 @@ template <> struct OutParamToDataType<MutableHandleValue> { static const DataTyp
|
||||
#define FOR_EACH_ARGS_3(Macro, Sep, Last) FOR_EACH_ARGS_2(Macro, Sep, Sep) Macro(3) Last(3)
|
||||
#define FOR_EACH_ARGS_4(Macro, Sep, Last) FOR_EACH_ARGS_3(Macro, Sep, Sep) Macro(4) Last(4)
|
||||
#define FOR_EACH_ARGS_5(Macro, Sep, Last) FOR_EACH_ARGS_4(Macro, Sep, Sep) Macro(5) Last(5)
|
||||
#define FOR_EACH_ARGS_6(Macro, Sep, Last) FOR_EACH_ARGS_5(Macro, Sep, Sep) Macro(6) Last(6)
|
||||
|
||||
#define COMPUTE_INDEX(NbArg) NbArg
|
||||
#define COMPUTE_OUTPARAM_RESULT(NbArg) OutParamToDataType<A ## NbArg>::result
|
||||
@ -370,6 +371,12 @@ template <class R, class A1, class A2, class A3, class A4, class A5>
|
||||
FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_5)
|
||||
};
|
||||
|
||||
template <class R, class A1, class A2, class A3, class A4, class A5, class A6>
|
||||
struct FunctionInfo<R (*)(JSContext *, A1, A2, A3, A4, A5, A6)> : public VMFunction {
|
||||
typedef R (*pf)(JSContext *, A1, A2, A3, A4, A5, A6);
|
||||
FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_6)
|
||||
};
|
||||
|
||||
#undef FUNCTION_INFO_STRUCT_BODY
|
||||
|
||||
#undef FOR_EACH_ARGS_5
|
||||
|
@ -226,14 +226,20 @@ class SourceDataCache
|
||||
void purge();
|
||||
};
|
||||
|
||||
struct EvalCacheEntry
|
||||
{
|
||||
JSScript *script;
|
||||
JSScript *callerScript;
|
||||
jsbytecode *pc;
|
||||
};
|
||||
|
||||
struct EvalCacheLookup
|
||||
{
|
||||
EvalCacheLookup(JSContext *cx) : str(cx), caller(cx) {}
|
||||
EvalCacheLookup(JSContext *cx) : str(cx), callerScript(cx) {}
|
||||
RootedLinearString str;
|
||||
RootedFunction caller;
|
||||
unsigned staticLevel;
|
||||
RootedScript callerScript;
|
||||
JSVersion version;
|
||||
JSCompartment *compartment;
|
||||
jsbytecode *pc;
|
||||
};
|
||||
|
||||
struct EvalCacheHashPolicy
|
||||
@ -241,10 +247,10 @@ struct EvalCacheHashPolicy
|
||||
typedef EvalCacheLookup Lookup;
|
||||
|
||||
static HashNumber hash(const Lookup &l);
|
||||
static bool match(RawScript script, const EvalCacheLookup &l);
|
||||
static bool match(const EvalCacheEntry &entry, const EvalCacheLookup &l);
|
||||
};
|
||||
|
||||
typedef HashSet<RawScript, EvalCacheHashPolicy, SystemAllocPolicy> EvalCache;
|
||||
typedef HashSet<EvalCacheEntry, EvalCacheHashPolicy, SystemAllocPolicy> EvalCache;
|
||||
|
||||
class NativeIterCache
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user