Bug 980059 - Make AsmJSActivation a real Activation (r=jandem)

--HG--
extra : rebase_source : 687bafb429d461a3e0856c0c693bcefb24167ec8
This commit is contained in:
Luke Wagner 2014-03-05 17:15:32 -06:00
parent b547063055
commit e5249d484a
5 changed files with 94 additions and 85 deletions

View File

@ -15,8 +15,6 @@
namespace js {
class ExclusiveContext;
class AsmJSModule;
class SPSProfiler;
namespace frontend {
template <typename ParseHandler> struct Parser;
template <typename ParseHandler> struct ParseContext;
@ -36,44 +34,6 @@ extern bool
CompileAsmJS(ExclusiveContext *cx, AsmJSParser &parser, frontend::ParseNode *stmtList,
bool *validated);
// The JSRuntime maintains a stack of AsmJSModule activations. An "activation"
// of module A is an initial call from outside A into a function inside A,
// followed by a sequence of calls inside A, and terminated by a call that
// leaves A. The AsmJSActivation stack serves three purposes:
// - record the correct cx to pass to VM calls from asm.js;
// - record enough information to pop all the frames of an activation if an
// exception is thrown;
// - record the information necessary for asm.js signal handlers to safely
// recover from (expected) out-of-bounds access, the operation callback,
// stack overflow, division by zero, etc.
class AsmJSActivation
{
JSContext *cx_;
AsmJSModule &module_;
AsmJSActivation *prev_;
void *errorRejoinSP_;
SPSProfiler *profiler_;
void *resumePC_;
public:
AsmJSActivation(JSContext *cx, AsmJSModule &module);
~AsmJSActivation();
JSContext *cx() { return cx_; }
AsmJSModule &module() const { return module_; }
AsmJSActivation *prev() const { return prev_; }
// Read by JIT code:
static unsigned offsetOfContext() { return offsetof(AsmJSActivation, cx_); }
static unsigned offsetOfResumePC() { return offsetof(AsmJSActivation, resumePC_); }
// Initialized by JIT code:
static unsigned offsetOfErrorRejoinSP() { return offsetof(AsmJSActivation, errorRejoinSP_); }
// Set from SIGSEGV handler:
void setResumePC(void *pc) { resumePC_ = pc; }
};
// The assumed page size; dynamically checked in CompileAsmJS.
const size_t AsmJSPageSize = 4096;

View File

@ -318,41 +318,6 @@ DynamicallyLinkModule(JSContext *cx, CallArgs args, AsmJSModule &module)
return true;
}
AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module)
: cx_(cx),
module_(module),
errorRejoinSP_(nullptr),
profiler_(nullptr),
resumePC_(nullptr)
{
if (cx->runtime()->spsProfiler.enabled()) {
// Use a profiler string that matches jsMatch regex in
// browser/devtools/profiler/cleopatra/js/parserWorker.js.
// (For now use a single static string to avoid further slowing down
// calls into asm.js.)
profiler_ = &cx->runtime()->spsProfiler;
profiler_->enterNative("asm.js code :0", this);
}
prev_ = cx_->runtime()->mainThread.asmJSActivationStack_;
JSRuntime::AutoLockForOperationCallback lock(cx_->runtime());
cx_->runtime()->mainThread.asmJSActivationStack_ = this;
(void) errorRejoinSP_; // squelch GCC warning
}
AsmJSActivation::~AsmJSActivation()
{
if (profiler_)
profiler_->exitNative();
JS_ASSERT(cx_->runtime()->mainThread.asmJSActivationStack_ == this);
JSRuntime::AutoLockForOperationCallback lock(cx_->runtime());
cx_->runtime()->mainThread.asmJSActivationStack_ = prev_;
}
static const unsigned ASM_MODULE_SLOT = 0;
static const unsigned ASM_EXPORT_INDEX_SLOT = 1;
@ -417,15 +382,12 @@ CallAsmJS(JSContext *cx, unsigned argc, Value *vp)
}
{
// Each call into an asm.js module requires an AsmJSActivation record
// pushed on a stack maintained by the runtime. This record is used for
// to handle a variety of exceptional things that can happen in asm.js
// code.
// Push an AsmJSActivation to describe the asm.js frames we're about to
// push when running this module. Additionally, push a JitActivation so
// that the optimized asm.js-to-Ion FFI call path (which we want to be
// very fast) can avoid doing so. The JitActivation is marked as
// inactive so stack iteration will skip over it.
AsmJSActivation activation(cx, module);
// Eagerly push an IonContext+JitActivation so that the optimized
// asm.js-to-Ion FFI call path (which we want to be very fast) can
// avoid doing so.
JitActivation jitActivation(cx, /* firstFrameIsConstructing = */ false, /* active */ false);
// Call the per-exported-function trampoline created by GenerateEntry.

View File

@ -626,7 +626,7 @@ ArrayBufferObject::neuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buff
JS_ASSERT(!buffer.isSharedArrayBuffer());
#ifdef JS_ION
AsmJSActivation *act = cx->mainThread().asmJSActivationStackFromOwnerThread();
for (; act; act = act->prev()) {
for (; act; act = act->prevAsmJS()) {
if (act->module().maybeHeapBufferObject() == &buffer)
break;
}

View File

@ -593,6 +593,12 @@ ScriptFrameIter::settleOnActivation()
++data_.activations_;
continue;
}
// AsmJS activations will soon contain iterable frames, but not atm.
if (activation->isAsmJS()) {
++data_.activations_;
continue;
}
#endif
JS_ASSERT(activation->isInterpreter());
@ -1379,6 +1385,41 @@ jit::JitActivation::setActive(JSContext *cx, bool active)
}
}
AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module)
: Activation(cx, AsmJS),
module_(module),
errorRejoinSP_(nullptr),
profiler_(nullptr),
resumePC_(nullptr)
{
if (cx->runtime()->spsProfiler.enabled()) {
// Use a profiler string that matches jsMatch regex in
// browser/devtools/profiler/cleopatra/js/parserWorker.js.
// (For now use a single static string to avoid further slowing down
// calls into asm.js.)
profiler_ = &cx->runtime()->spsProfiler;
profiler_->enterNative("asm.js code :0", this);
}
prevAsmJS_ = cx_->runtime()->mainThread.asmJSActivationStack_;
JSRuntime::AutoLockForOperationCallback lock(cx_->runtime());
cx_->runtime()->mainThread.asmJSActivationStack_ = this;
(void) errorRejoinSP_; // squelch GCC warning
}
AsmJSActivation::~AsmJSActivation()
{
if (profiler_)
profiler_->exitNative();
JS_ASSERT(cx_->runtime()->mainThread.asmJSActivationStack_ == this);
JSRuntime::AutoLockForOperationCallback lock(cx_->runtime());
cx_->runtime()->mainThread.asmJSActivationStack_ = prevAsmJS_;
}
InterpreterFrameIterator &
InterpreterFrameIterator::operator++()
{

View File

@ -24,9 +24,11 @@ struct JSGenerator;
namespace js {
class ArgumentsObject;
class AsmJSModule;
class InterpreterRegs;
class ScopeObject;
class ScriptFrameIter;
class SPSProfiler;
class StackFrame;
class StaticBlockObject;
@ -1106,6 +1108,7 @@ struct DefaultHasher<AbstractFramePtr> {
class InterpreterActivation;
class ForkJoinActivation;
class AsmJSActivation;
namespace jit {
class JitActivation;
@ -1131,7 +1134,7 @@ class Activation
// data structures instead.
size_t hideScriptedCallerCount_;
enum Kind { Interpreter, Jit, ForkJoin };
enum Kind { Interpreter, Jit, ForkJoin, AsmJS };
Kind kind_;
inline Activation(JSContext *cx, Kind kind_);
@ -1157,6 +1160,9 @@ class Activation
bool isForkJoin() const {
return kind_ == ForkJoin;
}
bool isAsmJS() const {
return kind_ == AsmJS;
}
InterpreterActivation *asInterpreter() const {
JS_ASSERT(isInterpreter());
@ -1170,6 +1176,10 @@ class Activation
JS_ASSERT(isForkJoin());
return (ForkJoinActivation *)this;
}
AsmJSActivation *asAsmJS() const {
JS_ASSERT(isAsmJS());
return (AsmJSActivation *)this;
}
void saveFrameChain() {
savedFrameChain_++;
@ -1405,6 +1415,42 @@ class InterpreterFrameIterator
}
};
// An AsmJSActivation is part of two activation linked lists:
// - the normal Activation list used by FrameIter
// - a list of only AsmJSActivations that is signal-safe since it is accessed
// from the profiler at arbitrary points
//
// An eventual goal is to remove AsmJSActivation and to run asm.js code in a
// JitActivation interleaved with Ion/Baseline jit code. This would allow
// efficient calls back and forth but requires that we can walk the stack for
// all kinds of jit code.
class AsmJSActivation : public Activation
{
AsmJSModule &module_;
AsmJSActivation *prevAsmJS_;
void *errorRejoinSP_;
SPSProfiler *profiler_;
void *resumePC_;
public:
AsmJSActivation(JSContext *cx, AsmJSModule &module);
~AsmJSActivation();
JSContext *cx() { return cx_; }
AsmJSModule &module() const { return module_; }
AsmJSActivation *prevAsmJS() const { return prevAsmJS_; }
// Read by JIT code:
static unsigned offsetOfContext() { return offsetof(AsmJSActivation, cx_); }
static unsigned offsetOfResumePC() { return offsetof(AsmJSActivation, resumePC_); }
// Initialized by JIT code:
static unsigned offsetOfErrorRejoinSP() { return offsetof(AsmJSActivation, errorRejoinSP_); }
// Set from SIGSEGV handler:
void setResumePC(void *pc) { resumePC_ = pc; }
};
class ScriptFrameIter
{
public: