Bug 1541404 part 19 - Add BaselineInterpreter class and use it in various places. r=tcampbell

I considered adding BaselineInterpreter.{h,cpp} files but there are shared
helper functions so this might get awkward. Maybe once the rest of the code is
in we can experiment with changes in this area.

Differential Revision: https://phabricator.services.mozilla.com/D29158

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jan de Mooij 2019-05-03 07:42:31 +00:00
Родитель 9dda0571c2
Коммит c4167e27e8
10 изменённых файлов: 197 добавлений и 26 удалений

Просмотреть файл

@ -5660,7 +5660,9 @@ bool BaselineCodeGen<Handler>::emit_JSOP_FINALYIELDRVAL() {
template <>
void BaselineCompilerCodeGen::emitJumpToInterpretOpLabel() {
MOZ_CRASH("NYI: Interpreter emitJumpToInterpretOpLabel");
TrampolinePtr code =
cx->runtime()->jitRuntime()->baselineInterpreter().interpretOpAddr();
masm.jump(code);
}
template <>

Просмотреть файл

@ -151,7 +151,9 @@ JitExecStatus jit::EnterBaselineAtBranch(JSContext* cx, InterpreterFrame* fp,
data.jitcode += MacroAssembler::ToggledCallSize(data.jitcode);
}
} else {
MOZ_CRASH("NYI: Interpreter executeOp code");
const BaselineInterpreter& interp =
cx->runtime()->jitRuntime()->baselineInterpreter();
data.jitcode = interp.interpretOpAddr().value;
}
// Note: keep this in sync with SetEnterJitData.
@ -1080,6 +1082,23 @@ void BaselineScript::toggleTraceLoggerEngine(bool enable) {
}
#endif
static void ToggleProfilerInstrumentation(JitCode* code,
uint32_t profilerEnterToggleOffset,
uint32_t profilerExitToggleOffset,
bool enable) {
CodeLocationLabel enterToggleLocation(code,
CodeOffset(profilerEnterToggleOffset));
CodeLocationLabel exitToggleLocation(code,
CodeOffset(profilerExitToggleOffset));
if (enable) {
Assembler::ToggleToCmp(enterToggleLocation);
Assembler::ToggleToCmp(exitToggleLocation);
} else {
Assembler::ToggleToJmp(enterToggleLocation);
Assembler::ToggleToJmp(exitToggleLocation);
}
}
void BaselineScript::toggleProfilerInstrumentation(bool enable) {
if (enable == isProfilerInstrumentationOn()) {
return;
@ -1088,22 +1107,49 @@ void BaselineScript::toggleProfilerInstrumentation(bool enable) {
JitSpew(JitSpew_BaselineIC, " toggling profiling %s for BaselineScript %p",
enable ? "on" : "off", this);
// Toggle the jump
CodeLocationLabel enterToggleLocation(method_,
CodeOffset(profilerEnterToggleOffset_));
CodeLocationLabel exitToggleLocation(method_,
CodeOffset(profilerExitToggleOffset_));
ToggleProfilerInstrumentation(method_, profilerEnterToggleOffset_,
profilerExitToggleOffset_, enable);
if (enable) {
Assembler::ToggleToCmp(enterToggleLocation);
Assembler::ToggleToCmp(exitToggleLocation);
flags_ |= uint32_t(PROFILER_INSTRUMENTATION_ON);
} else {
Assembler::ToggleToJmp(enterToggleLocation);
Assembler::ToggleToJmp(exitToggleLocation);
flags_ &= ~uint32_t(PROFILER_INSTRUMENTATION_ON);
}
}
void BaselineInterpreter::toggleProfilerInstrumentation(bool enable) {
if (!JitOptions.baselineInterpreter) {
return;
}
AutoWritableJitCode awjc(code_);
ToggleProfilerInstrumentation(code_, profilerEnterToggleOffset_,
profilerExitToggleOffset_, enable);
}
void BaselineInterpreter::toggleDebuggerInstrumentation(bool enable) {
if (!JitOptions.baselineInterpreter) {
return;
}
AutoWritableJitCode awjc(code_);
// Toggle prologue IsDebuggeeCheck code.
CodeLocationLabel debuggeeCheckLocation(code_,
CodeOffset(debuggeeCheckOffset_));
if (enable) {
Assembler::ToggleToCmp(debuggeeCheckLocation);
} else {
Assembler::ToggleToJmp(debuggeeCheckLocation);
}
// Toggle DebugTrapHandler calls.
for (uint32_t offset : debugTrapOffsets_) {
CodeLocationLabel trapLocation(code_, CodeOffset(offset));
Assembler::ToggleCall(trapLocation, enable);
}
}
void ICScript::purgeOptimizedStubs(JSScript* script) {
MOZ_ASSERT(script->icScript() == this);
@ -1277,6 +1323,8 @@ void jit::ToggleBaselineProfiling(JSRuntime* runtime, bool enable) {
return;
}
jrt->baselineInterpreter().toggleProfilerInstrumentation(enable);
for (ZonesIter zone(runtime, SkipAtoms); !zone.done(); zone.next()) {
for (auto script = zone->cellIter<JSScript>(); !script.done();
script.next()) {
@ -1365,3 +1413,26 @@ void jit::MarkActiveTypeScripts(Zone* zone) {
}
}
}
void BaselineInterpreter::init(JitCode* code, uint32_t interpretOpOffset,
uint32_t profilerEnterToggleOffset,
uint32_t profilerExitToggleOffset,
uint32_t debuggeeCheckOffset,
DebugTrapOffsets&& debugTrapOffsets) {
code_ = code;
interpretOpOffset_ = interpretOpOffset;
profilerEnterToggleOffset_ = profilerEnterToggleOffset;
profilerExitToggleOffset_ = profilerExitToggleOffset;
debuggeeCheckOffset_ = debuggeeCheckOffset;
debugTrapOffsets_ = std::move(debugTrapOffsets);
}
bool jit::GenerateBaselineInterpreter(JSContext* cx,
BaselineInterpreter& interpreter) {
// Temporary JitOptions check to prevent crashes for now.
if (JitOptions.baselineInterpreter) {
MOZ_CRASH("NYI: GenerateBaselineInterpreter");
}
return true;
}

Просмотреть файл

@ -651,6 +651,51 @@ void JitSpewBaselineICStats(JSScript* script, const char* dumpReason);
static const unsigned BASELINE_MAX_ARGS_LENGTH = 20000;
// Class storing the generated Baseline Interpreter code for the runtime.
class BaselineInterpreter {
// The interpreter code.
JitCode* code_ = nullptr;
// Offset of the code to start interpreting a bytecode op.
uint32_t interpretOpOffset_ = 0;
// The offsets for the toggledJump instructions for profiler instrumentation.
uint32_t profilerEnterToggleOffset_ = 0;
uint32_t profilerExitToggleOffset_ = 0;
// The offset for the toggledJump instruction for the debugger's
// IsDebuggeeCheck code in the prologue.
uint32_t debuggeeCheckOffset_ = 0;
// Offsets of toggled calls to the DebugTrapHandler trampoline (for
// breakpoints and stepping).
using DebugTrapOffsets = js::Vector<uint32_t, 0, SystemAllocPolicy>;
DebugTrapOffsets debugTrapOffsets_;
public:
BaselineInterpreter() = default;
BaselineInterpreter(const BaselineInterpreter&) = delete;
void operator=(const BaselineInterpreter&) = delete;
void init(JitCode* code, uint32_t interpretOpOffset,
uint32_t profilerEnterToggleOffset,
uint32_t profilerExitToggleOffset, uint32_t debuggeeCheckOffset,
DebugTrapOffsets&& debugTrapOffsets);
uint8_t* codeRaw() const { return code_->raw(); }
TrampolinePtr interpretOpAddr() const {
return TrampolinePtr(codeRaw() + interpretOpOffset_);
}
void toggleProfilerInstrumentation(bool enable);
void toggleDebuggerInstrumentation(bool enable);
};
MOZ_MUST_USE bool GenerateBaselineInterpreter(JSContext* cx,
BaselineInterpreter& interpreter);
} // namespace jit
} // namespace js

Просмотреть файл

@ -166,6 +166,7 @@ JitRuntime::JitRuntime()
doubleToInt32ValueStubOffset_(0),
debugTrapHandler_(nullptr),
baselineDebugModeOSRHandler_(nullptr),
baselineInterpreter_(),
trampolineCode_(nullptr),
jitcodeGlobalTable_(nullptr),
#ifdef DEBUG
@ -213,6 +214,10 @@ bool JitRuntime::initialize(JSContext* cx) {
return false;
}
if (!GenerateBaselineInterpreter(cx, baselineInterpreter_)) {
return false;
}
return true;
}

Просмотреть файл

@ -20,8 +20,11 @@ using namespace js::jit;
static EnterJitStatus JS_HAZ_JSNATIVE_CALLER EnterJit(JSContext* cx,
RunState& state,
uint8_t* code) {
MOZ_ASSERT(state.script()->hasBaselineScript());
// We don't want to call the interpreter stub here (because
// C++ -> interpreterStub -> C++ is slower than staying in C++).
MOZ_ASSERT(code);
MOZ_ASSERT(code != cx->runtime()->jitRuntime()->interpreterStub().value);
MOZ_ASSERT(IsBaselineEnabled(cx));
if (!CheckRecursionLimit(cx)) {
@ -55,7 +58,11 @@ static EnterJitStatus JS_HAZ_JSNATIVE_CALLER EnterJit(JSContext* cx,
if (numActualArgs > BASELINE_MAX_ARGS_LENGTH) {
return EnterJitStatus::NotEntered;
}
code = script->baselineScript()->method()->raw();
if (script->hasBaselineScript()) {
code = script->baselineScript()->method()->raw();
} else {
code = cx->runtime()->jitRuntime()->baselineInterpreter().codeRaw();
}
}
constructing = state.asInvoke()->constructing();
@ -131,11 +138,16 @@ EnterJitStatus js::jit::MaybeEnterJit(JSContext* cx, RunState& state) {
uint8_t* code = script->jitCodeRaw();
do {
// Make sure we have a BaselineScript: we don't want to call the
// interpreter stub here. Note that Baseline code contains warm-up
// checks in the prologue to Ion-compile if needed.
if (script->hasBaselineScript()) {
break;
// Make sure we can enter Baseline Interpreter or JIT code. Note that
// the prologue has warm-up checks to tier up if needed.
if (JitOptions.baselineInterpreter) {
if (script->types()) {
break;
}
} else {
if (script->hasBaselineScript()) {
break;
}
}
script->incWarmUpCounter();

Просмотреть файл

@ -376,21 +376,35 @@ static bool ProcessTryNotesBaseline(JSContext* cx, const JSJitFrameIter& frame,
script->resetWarmUpCounter();
// Resume at the start of the catch block.
PCMappingSlotInfo slotInfo;
rfe->kind = ResumeFromException::RESUME_CATCH;
rfe->target =
script->baselineScript()->nativeCodeForPC(script, *pc, &slotInfo);
MOZ_ASSERT(slotInfo.isStackSynced());
if (frame.baselineFrame()->runningInInterpreter()) {
const BaselineInterpreter& interp =
cx->runtime()->jitRuntime()->baselineInterpreter();
frame.baselineFrame()->setInterpreterPC(*pc);
rfe->target = interp.interpretOpAddr().value;
} else {
PCMappingSlotInfo slotInfo;
rfe->target =
script->baselineScript()->nativeCodeForPC(script, *pc, &slotInfo);
MOZ_ASSERT(slotInfo.isStackSynced());
}
return true;
}
case JSTRY_FINALLY: {
PCMappingSlotInfo slotInfo;
SettleOnTryNote(cx, tn, frame, ei, rfe, pc);
rfe->kind = ResumeFromException::RESUME_FINALLY;
rfe->target =
script->baselineScript()->nativeCodeForPC(script, *pc, &slotInfo);
MOZ_ASSERT(slotInfo.isStackSynced());
if (frame.baselineFrame()->runningInInterpreter()) {
const BaselineInterpreter& interp =
cx->runtime()->jitRuntime()->baselineInterpreter();
frame.baselineFrame()->setInterpreterPC(*pc);
rfe->target = interp.interpretOpAddr().value;
} else {
PCMappingSlotInfo slotInfo;
rfe->target =
script->baselineScript()->nativeCodeForPC(script, *pc, &slotInfo);
MOZ_ASSERT(slotInfo.isStackSynced());
}
// Drop the exception instead of leaking cross compartment data.
if (!cx->getPendingException(
MutableHandleValue::fromMarkedLocation(&rfe->exception))) {

Просмотреть файл

@ -16,6 +16,7 @@
#include "builtin/TypedObject.h"
#include "jit/BaselineICList.h"
#include "jit/BaselineJIT.h"
#include "jit/CompileInfo.h"
#include "jit/ICStubSpace.h"
#include "jit/IonCode.h"
@ -195,6 +196,9 @@ class JitRuntime {
WriteOnceData<JitCode*> baselineDebugModeOSRHandler_;
WriteOnceData<void*> baselineDebugModeOSRHandlerNoFrameRegPopAddr_;
// BaselineInterpreter state.
BaselineInterpreter baselineInterpreter_;
// Code for trampolines and VMFunction wrappers.
WriteOnceData<JitCode*> trampolineCode_;
@ -326,6 +330,8 @@ class JitRuntime {
JitCode* getBaselineDebugModeOSRHandler(JSContext* cx);
void* getBaselineDebugModeOSRHandlerAddress(JSContext* cx, bool popFrameReg);
BaselineInterpreter& baselineInterpreter() { return baselineInterpreter_; }
TrampolinePtr getGenericBailoutHandler() const {
return trampolineCode(bailoutHandlerOffset_);
}

Просмотреть файл

@ -5431,6 +5431,9 @@ void JSScript::updateJitCodeRaw(JSRuntime* rt) {
} else if (hasBaselineScript()) {
jitCodeRaw_ = baseline->method()->raw();
jitCodeSkipArgCheck_ = jitCodeRaw_;
} else if (types() && js::jit::JitOptions.baselineInterpreter) {
jitCodeRaw_ = rt->jitRuntime()->baselineInterpreter().codeRaw();
jitCodeSkipArgCheck_ = jitCodeRaw_;
} else {
jitCodeRaw_ = rt->jitRuntime()->interpreterStub().value;
jitCodeSkipArgCheck_ = jitCodeRaw_;

Просмотреть файл

@ -770,6 +770,10 @@ void JSRuntime::clearUsedByHelperThread(Zone* zone) {
}
void JSRuntime::incrementNumDebuggeeRealms() {
if (numDebuggeeRealms_ == 0) {
jitRuntime()->baselineInterpreter().toggleDebuggerInstrumentation(true);
}
numDebuggeeRealms_++;
MOZ_ASSERT(numDebuggeeRealms_ <= numRealms);
}
@ -777,6 +781,10 @@ void JSRuntime::incrementNumDebuggeeRealms() {
void JSRuntime::decrementNumDebuggeeRealms() {
MOZ_ASSERT(numDebuggeeRealms_ > 0);
numDebuggeeRealms_--;
if (numDebuggeeRealms_ == 0) {
jitRuntime()->baselineInterpreter().toggleDebuggerInstrumentation(false);
}
}
bool js::CurrentThreadCanAccessRuntime(const JSRuntime* rt) {

Просмотреть файл

@ -3555,6 +3555,10 @@ bool JSScript::makeTypes(JSContext* cx) {
types_ = new (typeScript) TypeScript(this, std::move(icScript), numTypeSets);
// We have a TypeScript so we can set the script's jitCodeRaw_ pointer to the
// Baseline Interpreter code.
updateJitCodeRaw(cx->runtime());
#ifdef DEBUG
StackTypeSet* typeArray = typeScript->typeArrayDontCheckGeneration();
for (unsigned i = 0; i < numBytecodeTypeSets(); i++) {
@ -4585,6 +4589,7 @@ void JSScript::maybeReleaseTypes() {
types_->destroy(zone());
types_ = nullptr;
updateJitCodeRaw(runtimeFromMainThread());
}
void TypeScript::destroy(Zone* zone) {