Bug 910782 - SpiderMonkey: Reduce indirection in InterpreterActivation. r=luke

This commit is contained in:
Dan Gohman 2013-10-28 10:32:50 -07:00
parent bb1470c01a
commit 085e28da19
6 changed files with 517 additions and 548 deletions

View File

@ -1440,7 +1440,7 @@ GeneratorState::~GeneratorState()
}
StackFrame *
GeneratorState::pushInterpreterFrame(JSContext *cx, FrameGuard *)
GeneratorState::pushInterpreterFrame(JSContext *cx)
{
/*
* Write barrier is needed since the generator stack can be updated,

File diff suppressed because it is too large Load Diff

View File

@ -203,7 +203,7 @@ class RunState
JSScript *script() const { return script_; }
virtual StackFrame *pushInterpreterFrame(JSContext *cx, FrameGuard *fg) = 0;
virtual StackFrame *pushInterpreterFrame(JSContext *cx) = 0;
virtual void setReturnValue(Value v) = 0;
private:
@ -240,7 +240,7 @@ class ExecuteState : public RunState
JSObject *scopeChain() const { return scopeChain_; }
ExecuteType type() const { return type_; }
virtual StackFrame *pushInterpreterFrame(JSContext *cx, FrameGuard *fg);
virtual StackFrame *pushInterpreterFrame(JSContext *cx);
virtual void setReturnValue(Value v) {
if (result_)
@ -269,7 +269,7 @@ class InvokeState : public RunState
bool constructing() const { return InitialFrameFlagsAreConstructing(initial_); }
CallArgs &args() const { return args_; }
virtual StackFrame *pushInterpreterFrame(JSContext *cx, FrameGuard *fg);
virtual StackFrame *pushInterpreterFrame(JSContext *cx);
virtual void setReturnValue(Value v) {
args_.rval().set(v);
@ -288,7 +288,7 @@ class GeneratorState : public RunState
GeneratorState(JSContext *cx, JSGenerator *gen, JSGeneratorState futureState);
~GeneratorState();
virtual StackFrame *pushInterpreterFrame(JSContext *cx, FrameGuard *fg);
virtual StackFrame *pushInterpreterFrame(JSContext *cx);
virtual void setReturnValue(Value) { }
JSGenerator *gen() const { return gen_; }

View File

@ -840,25 +840,43 @@ Activation::~Activation()
cx_->mainThread().activation_ = prev_;
}
InterpreterActivation::InterpreterActivation(JSContext *cx, StackFrame *entry, FrameRegs &regs,
jsbytecode *const switchMask)
InterpreterActivation::InterpreterActivation(RunState &state, JSContext *cx, StackFrame *entryFrame)
: Activation(cx, Interpreter),
entry_(entry),
regs_(regs),
switchMask_(switchMask)
state_(state),
entryFrame_(entryFrame),
opMask_(0)
#ifdef DEBUG
, oldFrameCount_(cx_->runtime()->interpreterStack().frameCount_)
#endif
{}
{
if (!state.isGenerator()) {
regs_.prepareToRun(*entryFrame, state.script());
JS_ASSERT(regs_.pc == state.script()->code);
} else {
regs_ = state.asGenerator()->gen()->regs;
}
JS_ASSERT_IF(entryFrame_->isEvalFrame(), state_.script()->isActiveEval);
}
InterpreterActivation::~InterpreterActivation()
{
// Pop all inline frames.
while (regs_.fp() != entry_)
while (regs_.fp() != entryFrame_)
popInlineFrame(regs_.fp());
JS_ASSERT(oldFrameCount_ == cx_->runtime()->interpreterStack().frameCount_);
JS_ASSERT_IF(oldFrameCount_ == 0, cx_->runtime()->interpreterStack().allocator_.used() == 0);
if (state_.isGenerator()) {
JSGenerator *gen = state_.asGenerator()->gen();
gen->fp->unsetPushedSPSFrame();
gen->regs = regs_;
return;
}
if (entryFrame_)
cx_->runtime()->interpreterStack().releaseFrame(entryFrame_);
}
inline bool
@ -876,7 +894,7 @@ InterpreterActivation::popInlineFrame(StackFrame *frame)
{
(void)frame; // Quell compiler warning.
JS_ASSERT(regs_.fp() == frame);
JS_ASSERT(regs_.fp() != entry_);
JS_ASSERT(regs_.fp() != entryFrame_);
cx_->runtime()->interpreterStack().popInlineFrame(regs_);
}

View File

@ -471,8 +471,7 @@ FrameRegs::setToEndOfScript()
/*****************************************************************************/
StackFrame *
InterpreterStack::pushInvokeFrame(JSContext *cx, const CallArgs &args, InitialFrameFlags initial,
FrameGuard *fg)
InterpreterStack::pushInvokeFrame(JSContext *cx, const CallArgs &args, InitialFrameFlags initial)
{
LifoAlloc::Mark mark = allocator_.mark();
@ -487,14 +486,13 @@ InterpreterStack::pushInvokeFrame(JSContext *cx, const CallArgs &args, InitialFr
fp->mark_ = mark;
fp->initCallFrame(cx, nullptr, nullptr, nullptr, *fun, script, argv, args.length(), flags);
fg->setPushed(*this, fp);
return fp;
}
StackFrame *
InterpreterStack::pushExecuteFrame(JSContext *cx, HandleScript script, const Value &thisv,
HandleObject scopeChain, ExecuteType type,
AbstractFramePtr evalInFrame, FrameGuard *fg)
AbstractFramePtr evalInFrame)
{
LifoAlloc::Mark mark = allocator_.mark();
@ -508,7 +506,6 @@ InterpreterStack::pushExecuteFrame(JSContext *cx, HandleScript script, const Val
fp->initExecuteFrame(cx, script, evalInFrame, thisv, *scopeChain, type);
fp->initVarsToUndefined();
fg->setPushed(*this, fp);
return fp;
}
@ -1344,7 +1341,7 @@ InterpreterFrameIterator &
InterpreterFrameIterator::operator++()
{
JS_ASSERT(!done());
if (fp_ != activation_->entry_) {
if (fp_ != activation_->entryFrame_) {
pc_ = fp_->prevpc();
sp_ = fp_->prevsp();
fp_ = fp_->prev();

View File

@ -27,7 +27,6 @@ class StackFrame;
class FrameRegs;
class InvokeFrameGuard;
class FrameGuard;
class ExecuteFrameGuard;
class GeneratorFrameGuard;
@ -1024,7 +1023,6 @@ class FrameRegs
class InterpreterStack
{
friend class FrameGuard;
friend class InterpreterActivation;
static const size_t DEFAULT_CHUNK_SIZE = 4 * 1024;
@ -1059,11 +1057,10 @@ class InterpreterStack
// For execution of eval or global code.
StackFrame *pushExecuteFrame(JSContext *cx, HandleScript script, const Value &thisv,
HandleObject scopeChain, ExecuteType type,
AbstractFramePtr evalInFrame, FrameGuard *fg);
AbstractFramePtr evalInFrame);
// Called to invoke a function.
StackFrame *pushInvokeFrame(JSContext *cx, const CallArgs &args, InitialFrameFlags initial,
FrameGuard *fg);
StackFrame *pushInvokeFrame(JSContext *cx, const CallArgs &args, InitialFrameFlags initial);
// The interpreter can push light-weight, "inline" frames without entering a
// new InterpreterActivation or recursively calling Interpret.
@ -1098,31 +1095,6 @@ class InvokeArgs : public JS::CallArgs
}
};
class RunState;
class FrameGuard
{
friend class InterpreterStack;
RunState &state_;
FrameRegs &regs_;
InterpreterStack *stack_;
StackFrame *fp_;
void setPushed(InterpreterStack &stack, StackFrame *fp) {
stack_ = &stack;
fp_ = fp;
}
public:
FrameGuard(RunState &state, FrameRegs &regs);
~FrameGuard();
StackFrame *fp() const {
JS_ASSERT(fp_);
return fp_;
}
};
template <>
struct DefaultHasher<AbstractFramePtr> {
typedef AbstractFramePtr Lookup;
@ -1214,28 +1186,34 @@ class Activation
void operator=(const Activation &other) MOZ_DELETE;
};
// The value to assign to InterpreterActivation's *switchMask_ to enable
// interrupts. This value is greater than the greatest opcode, and is chosen
// such that the bitwise or of this value with any opcode is this value.
// This variable holds a special opcode value which is greater than all normal
// opcodes, and is chosen such that the bitwise or of this value with any
// opcode is this value.
static const jsbytecode EnableInterruptsPseudoOpcode = -1;
static_assert(EnableInterruptsPseudoOpcode >= JSOP_LIMIT,
"EnableInterruptsPseudoOpcode must be greater than any opcode");
static_assert(EnableInterruptsPseudoOpcode == jsbytecode(-1),
"EnableInterruptsPseudoOpcode must be the maximum jsbytecode value");
class InterpreterFrameIterator;
class RunState;
class InterpreterActivation : public Activation
{
friend class js::InterpreterFrameIterator;
StackFrame *const entry_; // Entry frame for this activation.
FrameRegs &regs_;
jsbytecode *const switchMask_; // For debugger interrupts, see js::Interpret.
RunState &state_;
FrameRegs regs_;
StackFrame *entryFrame_;
jsbytecode opMask_; // For debugger interrupts, see js::Interpret.
#ifdef DEBUG
size_t oldFrameCount_;
#endif
public:
inline InterpreterActivation(JSContext *cx, StackFrame *entry, FrameRegs &regs,
jsbytecode *const switchMask);
inline InterpreterActivation(RunState &state, JSContext *cx, StackFrame *entryFrame);
inline ~InterpreterActivation();
inline bool pushInlineFrame(const CallArgs &args, HandleScript script,
@ -1245,9 +1223,15 @@ class InterpreterActivation : public Activation
StackFrame *current() const {
return regs_.fp();
}
FrameRegs &regs() const {
FrameRegs &regs() {
return regs_;
}
StackFrame *entryFrame() const {
return entryFrame_;
}
jsbytecode opMask() const {
return opMask_;
}
// If this js::Interpret frame is running |script|, enable interrupts.
void enableInterruptsIfRunning(JSScript *script) {
@ -1255,7 +1239,10 @@ class InterpreterActivation : public Activation
enableInterruptsUnconditionally();
}
void enableInterruptsUnconditionally() {
*switchMask_ = EnableInterruptsPseudoOpcode;
opMask_ = EnableInterruptsPseudoOpcode;
}
void clearInterruptsMask() {
opMask_ = 0;
}
};
@ -1381,8 +1368,8 @@ class InterpreterFrameIterator
{
if (activation) {
fp_ = activation->current();
pc_ = activation->regs_.pc;
sp_ = activation->regs_.sp;
pc_ = activation->regs().pc;
sp_ = activation->regs().sp;
}
}