mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-23 02:05:42 +00:00
Bug 1467191 - Unifies some implementations of CacheIR ops that perform a callVM. r=mgaudet
Differential Revision: https://phabricator.services.mozilla.com/D31702 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
f8f9b8becc
commit
46d3b5f507
@ -59,63 +59,48 @@ BaselineCacheIRCompiler::BaselineCacheIRCompiler(
|
||||
CACHE_IR_SHARED_OPS(DEFINE_SHARED_OP)
|
||||
#undef DEFINE_SHARED_OP
|
||||
|
||||
enum class CallCanGC { CanGC, CanNotGC };
|
||||
|
||||
// Instructions that have to perform a callVM require a stub frame. Call its
|
||||
// enter() and leave() methods to enter/leave the stub frame.
|
||||
class MOZ_RAII AutoStubFrame {
|
||||
BaselineCacheIRCompiler& compiler;
|
||||
// AutoStubFrame methods
|
||||
AutoStubFrame::AutoStubFrame(BaselineCacheIRCompiler& compiler)
|
||||
: compiler(compiler)
|
||||
#ifdef DEBUG
|
||||
uint32_t framePushedAtEnterStubFrame_;
|
||||
,
|
||||
framePushedAtEnterStubFrame_(0)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
void AutoStubFrame::enter(MacroAssembler& masm, Register scratch,
|
||||
CallCanGC canGC) {
|
||||
MOZ_ASSERT(compiler.allocator.stackPushed() == 0);
|
||||
|
||||
EmitBaselineEnterStubFrame(masm, scratch);
|
||||
|
||||
#ifdef DEBUG
|
||||
framePushedAtEnterStubFrame_ = masm.framePushed();
|
||||
#endif
|
||||
|
||||
AutoStubFrame(const AutoStubFrame&) = delete;
|
||||
void operator=(const AutoStubFrame&) = delete;
|
||||
|
||||
public:
|
||||
explicit AutoStubFrame(BaselineCacheIRCompiler& compiler)
|
||||
: compiler(compiler)
|
||||
#ifdef DEBUG
|
||||
,
|
||||
framePushedAtEnterStubFrame_(0)
|
||||
#endif
|
||||
{
|
||||
MOZ_ASSERT(!compiler.preparedForVMCall_);
|
||||
compiler.preparedForVMCall_ = true;
|
||||
if (canGC == CallCanGC::CanGC) {
|
||||
compiler.makesGCCalls_ = true;
|
||||
}
|
||||
|
||||
void enter(MacroAssembler& masm, Register scratch,
|
||||
CallCanGC canGC = CallCanGC::CanGC) {
|
||||
MOZ_ASSERT(compiler.allocator.stackPushed() == 0);
|
||||
|
||||
EmitBaselineEnterStubFrame(masm, scratch);
|
||||
}
|
||||
void AutoStubFrame::leave(MacroAssembler& masm, bool calledIntoIon) {
|
||||
MOZ_ASSERT(compiler.preparedForVMCall_);
|
||||
compiler.preparedForVMCall_ = false;
|
||||
|
||||
#ifdef DEBUG
|
||||
framePushedAtEnterStubFrame_ = masm.framePushed();
|
||||
#endif
|
||||
|
||||
MOZ_ASSERT(!compiler.preparedForVMCall_);
|
||||
compiler.preparedForVMCall_ = true;
|
||||
if (canGC == CallCanGC::CanGC) {
|
||||
compiler.makesGCCalls_ = true;
|
||||
}
|
||||
masm.setFramePushed(framePushedAtEnterStubFrame_);
|
||||
if (calledIntoIon) {
|
||||
masm.adjustFrame(sizeof(intptr_t)); // Calls into ion have this extra.
|
||||
}
|
||||
void leave(MacroAssembler& masm, bool calledIntoIon = false) {
|
||||
MOZ_ASSERT(compiler.preparedForVMCall_);
|
||||
compiler.preparedForVMCall_ = false;
|
||||
|
||||
#ifdef DEBUG
|
||||
masm.setFramePushed(framePushedAtEnterStubFrame_);
|
||||
if (calledIntoIon) {
|
||||
masm.adjustFrame(sizeof(intptr_t)); // Calls into ion have this extra.
|
||||
}
|
||||
#endif
|
||||
|
||||
EmitBaselineLeaveStubFrame(masm, calledIntoIon);
|
||||
}
|
||||
EmitBaselineLeaveStubFrame(masm, calledIntoIon);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
~AutoStubFrame() { MOZ_ASSERT(!compiler.preparedForVMCall_); }
|
||||
AutoStubFrame::~AutoStubFrame() { MOZ_ASSERT(!compiler.preparedForVMCall_); }
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
@ -652,81 +637,6 @@ bool BaselineCacheIRCompiler::emitCallProxyGetResult() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaselineCacheIRCompiler::emitCallProxyGetByValueResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
ValueOperand idVal = allocator.useValueRegister(masm, reader.valOperandId());
|
||||
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
|
||||
allocator.discardStack(masm);
|
||||
|
||||
AutoStubFrame stubFrame(*this);
|
||||
stubFrame.enter(masm, scratch);
|
||||
|
||||
masm.Push(idVal);
|
||||
masm.Push(obj);
|
||||
|
||||
using Fn =
|
||||
bool (*)(JSContext*, HandleObject, HandleValue, MutableHandleValue);
|
||||
callVM<Fn, ProxyGetPropertyByValue>(masm);
|
||||
|
||||
stubFrame.leave(masm);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaselineCacheIRCompiler::emitCallProxyHasPropResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
ValueOperand idVal = allocator.useValueRegister(masm, reader.valOperandId());
|
||||
bool hasOwn = reader.readBool();
|
||||
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
|
||||
allocator.discardStack(masm);
|
||||
|
||||
AutoStubFrame stubFrame(*this);
|
||||
stubFrame.enter(masm, scratch);
|
||||
|
||||
masm.Push(idVal);
|
||||
masm.Push(obj);
|
||||
|
||||
using Fn =
|
||||
bool (*)(JSContext*, HandleObject, HandleValue, MutableHandleValue);
|
||||
if (hasOwn) {
|
||||
callVM<Fn, ProxyHasOwn>(masm);
|
||||
} else {
|
||||
callVM<Fn, ProxyHas>(masm);
|
||||
}
|
||||
|
||||
stubFrame.leave(masm);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaselineCacheIRCompiler::emitCallNativeGetElementResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
Register index = allocator.useRegister(masm, reader.int32OperandId());
|
||||
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
|
||||
allocator.discardStack(masm);
|
||||
|
||||
AutoStubFrame stubFrame(*this);
|
||||
stubFrame.enter(masm, scratch);
|
||||
|
||||
masm.Push(index);
|
||||
masm.Push(TypedOrValueRegister(MIRType::Object, AnyRegister(obj)));
|
||||
masm.Push(obj);
|
||||
|
||||
using Fn = bool (*)(JSContext*, HandleNativeObject, HandleValue, int32_t,
|
||||
MutableHandleValue);
|
||||
callVM<Fn, NativeGetElement>(masm);
|
||||
|
||||
stubFrame.leave(masm);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaselineCacheIRCompiler::emitGuardFrameHasNoArgumentsObject() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
FailurePath* failure;
|
||||
@ -1819,28 +1729,6 @@ bool BaselineCacheIRCompiler::emitCallAddOrUpdateSparseElementHelper() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaselineCacheIRCompiler::emitCallGetSparseElementResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
Register id = allocator.useRegister(masm, reader.int32OperandId());
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
|
||||
allocator.discardStack(masm);
|
||||
|
||||
AutoStubFrame stubFrame(*this);
|
||||
stubFrame.enter(masm, scratch);
|
||||
|
||||
masm.Push(id);
|
||||
masm.Push(obj);
|
||||
|
||||
using Fn = bool (*)(JSContext * cx, HandleArrayObject obj, int32_t int_id,
|
||||
MutableHandleValue result);
|
||||
callVM<Fn, GetSparseElementHelper>(masm);
|
||||
|
||||
stubFrame.leave(masm);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaselineCacheIRCompiler::emitMegamorphicSetElement() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "jit/IonIC.h"
|
||||
#include "jit/SharedICHelpers.h"
|
||||
#include "jit/SharedICRegisters.h"
|
||||
#include "proxy/Proxy.h"
|
||||
#include "vm/GeneratorObject.h"
|
||||
|
||||
#include "builtin/Boolean-inl.h"
|
||||
@ -4390,6 +4391,86 @@ bool CacheIRCompiler::emitMetaTwoByte() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CacheIRCompiler::emitCallNativeGetElementResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
AutoCallVM callvm(masm, this, allocator);
|
||||
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
Register index = allocator.useRegister(masm, reader.int32OperandId());
|
||||
|
||||
allocator.discardStack(masm);
|
||||
|
||||
callvm.prepare();
|
||||
|
||||
masm.Push(index);
|
||||
masm.Push(TypedOrValueRegister(MIRType::Object, AnyRegister(obj)));
|
||||
masm.Push(obj);
|
||||
|
||||
using Fn = bool (*)(JSContext*, HandleNativeObject, HandleValue, int32_t,
|
||||
MutableHandleValue);
|
||||
callVM<Fn, NativeGetElement>(masm);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CacheIRCompiler::emitCallProxyHasPropResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
AutoCallVM callvm(masm, this, allocator);
|
||||
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
ValueOperand idVal = allocator.useValueRegister(masm, reader.valOperandId());
|
||||
bool hasOwn = reader.readBool();
|
||||
|
||||
callvm.prepare();
|
||||
|
||||
masm.Push(idVal);
|
||||
masm.Push(obj);
|
||||
|
||||
using Fn =
|
||||
bool (*)(JSContext*, HandleObject, HandleValue, MutableHandleValue);
|
||||
if (hasOwn) {
|
||||
callVM<Fn, ProxyHasOwn>(masm);
|
||||
} else {
|
||||
callVM<Fn, ProxyHas>(masm);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CacheIRCompiler::emitCallProxyGetByValueResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
AutoCallVM callvm(masm, this, allocator);
|
||||
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
ValueOperand idVal = allocator.useValueRegister(masm, reader.valOperandId());
|
||||
|
||||
callvm.prepare();
|
||||
masm.Push(idVal);
|
||||
masm.Push(obj);
|
||||
|
||||
using Fn =
|
||||
bool (*)(JSContext*, HandleObject, HandleValue, MutableHandleValue);
|
||||
callVM<Fn, ProxyGetPropertyByValue>(masm);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CacheIRCompiler::emitCallGetSparseElementResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
|
||||
AutoCallVM callvm(masm, this, allocator);
|
||||
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
Register id = allocator.useRegister(masm, reader.int32OperandId());
|
||||
|
||||
callvm.prepare();
|
||||
masm.Push(id);
|
||||
masm.Push(obj);
|
||||
|
||||
using Fn = bool (*)(JSContext * cx, HandleArrayObject obj, int32_t int_id,
|
||||
MutableHandleValue result);
|
||||
callVM<Fn, GetSparseElementHelper>(masm);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Fn, Fn fn>
|
||||
void CacheIRCompiler::callVM(MacroAssembler& masm) {
|
||||
VMFunctionId id = VMFunctionToId<Fn, fn>::id;
|
||||
@ -4431,12 +4512,55 @@ bool CacheIRCompiler::isBaseline() { return mode_ == Mode::Baseline; }
|
||||
|
||||
bool CacheIRCompiler::isIon() { return mode_ == Mode::Ion; }
|
||||
|
||||
BaselineCacheIRCompiler& CacheIRCompiler::asBaseline() {
|
||||
BaselineCacheIRCompiler* CacheIRCompiler::asBaseline() {
|
||||
MOZ_ASSERT(this->isBaseline());
|
||||
return *static_cast<BaselineCacheIRCompiler*>(this);
|
||||
return static_cast<BaselineCacheIRCompiler*>(this);
|
||||
}
|
||||
|
||||
IonCacheIRCompiler& CacheIRCompiler::asIon() {
|
||||
IonCacheIRCompiler* CacheIRCompiler::asIon() {
|
||||
MOZ_ASSERT(this->isIon());
|
||||
return *static_cast<IonCacheIRCompiler*>(this);
|
||||
return static_cast<IonCacheIRCompiler*>(this);
|
||||
}
|
||||
|
||||
AutoCallVM::AutoCallVM(MacroAssembler& masm, CacheIRCompiler* compiler,
|
||||
CacheRegisterAllocator& allocator)
|
||||
: masm_(masm), compiler_(compiler), allocator_(allocator) {
|
||||
// Ion needs to `prepareVMCall` before it can callVM
|
||||
// Ion also needs to initialize AutoOutputRegister and AutoSaveLiveRegisters
|
||||
// values
|
||||
if (compiler_->mode_ == CacheIRCompiler::Mode::Ion) {
|
||||
// Will need to use a downcast here as well, in order to pass the
|
||||
// stub to AutoSaveLiveRegisters
|
||||
IonCacheIRCompiler* ionCompiler = compiler_->asIon();
|
||||
|
||||
save_.emplace(*ionCompiler);
|
||||
output_.emplace(*ionCompiler);
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(compiler_->mode_ == CacheIRCompiler::Mode::Baseline);
|
||||
|
||||
stubFrame_.emplace(*compiler_->asBaseline());
|
||||
scratch_.emplace(allocator_, masm_);
|
||||
}
|
||||
|
||||
void AutoCallVM::prepare() {
|
||||
allocator_.discardStack(masm_);
|
||||
MOZ_ASSERT(compiler_ != nullptr);
|
||||
if (compiler_->mode_ == CacheIRCompiler::Mode::Ion) {
|
||||
compiler_->asIon()->prepareVMCall(masm_, *save_.ptr());
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(compiler_->mode_ == CacheIRCompiler::Mode::Baseline);
|
||||
stubFrame_->enter(masm_, scratch_.ref());
|
||||
}
|
||||
|
||||
AutoCallVM::~AutoCallVM() {
|
||||
if (compiler_->mode_ == CacheIRCompiler::Mode::Ion) {
|
||||
if (output_.isSome()) {
|
||||
masm_.storeCallResultValue(output_.ref());
|
||||
}
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(compiler_->mode_ == CacheIRCompiler::Mode::Baseline);
|
||||
stubFrame_->leave(masm_);
|
||||
}
|
||||
|
@ -131,6 +131,10 @@ class IonCacheIRCompiler;
|
||||
_(CallNumberToString) \
|
||||
_(BooleanToString) \
|
||||
_(CallIsSuspendedGeneratorResult) \
|
||||
_(CallNativeGetElementResult) \
|
||||
_(CallProxyHasPropResult) \
|
||||
_(CallProxyGetByValueResult) \
|
||||
_(CallGetSparseElementResult) \
|
||||
_(MetaTwoByte) \
|
||||
_(WrapResult)
|
||||
|
||||
@ -708,6 +712,9 @@ class AutoOutputRegister;
|
||||
class MOZ_RAII CacheIRCompiler {
|
||||
protected:
|
||||
friend class AutoOutputRegister;
|
||||
friend class AutoStubFrame;
|
||||
friend class AutoSaveLiveRegisters;
|
||||
friend class AutoCallVM;
|
||||
|
||||
enum class Mode { Baseline, Ion };
|
||||
|
||||
@ -715,8 +722,8 @@ class MOZ_RAII CacheIRCompiler {
|
||||
|
||||
bool isBaseline();
|
||||
bool isIon();
|
||||
BaselineCacheIRCompiler& asBaseline();
|
||||
IonCacheIRCompiler& asIon();
|
||||
BaselineCacheIRCompiler* asBaseline();
|
||||
IonCacheIRCompiler* asIon();
|
||||
|
||||
JSContext* cx_;
|
||||
CacheIRReader reader;
|
||||
@ -946,6 +953,46 @@ class MOZ_RAII AutoOutputRegister {
|
||||
operator TypedOrValueRegister() const { return output_; }
|
||||
};
|
||||
|
||||
enum class CallCanGC { CanGC, CanNotGC };
|
||||
|
||||
// Instructions that have to perform a callVM require a stub frame. Call its
|
||||
// enter() and leave() methods to enter/leave the stub frame.
|
||||
// Hoisted from jit/BaselineCacheIRCompiler.cpp. See there for method
|
||||
// definitions.
|
||||
class MOZ_RAII AutoStubFrame {
|
||||
BaselineCacheIRCompiler& compiler;
|
||||
#ifdef DEBUG
|
||||
uint32_t framePushedAtEnterStubFrame_;
|
||||
#endif
|
||||
|
||||
AutoStubFrame(const AutoStubFrame&) = delete;
|
||||
void operator=(const AutoStubFrame&) = delete;
|
||||
|
||||
public:
|
||||
explicit AutoStubFrame(BaselineCacheIRCompiler& compiler);
|
||||
|
||||
void enter(MacroAssembler& masm, Register scratch,
|
||||
CallCanGC canGC = CallCanGC::CanGC);
|
||||
void leave(MacroAssembler& masm, bool calledIntoIon = false);
|
||||
|
||||
#ifdef DEBUG
|
||||
~AutoStubFrame();
|
||||
#endif
|
||||
};
|
||||
// AutoSaveLiveRegisters must be used when we make a call that can GC. The
|
||||
// constructor ensures all live registers are stored on the stack (where the GC
|
||||
// expects them) and the destructor restores these registers.
|
||||
class MOZ_RAII AutoSaveLiveRegisters {
|
||||
IonCacheIRCompiler& compiler_;
|
||||
|
||||
AutoSaveLiveRegisters(const AutoSaveLiveRegisters&) = delete;
|
||||
void operator=(const AutoSaveLiveRegisters&) = delete;
|
||||
|
||||
public:
|
||||
explicit AutoSaveLiveRegisters(IonCacheIRCompiler& compiler);
|
||||
|
||||
~AutoSaveLiveRegisters();
|
||||
};
|
||||
// Like AutoScratchRegister, but reuse a register of |output| if possible.
|
||||
class MOZ_RAII AutoScratchRegisterMaybeOutput {
|
||||
mozilla::Maybe<AutoScratchRegister> scratch_;
|
||||
@ -969,6 +1016,65 @@ class MOZ_RAII AutoScratchRegisterMaybeOutput {
|
||||
operator Register() const { return scratchReg_; }
|
||||
};
|
||||
|
||||
// AutoCallVM is a wrapper class that unifies methods shared by
|
||||
// IonCacheIRCompiler and BaselineCacheIRCompiler that perform a callVM, but
|
||||
// require stub specific functionality before performing the VM call.
|
||||
//
|
||||
// Expected Usage:
|
||||
//
|
||||
// OPs with implementations that may be unified by this class must:
|
||||
// - Be listed in the CACHEIR_OPS list but not in the CACHE_IR_SHARED_OPS
|
||||
// list
|
||||
// - Differ only in their use of `AutoSaveLiveRegisters`,
|
||||
// `AutoOutputRegister`, and `AutoScratchRegister`. The Ion
|
||||
// implementation will use `AutoSaveLiveRegisters` and
|
||||
// `AutoOutputRegister`, while the Baseline implementation will use
|
||||
// `AutoScratchRegister`.
|
||||
// - Both use the `callVM` method.
|
||||
//
|
||||
// Using AutoCallVM:
|
||||
// - The constructor initializes `AutoOutputRegister` and
|
||||
// `AutoSaveLiveRegisters` variables for CacheIRCompilers with the mode
|
||||
// Ion, and initializes `AutoScratchRegister` and `AutoStubFrame`
|
||||
// variables for CacheIRCompilers with mode Baseline.
|
||||
// - The `prepare()` method calls the IonCacheIRCompiler method
|
||||
// `prepareVMCall` for IonCacheIRCompilers, calls the `enter()` method of
|
||||
// `AutoStubFrame` for BaselineCacheIRCompilers, and calls the
|
||||
// `discardStack` method of the `Register` class for both compiler types.
|
||||
// - The destructor calls the `masm` method `storeCallResultValue` for
|
||||
// IonCacheIRCompilers, and calls the `leave` method of `AutoStubFrame`
|
||||
// for BaselineCacheIRCompilers.
|
||||
//
|
||||
// Expected Usage Example:
|
||||
// See: `CacheIRCompiler::emitCallGetSparseElementResult()`
|
||||
//
|
||||
// Restrictions:
|
||||
// - OPs that do not meet the criteria listed above can not be unified with
|
||||
// AutoCallVM
|
||||
//
|
||||
|
||||
class MOZ_RAII AutoCallVM {
|
||||
MacroAssembler& masm_;
|
||||
CacheIRCompiler* compiler_;
|
||||
CacheRegisterAllocator& allocator_;
|
||||
|
||||
// Baseline specific stuff
|
||||
mozilla::Maybe<AutoStubFrame> stubFrame_;
|
||||
mozilla::Maybe<AutoScratchRegister> scratch_;
|
||||
|
||||
// Ion specific stuff
|
||||
mozilla::Maybe<AutoOutputRegister> output_;
|
||||
mozilla::Maybe<AutoSaveLiveRegisters> save_;
|
||||
|
||||
public:
|
||||
AutoCallVM(MacroAssembler& masm, CacheIRCompiler* compiler,
|
||||
CacheRegisterAllocator& allocator);
|
||||
|
||||
void prepare();
|
||||
|
||||
~AutoCallVM();
|
||||
};
|
||||
|
||||
// See the 'Sharing Baseline stub code' comment in CacheIR.h for a description
|
||||
// of this class.
|
||||
class CacheIRStubInfo {
|
||||
|
@ -33,8 +33,6 @@ using mozilla::Maybe;
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
class AutoSaveLiveRegisters;
|
||||
|
||||
// IonCacheIRCompiler compiles CacheIR to IonIC native code.
|
||||
IonCacheIRCompiler::IonCacheIRCompiler(
|
||||
JSContext* cx, const CacheIRWriter& writer, IonIC* ic, IonScript* ionScript,
|
||||
@ -88,30 +86,22 @@ void IonCacheIRCompiler::pushStubCodePointer() {
|
||||
// AutoSaveLiveRegisters must be used when we make a call that can GC. The
|
||||
// constructor ensures all live registers are stored on the stack (where the GC
|
||||
// expects them) and the destructor restores these registers.
|
||||
class MOZ_RAII AutoSaveLiveRegisters {
|
||||
IonCacheIRCompiler& compiler_;
|
||||
|
||||
AutoSaveLiveRegisters(const AutoSaveLiveRegisters&) = delete;
|
||||
void operator=(const AutoSaveLiveRegisters&) = delete;
|
||||
|
||||
public:
|
||||
explicit AutoSaveLiveRegisters(IonCacheIRCompiler& compiler)
|
||||
: compiler_(compiler) {
|
||||
MOZ_ASSERT(compiler_.liveRegs_.isSome());
|
||||
compiler_.allocator.saveIonLiveRegisters(
|
||||
compiler_.masm, compiler_.liveRegs_.ref(),
|
||||
compiler_.ic_->scratchRegisterForEntryJump(), compiler_.ionScript_);
|
||||
compiler_.savedLiveRegs_ = true;
|
||||
}
|
||||
~AutoSaveLiveRegisters() {
|
||||
MOZ_ASSERT(compiler_.stubJitCodeOffset_.isSome(),
|
||||
"Must have pushed JitCode* pointer");
|
||||
compiler_.allocator.restoreIonLiveRegisters(compiler_.masm,
|
||||
compiler_.liveRegs_.ref());
|
||||
MOZ_ASSERT(compiler_.masm.framePushed() ==
|
||||
compiler_.ionScript_->frameSize());
|
||||
}
|
||||
};
|
||||
AutoSaveLiveRegisters::AutoSaveLiveRegisters(IonCacheIRCompiler& compiler)
|
||||
: compiler_(compiler) {
|
||||
MOZ_ASSERT(compiler_.liveRegs_.isSome());
|
||||
MOZ_ASSERT(compiler_.ic_);
|
||||
compiler_.allocator.saveIonLiveRegisters(
|
||||
compiler_.masm, compiler_.liveRegs_.ref(),
|
||||
compiler_.ic_->scratchRegisterForEntryJump(), compiler_.ionScript_);
|
||||
compiler_.savedLiveRegs_ = true;
|
||||
}
|
||||
AutoSaveLiveRegisters::~AutoSaveLiveRegisters() {
|
||||
MOZ_ASSERT(compiler_.stubJitCodeOffset_.isSome(),
|
||||
"Must have pushed JitCode* pointer");
|
||||
compiler_.allocator.restoreIonLiveRegisters(compiler_.masm,
|
||||
compiler_.liveRegs_.ref());
|
||||
MOZ_ASSERT(compiler_.masm.framePushed() == compiler_.ionScript_->frameSize());
|
||||
}
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
@ -1108,81 +1098,6 @@ bool IonCacheIRCompiler::emitCallProxyGetResult() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IonCacheIRCompiler::emitCallProxyGetByValueResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
AutoSaveLiveRegisters save(*this);
|
||||
AutoOutputRegister output(*this);
|
||||
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
ValueOperand idVal = allocator.useValueRegister(masm, reader.valOperandId());
|
||||
|
||||
allocator.discardStack(masm);
|
||||
|
||||
prepareVMCall(masm, save);
|
||||
|
||||
masm.Push(idVal);
|
||||
masm.Push(obj);
|
||||
|
||||
using Fn =
|
||||
bool (*)(JSContext*, HandleObject, HandleValue, MutableHandleValue);
|
||||
callVM<Fn, ProxyGetPropertyByValue>(masm);
|
||||
|
||||
masm.storeCallResultValue(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IonCacheIRCompiler::emitCallProxyHasPropResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
AutoSaveLiveRegisters save(*this);
|
||||
AutoOutputRegister output(*this);
|
||||
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
ValueOperand idVal = allocator.useValueRegister(masm, reader.valOperandId());
|
||||
bool hasOwn = reader.readBool();
|
||||
|
||||
allocator.discardStack(masm);
|
||||
|
||||
prepareVMCall(masm, save);
|
||||
|
||||
masm.Push(idVal);
|
||||
masm.Push(obj);
|
||||
|
||||
using Fn =
|
||||
bool (*)(JSContext*, HandleObject, HandleValue, MutableHandleValue);
|
||||
if (hasOwn) {
|
||||
callVM<Fn, ProxyHasOwn>(masm);
|
||||
} else {
|
||||
callVM<Fn, ProxyHas>(masm);
|
||||
}
|
||||
|
||||
masm.storeCallResultValue(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IonCacheIRCompiler::emitCallNativeGetElementResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
AutoSaveLiveRegisters save(*this);
|
||||
AutoOutputRegister output(*this);
|
||||
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
Register index = allocator.useRegister(masm, reader.int32OperandId());
|
||||
|
||||
allocator.discardStack(masm);
|
||||
|
||||
prepareVMCall(masm, save);
|
||||
|
||||
masm.Push(index);
|
||||
masm.Push(TypedOrValueRegister(MIRType::Object, AnyRegister(obj)));
|
||||
masm.Push(obj);
|
||||
|
||||
using Fn = bool (*)(JSContext*, HandleNativeObject, HandleValue, int32_t,
|
||||
MutableHandleValue);
|
||||
callVM<Fn, NativeGetElement>(masm);
|
||||
|
||||
masm.storeCallResultValue(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IonCacheIRCompiler::emitGuardFrameHasNoArgumentsObject() {
|
||||
MOZ_CRASH("Baseline-specific op");
|
||||
}
|
||||
@ -2200,27 +2115,6 @@ bool IonCacheIRCompiler::emitCallAddOrUpdateSparseElementHelper() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IonCacheIRCompiler::emitCallGetSparseElementResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
AutoSaveLiveRegisters save(*this);
|
||||
AutoOutputRegister output(*this);
|
||||
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
Register id = allocator.useRegister(masm, reader.int32OperandId());
|
||||
|
||||
allocator.discardStack(masm);
|
||||
prepareVMCall(masm, save);
|
||||
masm.Push(id);
|
||||
masm.Push(obj);
|
||||
|
||||
using Fn = bool (*)(JSContext * cx, HandleArrayObject obj, int32_t int_id,
|
||||
MutableHandleValue result);
|
||||
callVM<Fn, GetSparseElementHelper>(masm);
|
||||
|
||||
masm.storeCallResultValue(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IonCacheIRCompiler::emitMegamorphicSetElement() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
AutoSaveLiveRegisters save(*this);
|
||||
|
@ -7,6 +7,7 @@
|
||||
#ifndef jit_IonCacheIRCompiler_h
|
||||
#define jit_IonCacheIRCompiler_h
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "jit/CacheIR.h"
|
||||
#include "jit/CacheIRCompiler.h"
|
||||
#include "jit/IonIC.h"
|
||||
@ -18,6 +19,7 @@ namespace jit {
|
||||
class MOZ_RAII IonCacheIRCompiler : public CacheIRCompiler {
|
||||
public:
|
||||
friend class AutoSaveLiveRegisters;
|
||||
friend class AutoCallVM;
|
||||
|
||||
IonCacheIRCompiler(JSContext* cx, const CacheIRWriter& writer, IonIC* ic,
|
||||
IonScript* ionScript, IonICStub* stub,
|
||||
@ -41,10 +43,9 @@ class MOZ_RAII IonCacheIRCompiler : public CacheIRCompiler {
|
||||
|
||||
CodeOffsetJump rejoinOffset_;
|
||||
Vector<CodeOffset, 4, SystemAllocPolicy> nextCodeOffsets_;
|
||||
Maybe<LiveRegisterSet> liveRegs_;
|
||||
Maybe<CodeOffset> stubJitCodeOffset_;
|
||||
mozilla::Maybe<LiveRegisterSet> liveRegs_;
|
||||
mozilla::Maybe<CodeOffset> stubJitCodeOffset_;
|
||||
|
||||
private:
|
||||
bool savedLiveRegs_;
|
||||
|
||||
template <typename T>
|
||||
|
Loading…
Reference in New Issue
Block a user