зеркало из https://github.com/mozilla/gecko-dev.git
Backed out efc4b8a23cd7:12e8fc56b5eb (bug 876064) for asm.js test failures
This commit is contained in:
Родитель
1fddfac45e
Коммит
f327c82296
|
@ -22,7 +22,11 @@ using namespace js;
|
|||
using namespace js::ion;
|
||||
|
||||
BaselineCompiler::BaselineCompiler(JSContext *cx, HandleScript script)
|
||||
: BaselineCompilerSpecific(cx, script)
|
||||
: BaselineCompilerSpecific(cx, script),
|
||||
return_(new HeapLabel())
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
, postBarrierSlot_(new HeapLabel())
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -257,7 +261,7 @@ BaselineCompiler::emitPrologue()
|
|||
bool
|
||||
BaselineCompiler::emitEpilogue()
|
||||
{
|
||||
masm.bind(&return_);
|
||||
masm.bind(return_);
|
||||
|
||||
// Pop SPS frame if necessary
|
||||
emitSPSPop();
|
||||
|
@ -279,7 +283,7 @@ BaselineCompiler::emitEpilogue()
|
|||
bool
|
||||
BaselineCompiler::emitOutOfLinePostBarrierSlot()
|
||||
{
|
||||
masm.bind(&postBarrierSlot_);
|
||||
masm.bind(postBarrierSlot_);
|
||||
|
||||
Register objReg = R2.scratchReg();
|
||||
GeneralRegisterSet regs(GeneralRegisterSet::All());
|
||||
|
@ -342,7 +346,7 @@ BaselineCompiler::emitDebugPrologue()
|
|||
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, &done);
|
||||
{
|
||||
masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
|
||||
masm.jump(&return_);
|
||||
masm.jump(return_);
|
||||
}
|
||||
masm.bind(&done);
|
||||
return true;
|
||||
|
@ -1820,7 +1824,7 @@ BaselineCompiler::emit_JSOP_SETALIASEDVAR()
|
|||
masm.branchPtr(Assembler::Below, objReg, ImmWord(nursery.heapEnd()), &skipBarrier);
|
||||
|
||||
masm.bind(&isTenured);
|
||||
masm.call(&postBarrierSlot_);
|
||||
masm.call(postBarrierSlot_);
|
||||
|
||||
masm.bind(&skipBarrier);
|
||||
#endif
|
||||
|
@ -2485,7 +2489,7 @@ BaselineCompiler::emit_JSOP_DEBUGGER()
|
|||
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, &done);
|
||||
{
|
||||
masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
|
||||
masm.jump(&return_);
|
||||
masm.jump(return_);
|
||||
}
|
||||
masm.bind(&done);
|
||||
return true;
|
||||
|
@ -2518,7 +2522,7 @@ BaselineCompiler::emitReturn()
|
|||
if (JSOp(*pc) != JSOP_STOP) {
|
||||
// JSOP_STOP is immediately followed by the return label, so we don't
|
||||
// need a jump.
|
||||
masm.jump(&return_);
|
||||
masm.jump(return_);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -184,9 +184,9 @@ namespace ion {
|
|||
class BaselineCompiler : public BaselineCompilerSpecific
|
||||
{
|
||||
FixedList<Label> labels_;
|
||||
NonAssertingLabel return_;
|
||||
HeapLabel * return_;
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
NonAssertingLabel postBarrierSlot_;
|
||||
HeapLabel * postBarrierSlot_;
|
||||
#endif
|
||||
|
||||
// Native code offset right before the scope chain is initialized.
|
||||
|
|
|
@ -887,7 +887,7 @@ CodeGenerator::visitReturn(LReturn *lir)
|
|||
#endif
|
||||
// Don't emit a jump to the return label if this is the last block.
|
||||
if (current->mir() != *gen->graph().poBegin())
|
||||
masm.jump(&returnLabel_);
|
||||
masm.jump(returnLabel_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6944,7 +6944,7 @@ CodeGenerator::visitOutOfLineParallelAbort(OutOfLineParallelAbort *ool)
|
|||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ParallelAbort));
|
||||
|
||||
masm.moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
|
||||
masm.jump(&returnLabel_);
|
||||
masm.jump(returnLabel_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -7004,7 +7004,7 @@ CodeGenerator::visitOutOfLinePropagateParallelAbort(OutOfLinePropagateParallelAb
|
|||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, PropagateParallelAbort));
|
||||
|
||||
masm.moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
|
||||
masm.jump(&returnLabel_);
|
||||
masm.jump(returnLabel_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -7097,7 +7097,7 @@ CodeGenerator::visitAsmJSReturn(LAsmJSReturn *lir)
|
|||
masm.ma_vxfer(d0, r0, r1);
|
||||
#endif
|
||||
if (current->mir() != *gen->graph().poBegin())
|
||||
masm.jump(&returnLabel_);
|
||||
masm.jump(returnLabel_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -7106,7 +7106,7 @@ CodeGenerator::visitAsmJSVoidReturn(LAsmJSVoidReturn *lir)
|
|||
{
|
||||
// Don't emit a jump to the return label if this is the last block.
|
||||
if (current->mir() != *gen->graph().poBegin())
|
||||
masm.jump(&returnLabel_);
|
||||
masm.jump(returnLabel_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,8 @@ using namespace js::ion;
|
|||
|
||||
// shared
|
||||
CodeGeneratorARM::CodeGeneratorARM(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm)
|
||||
: CodeGeneratorShared(gen, graph, masm)
|
||||
: CodeGeneratorShared(gen, graph, masm),
|
||||
deoptLabel_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -45,13 +46,17 @@ CodeGeneratorARM::generatePrologue()
|
|||
masm.checkStackAlignment();
|
||||
}
|
||||
|
||||
// Allocate returnLabel_ on the heap, so we don't run its destructor and
|
||||
// assert-not-bound in debug mode on compilation failure.
|
||||
returnLabel_ = new HeapLabel();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGeneratorARM::generateEpilogue()
|
||||
{
|
||||
masm.bind(&returnLabel_);
|
||||
masm.bind(returnLabel_);
|
||||
if (gen->compilingAsmJS()) {
|
||||
// Pop the stack we allocated at the start of the function.
|
||||
masm.freeStack(frameDepth_);
|
||||
|
@ -147,9 +152,9 @@ CodeGeneratorARM::generateOutOfLineCode()
|
|||
if (!CodeGeneratorShared::generateOutOfLineCode())
|
||||
return false;
|
||||
|
||||
if (deoptLabel_.used()) {
|
||||
if (deoptLabel_) {
|
||||
// All non-table-based bailouts will go here.
|
||||
masm.bind(&deoptLabel_);
|
||||
masm.bind(deoptLabel_);
|
||||
|
||||
// Push the frame size, so the handler can recover the IonScript.
|
||||
masm.ma_mov(Imm32(frameSize()), lr);
|
||||
|
@ -259,10 +264,12 @@ CodeGeneratorARM::bailout(LSnapshot *snapshot)
|
|||
bool
|
||||
CodeGeneratorARM::visitOutOfLineBailout(OutOfLineBailout *ool)
|
||||
{
|
||||
if (!deoptLabel_)
|
||||
deoptLabel_ = new HeapLabel();
|
||||
masm.ma_mov(Imm32(ool->snapshot()->snapshotOffset()), ScratchRegister);
|
||||
masm.ma_push(ScratchRegister);
|
||||
masm.ma_push(ScratchRegister);
|
||||
masm.ma_b(&deoptLabel_);
|
||||
masm.ma_b(deoptLabel_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,8 +24,8 @@ class CodeGeneratorARM : public CodeGeneratorShared
|
|||
|
||||
protected:
|
||||
// Label for the common return path.
|
||||
NonAssertingLabel returnLabel_;
|
||||
NonAssertingLabel deoptLabel_;
|
||||
HeapLabel *returnLabel_;
|
||||
HeapLabel *deoptLabel_;
|
||||
// ugh. this is not going to be pretty to move over.
|
||||
// stack slotted variables are not useful on arm.
|
||||
// it looks like this will need to return one of two types.
|
||||
|
|
|
@ -278,19 +278,11 @@ class Label : public LabelBase
|
|||
}
|
||||
};
|
||||
|
||||
// Label's destructor asserts that if it has been used it has also been bound.
|
||||
// In the case long-lived labels, however, failed compilation (e.g. OOM) will
|
||||
// trigger this failure innocuously. This Label silences the assertion.
|
||||
class NonAssertingLabel : public Label
|
||||
// Wrapper around Label, on the heap, to avoid a bogus assert with OOM.
|
||||
struct HeapLabel
|
||||
: public TempObject,
|
||||
public Label
|
||||
{
|
||||
public:
|
||||
~NonAssertingLabel()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (used())
|
||||
bind(0);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
class RepatchLabel
|
||||
|
|
|
@ -22,7 +22,8 @@ namespace js {
|
|||
namespace ion {
|
||||
|
||||
CodeGeneratorX86Shared::CodeGeneratorX86Shared(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm)
|
||||
: CodeGeneratorShared(gen, graph, masm)
|
||||
: CodeGeneratorShared(gen, graph, masm),
|
||||
deoptLabel_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -38,13 +39,17 @@ CodeGeneratorX86Shared::generatePrologue()
|
|||
// Note that this automatically sets MacroAssembler::framePushed().
|
||||
masm.reserveStack(frameSize());
|
||||
|
||||
// Allocate returnLabel_ on the heap, so we don't run its destructor and
|
||||
// assert-not-bound in debug mode on compilation failure.
|
||||
returnLabel_ = new HeapLabel();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGeneratorX86Shared::generateEpilogue()
|
||||
{
|
||||
masm.bind(&returnLabel_);
|
||||
masm.bind(returnLabel_);
|
||||
|
||||
// Pop the stack we allocated at the start of the function.
|
||||
masm.freeStack(frameSize());
|
||||
|
@ -223,9 +228,9 @@ CodeGeneratorX86Shared::generateOutOfLineCode()
|
|||
if (!CodeGeneratorShared::generateOutOfLineCode())
|
||||
return false;
|
||||
|
||||
if (deoptLabel_.used()) {
|
||||
if (deoptLabel_) {
|
||||
// All non-table-based bailouts will go here.
|
||||
masm.bind(&deoptLabel_);
|
||||
masm.bind(deoptLabel_);
|
||||
|
||||
// Push the frame size, so the handler can recover the IonScript.
|
||||
masm.push(Imm32(frameSize()));
|
||||
|
@ -344,8 +349,11 @@ CodeGeneratorX86Shared::bailout(LSnapshot *snapshot)
|
|||
bool
|
||||
CodeGeneratorX86Shared::visitOutOfLineBailout(OutOfLineBailout *ool)
|
||||
{
|
||||
if (!deoptLabel_)
|
||||
deoptLabel_ = new HeapLabel();
|
||||
|
||||
masm.push(Imm32(ool->snapshot()->snapshotOffset()));
|
||||
masm.jmp(&deoptLabel_);
|
||||
masm.jmp(deoptLabel_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
|
|||
|
||||
protected:
|
||||
// Label for the common return path.
|
||||
NonAssertingLabel returnLabel_;
|
||||
NonAssertingLabel deoptLabel_;
|
||||
HeapLabel *returnLabel_;
|
||||
HeapLabel *deoptLabel_;
|
||||
|
||||
inline Operand ToOperand(const LAllocation &a) {
|
||||
if (a.isGeneralReg())
|
||||
|
|
|
@ -386,22 +386,27 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
bind(&done);
|
||||
}
|
||||
|
||||
bool maybeInlineDouble(double d, const FloatRegister &dest) {
|
||||
uint64_t u = mozilla::BitwiseCast<uint64_t>(d);
|
||||
bool maybeInlineDouble(uint64_t u, const FloatRegister &dest) {
|
||||
// This implements parts of "13.4 Generating constants" of
|
||||
// "2. Optimizing subroutines in assembly language" by Agner Fog,
|
||||
// generalized to handle any case that can use a pcmpeqw and
|
||||
// up to two shifts.
|
||||
|
||||
// Loading zero with xor is specially optimized in hardware.
|
||||
if (u == 0) {
|
||||
xorpd(dest, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
// It is also possible to load several common constants using pcmpeqw
|
||||
// to get all ones and then psllq and psrlq to get zeros at the ends,
|
||||
// as described in "13.4 Generating constants" of
|
||||
// "2. Optimizing subroutines in assembly language" by Agner Fog, and as
|
||||
// previously implemented here. However, with x86 and x64 both using
|
||||
// constant pool loads for double constants, this is probably only
|
||||
// worthwhile in cases where a load is likely to be delayed.
|
||||
int tz = js_bitscan_ctz64(u);
|
||||
int lz = js_bitscan_clz64(u);
|
||||
if (u == (~uint64_t(0) << (lz + tz) >> lz)) {
|
||||
pcmpeqw(dest, dest);
|
||||
if (tz != 0)
|
||||
psllq(Imm32(lz + tz), dest);
|
||||
if (lz != 0)
|
||||
psrlq(Imm32(lz), dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -8,65 +8,12 @@
|
|||
#include "ion/BaselineFrame.h"
|
||||
#include "ion/MoveEmitter.h"
|
||||
#include "ion/IonFrames.h"
|
||||
#include "mozilla/Casting.h"
|
||||
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::ion;
|
||||
|
||||
void
|
||||
MacroAssemblerX64::loadConstantDouble(double d, const FloatRegister &dest)
|
||||
{
|
||||
if (maybeInlineDouble(d, dest))
|
||||
return;
|
||||
|
||||
if (!doubleMap_.initialized()) {
|
||||
enoughMemory_ &= doubleMap_.init();
|
||||
if (!enoughMemory_)
|
||||
return;
|
||||
}
|
||||
size_t doubleIndex;
|
||||
DoubleMap::AddPtr p = doubleMap_.lookupForAdd(d);
|
||||
if (p) {
|
||||
doubleIndex = p->value;
|
||||
} else {
|
||||
doubleIndex = doubles_.length();
|
||||
enoughMemory_ &= doubles_.append(Double(d));
|
||||
enoughMemory_ &= doubleMap_.add(p, d, doubleIndex);
|
||||
if (!enoughMemory_)
|
||||
return;
|
||||
}
|
||||
Double &dbl = doubles_[doubleIndex];
|
||||
JS_ASSERT(!dbl.uses.bound());
|
||||
|
||||
// The constants will be stored in a pool appended to the text (see
|
||||
// finish()), so they will always be a fixed distance from the
|
||||
// instructions which reference them. This allows the instructions to use
|
||||
// PC-relative addressing. Use "jump" label support code, because we need
|
||||
// the same PC-relative address patching that jumps use.
|
||||
JmpSrc j = masm.movsd_ripr(dest.code());
|
||||
JmpSrc prev = JmpSrc(dbl.uses.use(j.offset()));
|
||||
masm.setNextJump(j, prev);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::finish()
|
||||
{
|
||||
JS_STATIC_ASSERT(CodeAlignment >= sizeof(double));
|
||||
|
||||
if (!doubles_.empty())
|
||||
masm.align(sizeof(double));
|
||||
|
||||
for (size_t i = 0; i < doubles_.length(); i++) {
|
||||
Double &dbl = doubles_[i];
|
||||
bind(&dbl.uses);
|
||||
masm.doubleConstant(dbl.value);
|
||||
}
|
||||
|
||||
MacroAssemblerX86Shared::finish();
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::setupABICall(uint32_t args)
|
||||
{
|
||||
|
|
|
@ -45,16 +45,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
bool dynamicAlignment_;
|
||||
bool enoughMemory_;
|
||||
|
||||
struct Double {
|
||||
double value;
|
||||
NonAssertingLabel uses;
|
||||
Double(double value) : value(value) {}
|
||||
};
|
||||
Vector<Double, 0, IonAllocPolicy> doubles_;
|
||||
|
||||
typedef HashMap<double, size_t, DefaultHasher<double>, IonAllocPolicy> DoubleMap;
|
||||
DoubleMap doubleMap_;
|
||||
|
||||
void setupABICall(uint32_t arg);
|
||||
|
||||
protected:
|
||||
|
@ -81,10 +71,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
{
|
||||
}
|
||||
|
||||
// The buffer is about to be linked, make sure any constant pools or excess
|
||||
// bookkeeping has been flushed to the instruction stream.
|
||||
void finish();
|
||||
|
||||
bool oom() const {
|
||||
return MacroAssemblerX86Shared::oom() || !enoughMemory_;
|
||||
}
|
||||
|
@ -952,7 +938,17 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
cvtsi2sd(operand.valueReg(), dest);
|
||||
}
|
||||
|
||||
void loadConstantDouble(double d, const FloatRegister &dest);
|
||||
void loadConstantDouble(double d, const FloatRegister &dest) {
|
||||
union DoublePun {
|
||||
uint64_t u;
|
||||
double d;
|
||||
} pun;
|
||||
pun.d = d;
|
||||
if (!maybeInlineDouble(pun.u, dest)) {
|
||||
mov(ImmWord(pun.u), ScratchReg);
|
||||
movqsd(ScratchReg, dest);
|
||||
}
|
||||
}
|
||||
void loadStaticDouble(const double *dp, const FloatRegister &dest) {
|
||||
loadConstantDouble(*dp, dest);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include "ion/BaselineFrame.h"
|
||||
#include "ion/MoveEmitter.h"
|
||||
#include "ion/IonFrames.h"
|
||||
#include "mozilla/Casting.h"
|
||||
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
|
@ -18,7 +17,12 @@ using namespace js::ion;
|
|||
void
|
||||
MacroAssemblerX86::loadConstantDouble(double d, const FloatRegister &dest)
|
||||
{
|
||||
if (maybeInlineDouble(d, dest))
|
||||
union DoublePun {
|
||||
uint64_t u;
|
||||
double d;
|
||||
} dpun;
|
||||
dpun.d = d;
|
||||
if (maybeInlineDouble(dpun.u, dest))
|
||||
return;
|
||||
|
||||
if (!doubleMap_.initialized()) {
|
||||
|
@ -38,21 +42,10 @@ MacroAssemblerX86::loadConstantDouble(double d, const FloatRegister &dest)
|
|||
return;
|
||||
}
|
||||
Double &dbl = doubles_[doubleIndex];
|
||||
JS_ASSERT(!dbl.uses.bound());
|
||||
|
||||
masm.movsd_mr(reinterpret_cast<const void *>(dbl.uses.prev()), dest.code());
|
||||
masm.movsd_mr(reinterpret_cast<void *>(dbl.uses.prev()), dest.code());
|
||||
dbl.uses.setPrev(masm.size());
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::loadStaticDouble(const double *dp, const FloatRegister &dest) {
|
||||
if (maybeInlineDouble(*dp, dest))
|
||||
return;
|
||||
|
||||
// x86 can just load from any old immediate address.
|
||||
movsd(dp, dest);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::finish()
|
||||
{
|
||||
|
|
|
@ -793,7 +793,9 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
|||
}
|
||||
|
||||
void loadConstantDouble(double d, const FloatRegister &dest);
|
||||
void loadStaticDouble(const double *dp, const FloatRegister &dest);
|
||||
void loadStaticDouble(const double *dp, const FloatRegister &dest) {
|
||||
movsd(dp, dest);
|
||||
}
|
||||
|
||||
void branchTruncateDouble(const FloatRegister &src, const Register &dest, Label *fail) {
|
||||
const uint32_t IndefiniteIntegerValue = 0x80000000;
|
||||
|
|
Загрузка…
Ссылка в новой задаче