mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 980059 - Make AsmJSActivation a real Activation (r=jandem)
--HG-- extra : rebase_source : 687bafb429d461a3e0856c0c693bcefb24167ec8
This commit is contained in:
parent
b547063055
commit
e5249d484a
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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++()
|
||||
{
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user