Bug 1290421: Throw ahead of time on statically known out-of-bounds; r=sunfish

MozReview-Commit-ID: Bj5MKn9w3vw

--HG--
extra : rebase_source : e70fab6c482de3ceffaac876f3e6beee69f778a6
This commit is contained in:
Benjamin Bouvier 2016-07-29 11:45:15 +02:00
parent c8aa291733
commit 6abe4661c1
14 changed files with 61 additions and 82 deletions

View File

@ -698,6 +698,19 @@ class FunctionCompiler
}
private:
// False means we're sure to be out-of-bounds after this bounds check.
bool maybeAddBoundsCheck(MDefinition* base, const MWasmMemoryAccess& access)
{
if (access.offset() > uint32_t(INT32_MAX)) {
curBlock_->end(MWasmTrap::New(alloc(), Trap::OutOfBounds));
curBlock_ = nullptr;
return false;
}
if (!mg().usesSignal.forOOB)
curBlock_->add(MWasmBoundsCheck::New(alloc(), base, access));
return true;
}
MDefinition* loadHeapPrivate(MDefinition* base, const MWasmMemoryAccess& access,
bool isInt64 = false)
{
@ -708,8 +721,8 @@ class FunctionCompiler
if (mg().isAsmJS()) {
load = MAsmJSLoadHeap::New(alloc(), base, access);
} else {
if (!mg().usesSignal.forOOB)
curBlock_->add(MWasmBoundsCheck::New(alloc(), base, access));
if (!maybeAddBoundsCheck(base, access))
return nullptr;
load = MWasmLoad::New(alloc(), base, access, isInt64);
}
@ -726,8 +739,8 @@ class FunctionCompiler
if (mg().isAsmJS()) {
store = MAsmJSStoreHeap::New(alloc(), base, access, v);
} else {
if (!mg().usesSignal.forOOB)
curBlock_->add(MWasmBoundsCheck::New(alloc(), base, access));
if (!maybeAddBoundsCheck(base, access))
return;
store = MWasmStore::New(alloc(), base, access, v);
}
@ -1109,7 +1122,7 @@ class FunctionCompiler
if (inDeadCode())
return;
auto* ins = MAsmThrowUnreachable::New(alloc());
auto* ins = MWasmTrap::New(alloc(), wasm::Trap::Unreachable);
curBlock_->end(ins);
curBlock_ = nullptr;
}

View File

@ -11520,10 +11520,10 @@ CodeGenerator::visitAsmJSInterruptCheck(LAsmJSInterruptCheck* lir)
}
void
CodeGenerator::visitAsmThrowUnreachable(LAsmThrowUnreachable* lir)
CodeGenerator::visitWasmTrap(LWasmTrap* lir)
{
MOZ_ASSERT(gen->compilingAsmJS());
masm.jump(wasm::JumpTarget::Unreachable);
masm.jump(wasm::JumpTarget(lir->mir()->trap()));
}
typedef bool (*RecompileFn)(JSContext*);

View File

@ -415,7 +415,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
void visitInterruptCheck(LInterruptCheck* lir);
void visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit* ins);
void visitAsmJSInterruptCheck(LAsmJSInterruptCheck* lir);
void visitAsmThrowUnreachable(LAsmThrowUnreachable* lir);
void visitWasmTrap(LWasmTrap* lir);
void visitRecompileCheck(LRecompileCheck* ins);
void visitRotate(LRotate* ins);

View File

@ -2530,9 +2530,9 @@ LIRGenerator::visitAsmJSInterruptCheck(MAsmJSInterruptCheck* ins)
}
void
LIRGenerator::visitAsmThrowUnreachable(MAsmThrowUnreachable* ins)
LIRGenerator::visitWasmTrap(MWasmTrap* ins)
{
add(new(alloc()) LAsmThrowUnreachable, ins);
add(new(alloc()) LWasmTrap, ins);
}
void

View File

@ -191,7 +191,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitFunctionEnvironment(MFunctionEnvironment* ins);
void visitInterruptCheck(MInterruptCheck* ins);
void visitAsmJSInterruptCheck(MAsmJSInterruptCheck* ins);
void visitAsmThrowUnreachable(MAsmThrowUnreachable* ins);
void visitWasmTrap(MWasmTrap* ins);
void visitAsmReinterpret(MAsmReinterpret* ins);
void visitStoreSlot(MStoreSlot* ins);
void visitFilterTypeSet(MFilterTypeSet* ins);

View File

@ -7738,18 +7738,28 @@ class MAsmJSInterruptCheck
TRIVIAL_NEW_WRAPPERS
};
// Directly jumps to the unreachable trap handler.
class MAsmThrowUnreachable
// Directly jumps to the indicated trap, leaving Wasm code and reporting a
// runtime error.
class MWasmTrap
: public MAryControlInstruction<0, 0>,
public NoTypePolicy::Data
{
wasm::Trap trap_;
explicit MWasmTrap(wasm::Trap trap)
: trap_(trap)
{}
public:
INSTRUCTION_HEADER(AsmThrowUnreachable)
INSTRUCTION_HEADER(WasmTrap)
TRIVIAL_NEW_WRAPPERS
AliasSet getAliasSet() const override {
return AliasSet::None();
}
wasm::Trap trap() const { return trap_; }
};
// Checks if a value is JS_UNINITIALIZED_LEXICAL, bailout out if so, leaving

View File

@ -262,7 +262,6 @@ namespace jit {
_(CallInstanceOf) \
_(InterruptCheck) \
_(AsmJSInterruptCheck) \
_(AsmThrowUnreachable) \
_(GetDOMProperty) \
_(GetDOMMember) \
_(SetDOMProperty) \
@ -274,6 +273,7 @@ namespace jit {
_(WasmBoundsCheck) \
_(WasmLoad) \
_(WasmStore) \
_(WasmTrap) \
_(WasmTruncateToInt32) \
_(AsmJSNeg) \
_(AsmJSUnsignedToDouble) \

View File

@ -2291,11 +2291,7 @@ CodeGeneratorARM::visitWasmBoundsCheck(LWasmBoundsCheck* ins)
{
MWasmBoundsCheck* mir = ins->mir();
uint32_t offset = mir->offset();
if (offset > INT32_MAX) {
masm.as_b(wasm::JumpTarget::OutOfBounds);
return;
}
MOZ_ASSERT(mir->offset() <= INT32_MAX);
if (!mir->isRedundant()) {
// No guarantee that heapBase + endOffset can be properly encoded in
@ -2348,11 +2344,7 @@ CodeGeneratorARM::emitWasmLoad(T* lir)
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
uint32_t offset = mir->offset();
if (offset > INT32_MAX) {
// This is unreachable because of bounds checks.
masm.breakpoint();
return;
}
MOZ_ASSERT(offset <= INT32_MAX);
Register ptr = ToRegister(lir->ptr());
Scalar::Type type = mir->accessType();
@ -2419,11 +2411,7 @@ CodeGeneratorARM::emitWasmUnalignedLoad(T* lir)
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
uint32_t offset = mir->offset();
if (offset > INT32_MAX) {
// This is unreachable because of bounds checks.
masm.breakpoint();
return;
}
MOZ_ASSERT(offset <= INT32_MAX);
Register ptr = ToRegister(lir->ptrCopy());
if (offset)
@ -2503,11 +2491,7 @@ CodeGeneratorARM::emitWasmStore(T* lir)
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
uint32_t offset = mir->offset();
if (offset > INT32_MAX) {
// This is unreachable because of bounds checks.
masm.breakpoint();
return;
}
MOZ_ASSERT(offset <= INT32_MAX);
Register ptr = ToRegister(lir->ptr());
unsigned byteSize = mir->byteSize();

View File

@ -1666,10 +1666,7 @@ CodeGeneratorMIPSShared::visitWasmBoundsCheck(LWasmBoundsCheck* ins)
MWasmBoundsCheck* mir = ins->mir();
uint32_t offset = mir->offset();
if (offset > INT32_MAX) {
masm.jump(wasm::JumpTarget::OutOfBounds);
return;
}
MOZ_ASSERT(offset <= INT32_MAX);
uint32_t endOffset = mir->endOffset();
Register ptr = ToRegister(ins->ptr());
@ -1693,11 +1690,7 @@ CodeGeneratorMIPSShared::visitWasmLoad(LWasmLoad* lir)
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
uint32_t offset = mir->offset();
if (offset > INT32_MAX) {
// This is unreachable because of bounds checks.
masm.breakpoint();
return;
}
MOZ_ASSERT(offset <= INT32_MAX);
Register ptr = ToRegister(lir->ptr());
@ -1745,11 +1738,7 @@ CodeGeneratorMIPSShared::visitWasmStore(LWasmStore* lir)
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
uint32_t offset = mir->offset();
if (offset > INT32_MAX) {
// This is unreachable because of bounds checks.
masm.breakpoint();
return;
}
MOZ_ASSERT(offset <= INT32_MAX);
Register ptr = ToRegister(lir->ptr());

View File

@ -1404,13 +1404,17 @@ class LAsmJSInterruptCheck : public LInstructionHelper<0, 0, 0>
}
};
class LAsmThrowUnreachable : public LInstructionHelper<0, 0, 0>
class LWasmTrap : public LInstructionHelper<0, 0, 0>
{
public:
LIR_HEADER(AsmThrowUnreachable);
LIR_HEADER(WasmTrap);
LAsmThrowUnreachable()
LWasmTrap()
{ }
const MWasmTrap* mir() const {
return mir_->toWasmTrap();
}
};
template<size_t Defs, size_t Ops>

View File

@ -369,7 +369,7 @@
_(CallInstanceOf) \
_(InterruptCheck) \
_(AsmJSInterruptCheck) \
_(AsmThrowUnreachable) \
_(WasmTrap) \
_(AsmReinterpret) \
_(AsmReinterpretToI64) \
_(AsmReinterpretFromI64) \

View File

@ -538,11 +538,7 @@ CodeGeneratorX64::emitWasmLoad(T* ins)
Scalar::Type accessType = mir->accessType();
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD NYI");
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
if (mir->offset() > INT32_MAX) {
masm.jump(wasm::JumpTarget::OutOfBounds);
return;
}
MOZ_ASSERT(mir->offset() <= INT32_MAX);
const LAllocation* ptr = ins->ptr();
Operand srcAddr = ptr->isBogus()
@ -583,11 +579,7 @@ CodeGeneratorX64::emitWasmStore(T* ins)
Scalar::Type accessType = mir->accessType();
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD NYI");
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
if (mir->offset() > INT32_MAX) {
masm.jump(wasm::JumpTarget::OutOfBounds);
return;
}
MOZ_ASSERT(mir->offset() <= INT32_MAX);
const LAllocation* value = ins->getOperand(ins->ValueIndex);
const LAllocation* ptr = ins->ptr();

View File

@ -494,11 +494,9 @@ void
CodeGeneratorX86Shared::visitWasmBoundsCheck(LWasmBoundsCheck* ins)
{
const MWasmBoundsCheck* mir = ins->mir();
MOZ_ASSERT(gen->needsBoundsCheckBranch(mir));
if (mir->offset() > INT32_MAX) {
masm.jump(wasm::JumpTarget::OutOfBounds);
return;
}
MOZ_ASSERT(mir->offset() <= INT32_MAX);
Register ptrReg = ToRegister(ins->ptr());
maybeEmitWasmBoundsCheckBranch(mir, ptrReg, mir->isRedundant());
@ -548,9 +546,8 @@ CodeGeneratorX86Shared::maybeEmitWasmBoundsCheckBranch(const MWasmMemoryAccess*
MOZ_ASSERT(mir->endOffset() >= 1,
"need to subtract 1 to use JAE, see also AssemblerX86Shared::UpdateBoundsCheck");
/*
* TODO: See 1287224 Unify MWasmBoundsCheck::redunant_ and needsBoundsCheck
*/
// TODO: See 1287224 Unify MWasmBoundsCheck::redunant_ and needsBoundsCheck
if (!redundant) {
uint32_t cmpOffset = masm.cmp32WithPatch(ptr, Imm32(1 - mir->endOffset())).offset();
masm.j(Assembler::AboveOrEqual, wasm::JumpTarget::OutOfBounds);

View File

@ -500,12 +500,7 @@ CodeGeneratorX86::emitWasmLoad(T* ins)
Scalar::Type accessType = mir->accessType();
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD NYI");
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
if (mir->offset() > INT32_MAX) {
// This is unreachable because of the bounds check.
masm.breakpoint();
return;
}
MOZ_ASSERT(mir->offset() <= INT32_MAX);
const LAllocation* ptr = ins->ptr();
Operand srcAddr = ptr->isBogus()
@ -539,12 +534,7 @@ CodeGeneratorX86::emitWasmStore(T* ins)
Scalar::Type accessType = mir->accessType();
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD NYI");
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
if (mir->offset() > INT32_MAX) {
// This is unreachable because of the bounds check.
masm.breakpoint();
return;
}
MOZ_ASSERT(mir->offset() <= INT32_MAX);
const LAllocation* ptr = ins->ptr();
Operand dstAddr = ptr->isBogus()