Bug 864214 - Generate MIR nodes for accessing statically known typed arrays on x86, r=luke,jandem.

This commit is contained in:
Brian Hackett 2013-04-27 15:02:42 -06:00
Родитель 5e695a24f0
Коммит 921409a189
28 изменённых файлов: 526 добавлений и 29 удалений

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

@ -6231,9 +6231,93 @@ IonBuilder::getTypedArrayElements(MDefinition *obj)
return MTypedArrayElements::New(obj);
}
MDefinition *
IonBuilder::convertShiftToMaskForStaticTypedArray(MDefinition *id,
ArrayBufferView::ViewType viewType)
{
if (!id->isRsh() || id->isEffectful())
return NULL;
if (!id->getOperand(1)->isConstant())
return NULL;
const Value &value = id->getOperand(1)->toConstant()->value();
if (!value.isInt32() || uint32_t(value.toInt32()) != TypedArrayShift(viewType))
return NULL;
// Instead of shifting, mask off the low bits of the index so that
// a non-scaled access on the typed array can be performed.
MConstant *mask = MConstant::New(Int32Value(~((1 << value.toInt32()) - 1)));
MBitAnd *ptr = MBitAnd::New(id->getOperand(0), mask);
ptr->infer();
JS_ASSERT(!ptr->isEffectful());
current->add(mask);
current->add(ptr);
return ptr;
}
bool
IonBuilder::jsop_getelem_typed_static(bool *psucceeded)
{
if (!LIRGenerator::allowStaticTypedArrayAccesses())
return true;
MDefinition *id = current->peek(-1);
MDefinition *obj = current->peek(-2);
if (ElementAccessHasExtraIndexedProperty(cx, obj))
return true;
if (!obj->resultTypeSet())
return true;
JSObject *typedArray = obj->resultTypeSet()->getSingleton();
if (!typedArray)
return true;
JS_ASSERT(typedArray->isTypedArray());
ArrayBufferView::ViewType viewType = JS_GetArrayBufferViewType(typedArray);
MDefinition *ptr = convertShiftToMaskForStaticTypedArray(id, viewType);
if (!ptr)
return true;
obj->setFolded();
MLoadTypedArrayElementStatic *load = MLoadTypedArrayElementStatic::New(typedArray, ptr);
current->add(load);
// The load is infallible if an undefined result will be coerced to the
// appropriate numeric type if the read is out of bounds. The truncation
// analysis picks up some of these cases, but is incomplete with respect
// to others. For now, sniff the bytecode for simple patterns following
// the load which guarantee a truncation or numeric conversion.
if (viewType == ArrayBufferView::TYPE_FLOAT32 || viewType == ArrayBufferView::TYPE_FLOAT64) {
jsbytecode *next = pc + JSOP_GETELEM_LENGTH;
if (*next == JSOP_POS)
load->setInfallible();
} else {
jsbytecode *next = pc + JSOP_GETELEM_LENGTH;
if (*next == JSOP_ZERO && *(next + JSOP_ZERO_LENGTH) == JSOP_BITOR)
load->setInfallible();
}
current->popn(2);
current->push(load);
*psucceeded = true;
return true;
}
bool
IonBuilder::jsop_getelem_typed(int arrayType)
{
bool staticAccess = false;
if (!jsop_getelem_typed_static(&staticAccess))
return false;
if (staticAccess)
return true;
types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc);
MDefinition *id = current->pop();
@ -6447,9 +6531,59 @@ IonBuilder::jsop_setelem_dense(types::StackTypeSet::DoubleConversion conversion)
return true;
}
bool
IonBuilder::jsop_setelem_typed_static(bool *psucceeded)
{
if (!LIRGenerator::allowStaticTypedArrayAccesses())
return true;
MDefinition *value = current->peek(-1);
MDefinition *id = current->peek(-2);
MDefinition *obj = current->peek(-3);
if (ElementAccessHasExtraIndexedProperty(cx, obj))
return true;
if (!obj->resultTypeSet())
return true;
JSObject *typedArray = obj->resultTypeSet()->getSingleton();
if (!typedArray)
return true;
JS_ASSERT(typedArray->isTypedArray());
ArrayBufferView::ViewType viewType = JS_GetArrayBufferViewType(typedArray);
MDefinition *ptr = convertShiftToMaskForStaticTypedArray(id, viewType);
if (!ptr)
return true;
obj->setFolded();
// Clamp value to [0, 255] for Uint8ClampedArray.
MDefinition *toWrite = value;
if (viewType == ArrayBufferView::TYPE_UINT8_CLAMPED) {
toWrite = MClampToUint8::New(value);
current->add(toWrite->toInstruction());
}
MInstruction *store = MStoreTypedArrayElementStatic::New(typedArray, ptr, toWrite);
current->add(store);
current->popn(3);
current->push(value);
*psucceeded = true;
return resumeAfter(store);
}
bool
IonBuilder::jsop_setelem_typed(int arrayType)
{
bool staticAccess = false;
if (!jsop_setelem_typed_static(&staticAccess))
return false;
if (staticAccess)
return true;
MDefinition *value = current->pop();
MDefinition *id = current->pop();
MDefinition *obj = current->pop();

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

@ -324,6 +324,8 @@ class IonBuilder : public MIRGenerator
MInstruction *addShapeGuard(MDefinition *obj, const RawShape shape, BailoutKind bailoutKind);
JSObject *getNewArrayTemplateObject(uint32_t count);
MDefinition *convertShiftToMaskForStaticTypedArray(MDefinition *id,
ArrayBufferView::ViewType viewType);
bool invalidatedIdempotentCache();
@ -377,10 +379,12 @@ class IonBuilder : public MIRGenerator
bool jsop_getelem();
bool jsop_getelem_dense();
bool jsop_getelem_typed(int arrayType);
bool jsop_getelem_typed_static(bool *psucceeded);
bool jsop_getelem_string();
bool jsop_setelem();
bool jsop_setelem_dense(types::StackTypeSet::DoubleConversion conversion);
bool jsop_setelem_typed(int arrayType);
bool jsop_setelem_typed_static(bool *psucceeded);
bool jsop_length();
bool jsop_length_fastPath();
bool jsop_arguments();

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

@ -3228,6 +3228,21 @@ class LLoadTypedArrayElementHole : public LInstructionHelper<BOX_PIECES, 2, 0>
}
};
class LLoadTypedArrayElementStatic : public LInstructionHelper<1, 1, 0>
{
public:
LIR_HEADER(LoadTypedArrayElementStatic);
LLoadTypedArrayElementStatic(const LAllocation &ptr) {
setOperand(0, ptr);
}
MLoadTypedArrayElementStatic *mir() const {
return mir_->toLoadTypedArrayElementStatic();
}
const LAllocation *ptr() {
return getOperand(0);
}
};
class LStoreTypedArrayElement : public LInstructionHelper<0, 3, 0>
{
public:
@ -3285,6 +3300,25 @@ class LStoreTypedArrayElementHole : public LInstructionHelper<0, 4, 0>
}
};
class LStoreTypedArrayElementStatic : public LInstructionHelper<0, 2, 0>
{
public:
LIR_HEADER(StoreTypedArrayElementStatic);
LStoreTypedArrayElementStatic(const LAllocation &ptr, const LAllocation &value) {
setOperand(0, ptr);
setOperand(1, value);
}
MStoreTypedArrayElementStatic *mir() const {
return mir_->toStoreTypedArrayElementStatic();
}
const LAllocation *ptr() {
return getOperand(0);
}
const LAllocation *value() {
return getOperand(1);
}
};
class LEffectiveAddress : public LInstructionHelper<1, 2, 0>
{
public:

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

@ -158,8 +158,10 @@
_(StoreElementHoleT) \
_(LoadTypedArrayElement) \
_(LoadTypedArrayElementHole) \
_(LoadTypedArrayElementStatic) \
_(StoreTypedArrayElement) \
_(StoreTypedArrayElementHole) \
_(StoreTypedArrayElementStatic) \
_(EffectiveAddress) \
_(ClampIToUint8) \
_(ClampDToUint8) \

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

@ -2109,6 +2109,17 @@ LIRGenerator::visitLoadTypedArrayElementHole(MLoadTypedArrayElementHole *ins)
return defineBox(lir, ins) && assignSafepoint(lir, ins);
}
bool
LIRGenerator::visitLoadTypedArrayElementStatic(MLoadTypedArrayElementStatic *ins)
{
LLoadTypedArrayElementStatic *lir =
new LLoadTypedArrayElementStatic(useRegisterAtStart(ins->ptr()));
if (ins->fallible() && !assignSnapshot(lir))
return false;
return define(lir, ins);
}
bool
LIRGenerator::visitLoadFixedSlot(MLoadFixedSlot *ins)
{

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

@ -189,6 +189,7 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitArrayConcat(MArrayConcat *ins);
bool visitLoadTypedArrayElement(MLoadTypedArrayElement *ins);
bool visitLoadTypedArrayElementHole(MLoadTypedArrayElementHole *ins);
bool visitLoadTypedArrayElementStatic(MLoadTypedArrayElementStatic *ins);
bool visitClampToUint8(MClampToUint8 *ins);
bool visitLoadFixedSlot(MLoadFixedSlot *ins);
bool visitStoreFixedSlot(MStoreFixedSlot *ins);

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

@ -15,7 +15,7 @@
#include "jsnum.h"
#include "jsstr.h"
#include "jsatominlines.h"
#include "jstypedarrayinlines.h" // For ClampIntForUint8Array
#include "jstypedarrayinlines.h"
using namespace js;
using namespace js::ion;
@ -2195,6 +2195,30 @@ MInArray::needsNegativeIntCheck() const
return !index()->range() || index()->range()->lower() < 0;
}
void *
MLoadTypedArrayElementStatic::base() const
{
return TypedArray::viewData(typedArray_);
}
size_t
MLoadTypedArrayElementStatic::length() const
{
return TypedArray::byteLength(typedArray_);
}
void *
MStoreTypedArrayElementStatic::base() const
{
return TypedArray::viewData(typedArray_);
}
size_t
MStoreTypedArrayElementStatic::length() const
{
return TypedArray::byteLength(typedArray_);
}
MDefinition *
MAsmJSUnsignedToDouble::foldsTo(bool useValueNumbers)
{

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

@ -4827,6 +4827,50 @@ class MLoadTypedArrayElementHole
}
};
// Load a value fallibly or infallibly from a statically known typed array.
class MLoadTypedArrayElementStatic : public MUnaryInstruction
{
MLoadTypedArrayElementStatic(JSObject *typedArray, MDefinition *ptr)
: MUnaryInstruction(ptr), typedArray_(typedArray), fallible_(true)
{
int type = TypedArray::type(typedArray_);
if (type == TypedArray::TYPE_FLOAT32 || type == TypedArray::TYPE_FLOAT64)
setResultType(MIRType_Double);
else
setResultType(MIRType_Int32);
}
CompilerRootObject typedArray_;
bool fallible_;
public:
INSTRUCTION_HEADER(LoadTypedArrayElementStatic);
static MLoadTypedArrayElementStatic *New(JSObject *typedArray, MDefinition *ptr) {
return new MLoadTypedArrayElementStatic(typedArray, ptr);
}
ArrayBufferView::ViewType viewType() const { return JS_GetArrayBufferViewType(typedArray_); }
void *base() const;
size_t length() const;
MDefinition *ptr() const { return getOperand(0); }
AliasSet getAliasSet() const {
return AliasSet::Load(AliasSet::TypedArrayElement);
}
bool fallible() const {
return fallible_;
}
void setInfallible() {
fallible_ = false;
}
void computeRange();
bool truncate();
};
class MStoreTypedArrayElement
: public MTernaryInstruction,
public StoreTypedArrayPolicy
@ -4951,6 +4995,39 @@ class MStoreTypedArrayElementHole
}
};
// Store a value infallibly to a statically known typed array.
class MStoreTypedArrayElementStatic :
public MBinaryInstruction
, public StoreTypedArrayElementStaticPolicy
{
MStoreTypedArrayElementStatic(JSObject *typedArray, MDefinition *ptr, MDefinition *v)
: MBinaryInstruction(ptr, v), typedArray_(typedArray)
{}
CompilerRootObject typedArray_;
public:
INSTRUCTION_HEADER(StoreTypedArrayElementStatic);
static MStoreTypedArrayElementStatic *New(JSObject *typedArray, MDefinition *ptr, MDefinition *v) {
return new MStoreTypedArrayElementStatic(typedArray, ptr, v);
}
TypePolicy *typePolicy() {
return this;
}
ArrayBufferView::ViewType viewType() const { return JS_GetArrayBufferViewType(typedArray_); }
void *base() const;
size_t length() const;
MDefinition *ptr() const { return getOperand(0); }
MDefinition *value() const { return getOperand(1); }
AliasSet getAliasSet() const {
return AliasSet::Store(AliasSet::TypedArrayElement);
}
};
// Compute an "effective address", i.e., a compound computation of the form:
// base + index * scale + displacement
class MEffectiveAddress : public MBinaryInstruction

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

@ -126,8 +126,10 @@ namespace ion {
_(ArrayConcat) \
_(LoadTypedArrayElement) \
_(LoadTypedArrayElementHole) \
_(LoadTypedArrayElementStatic) \
_(StoreTypedArrayElement) \
_(StoreTypedArrayElementHole) \
_(StoreTypedArrayElementStatic) \
_(EffectiveAddress) \
_(ClampToUint8) \
_(LoadFixedSlot) \

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

@ -213,8 +213,10 @@ class ParallelArrayVisitor : public MInstructionVisitor
UNSAFE_OP(ArrayPush)
SAFE_OP(LoadTypedArrayElement)
SAFE_OP(LoadTypedArrayElementHole)
SAFE_OP(LoadTypedArrayElementStatic)
MAYBE_WRITE_GUARDED_OP(StoreTypedArrayElement, elements)
WRITE_GUARDED_OP(StoreTypedArrayElementHole, elements)
UNSAFE_OP(StoreTypedArrayElementStatic)
UNSAFE_OP(ClampToUint8)
SAFE_OP(LoadFixedSlot)
WRITE_GUARDED_OP(StoreFixedSlot, object)

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

@ -750,6 +750,12 @@ MToInt32::computeRange()
setRange(new Range(input.lower(), input.upper()));
}
void
MLoadTypedArrayElementStatic::computeRange()
{
setRange(new Range(this));
}
///////////////////////////////////////////////////////////////////////////////
// Range Analysis
///////////////////////////////////////////////////////////////////////////////
@ -1336,6 +1342,13 @@ MToDouble::truncate()
return true;
}
bool
MLoadTypedArrayElementStatic::truncate()
{
setInfallible();
return false;
}
bool
MDefinition::isOperandTruncated(size_t index) const
{

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

@ -548,6 +548,15 @@ StoreTypedArrayHolePolicy::adjustInputs(MInstruction *ins)
return adjustValueInput(ins, store->arrayType(), store->value(), 3);
}
bool
StoreTypedArrayElementStaticPolicy::adjustInputs(MInstruction *ins)
{
MStoreTypedArrayElementStatic *store = ins->toStoreTypedArrayElementStatic();
JS_ASSERT(store->ptr()->type() == MIRType_Int32);
return adjustValueInput(ins, store->viewType(), store->value(), 1);
}
bool
ClampPolicy::adjustInputs(MInstruction *ins)
{

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

@ -229,6 +229,12 @@ class StoreTypedArrayHolePolicy : public StoreTypedArrayPolicy
bool adjustInputs(MInstruction *ins);
};
class StoreTypedArrayElementStaticPolicy : public StoreTypedArrayPolicy
{
public:
bool adjustInputs(MInstruction *ins);
};
// Accepts integers and doubles. Everything else is boxed.
class ClampPolicy : public BoxInputsPolicy
{

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

@ -1661,6 +1661,20 @@ getBase(U *mir)
return InvalidReg;
}
bool
CodeGeneratorARM::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic *ins)
{
JS_NOT_REACHED("NYI");
return true;
}
bool
CodeGeneratorARM::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic *ins)
{
JS_NOT_REACHED("NYI");
return true;
}
bool
CodeGeneratorARM::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins)
{

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

@ -143,6 +143,8 @@ class CodeGeneratorARM : public CodeGeneratorShared
bool visitNegI(LNegI *lir);
bool visitNegD(LNegD *lir);
bool visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic *ins);
bool visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic *ins);
bool visitAsmJSLoadHeap(LAsmJSLoadHeap *ins);
bool visitAsmJSStoreHeap(LAsmJSStoreHeap *ins);
bool visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins);

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

@ -461,4 +461,11 @@ LIRGeneratorARM::lowerTruncateDToInt32(MTruncateToInt32 *ins)
return define(new LTruncateDToInt32(useRegister(opd), LDefinition::BogusTemp()), ins);
}
bool
LIRGeneratorARM::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins)
{
JS_NOT_REACHED("NYI");
return true;
}
//__aeabi_uidiv

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

@ -72,6 +72,7 @@ class LIRGeneratorARM : public LIRGeneratorShared
bool visitAsmJSStoreHeap(MAsmJSStoreHeap *ins);
bool visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins);
bool visitInterruptCheck(MInterruptCheck *ins);
bool visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins);
};
typedef LIRGeneratorARM LIRGeneratorSpecific;

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

@ -175,6 +175,11 @@ class LIRGeneratorShared : public MInstructionVisitorWithDefaults
static bool allowTypedElementHoleCheck() {
return false;
}
// Whether to generate typed array accesses on statically known objects.
static bool allowStaticTypedArrayAccesses() {
return false;
}
};
} // namespace ion

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

@ -384,6 +384,20 @@ CodeGeneratorX64::visitUInt32ToDouble(LUInt32ToDouble *lir)
return true;
}
bool
CodeGeneratorX64::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic *ins)
{
JS_NOT_REACHED("NYI");
return true;
}
bool
CodeGeneratorX64::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic *ins)
{
JS_NOT_REACHED("NYI");
return true;
}
bool
CodeGeneratorX64::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins)
{

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

@ -52,6 +52,8 @@ class CodeGeneratorX64 : public CodeGeneratorX86Shared
bool visitCompareVAndBranch(LCompareVAndBranch *lir);
bool visitUInt32ToDouble(LUInt32ToDouble *lir);
bool visitTruncateDToInt32(LTruncateDToInt32 *ins);
bool visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic *ins);
bool visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic *ins);
bool visitAsmJSLoadHeap(LAsmJSLoadHeap *ins);
bool visitAsmJSStoreHeap(LAsmJSStoreHeap *ins);
bool visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins);

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

@ -214,3 +214,10 @@ LIRGeneratorX64::lowerTruncateDToInt32(MTruncateToInt32 *ins)
return define(new LTruncateDToInt32(useRegister(opd), LDefinition::BogusTemp()), ins);
}
bool
LIRGeneratorX64::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins)
{
JS_NOT_REACHED("NYI");
return true;
}

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

@ -49,6 +49,7 @@ class LIRGeneratorX64 : public LIRGeneratorX86Shared
bool visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins);
bool visitAsmJSStoreHeap(MAsmJSStoreHeap *ins);
bool visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins);
bool visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins);
};
typedef LIRGeneratorX64 LIRGeneratorSpecific;

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

@ -397,25 +397,84 @@ CodeGeneratorX86::visitUInt32ToDouble(LUInt32ToDouble *lir)
return true;
}
class ion::OutOfLineAsmJSLoadHeapOutOfBounds : public OutOfLineCodeBase<CodeGeneratorX86>
// Load a NaN or zero into a register for an out of bounds AsmJS or static
// typed array load.
class ion::OutOfLineLoadTypedArrayOutOfBounds : public OutOfLineCodeBase<CodeGeneratorX86>
{
AnyRegister dest_;
public:
OutOfLineAsmJSLoadHeapOutOfBounds(AnyRegister dest) : dest_(dest) {}
OutOfLineLoadTypedArrayOutOfBounds(AnyRegister dest) : dest_(dest) {}
const AnyRegister &dest() const { return dest_; }
bool accept(CodeGeneratorX86 *codegen) { return codegen->visitOutOfLineAsmJSLoadHeapOutOfBounds(this); }
bool accept(CodeGeneratorX86 *codegen) { return codegen->visitOutOfLineLoadTypedArrayOutOfBounds(this); }
};
void
CodeGeneratorX86::loadViewTypeElement(ArrayBufferView::ViewType vt, const Address &srcAddr,
const LDefinition *out)
{
switch (vt) {
case ArrayBufferView::TYPE_INT8: masm.movxblWithPatch(srcAddr, ToRegister(out)); break;
case ArrayBufferView::TYPE_UINT8_CLAMPED:
case ArrayBufferView::TYPE_UINT8: masm.movzblWithPatch(srcAddr, ToRegister(out)); break;
case ArrayBufferView::TYPE_INT16: masm.movxwlWithPatch(srcAddr, ToRegister(out)); break;
case ArrayBufferView::TYPE_UINT16: masm.movzwlWithPatch(srcAddr, ToRegister(out)); break;
case ArrayBufferView::TYPE_INT32: masm.movlWithPatch(srcAddr, ToRegister(out)); break;
case ArrayBufferView::TYPE_UINT32: masm.movlWithPatch(srcAddr, ToRegister(out)); break;
case ArrayBufferView::TYPE_FLOAT64: masm.movsdWithPatch(srcAddr, ToFloatRegister(out)); break;
default: JS_NOT_REACHED("unexpected array type");
}
}
bool
CodeGeneratorX86::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic *ins)
{
const MLoadTypedArrayElementStatic *mir = ins->mir();
ArrayBufferView::ViewType vt = mir->viewType();
Register ptr = ToRegister(ins->ptr());
const LDefinition *out = ins->output();
OutOfLineLoadTypedArrayOutOfBounds *ool = NULL;
if (!mir->fallible()) {
ool = new OutOfLineLoadTypedArrayOutOfBounds(ToAnyRegister(out));
if (!addOutOfLineCode(ool))
return false;
}
masm.cmpl(ptr, Imm32(mir->length()));
if (ool)
masm.j(Assembler::AboveOrEqual, ool->entry());
else if (!bailoutIf(Assembler::AboveOrEqual, ins->snapshot()))
return false;
Address srcAddr(ptr, (int32_t) mir->base());
if (vt == ArrayBufferView::TYPE_FLOAT32) {
FloatRegister dest = ToFloatRegister(out);
masm.movssWithPatch(srcAddr, dest);
masm.cvtss2sd(dest, dest);
if (ool)
masm.bind(ool->rejoin());
return true;
}
loadViewTypeElement(vt, srcAddr, out);
if (ool)
masm.bind(ool->rejoin());
return true;
}
bool
CodeGeneratorX86::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins)
{
// This is identical to LoadTypedArrayElementStatic, except that the
// array's base and length are not known ahead of time and can be patched
// later on, and the instruction is always infallible.
const MAsmJSLoadHeap *mir = ins->mir();
ArrayBufferView::ViewType vt = mir->viewType();
Register ptr = ToRegister(ins->ptr());
const LDefinition *out = ins->output();
OutOfLineAsmJSLoadHeapOutOfBounds *ool = new OutOfLineAsmJSLoadHeapOutOfBounds(ToAnyRegister(out));
OutOfLineLoadTypedArrayOutOfBounds *ool = new OutOfLineLoadTypedArrayOutOfBounds(ToAnyRegister(out));
if (!addOutOfLineCode(ool))
return false;
@ -433,23 +492,14 @@ CodeGeneratorX86::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins)
return gen->noteHeapAccess(AsmJSHeapAccess(cmp.offset(), before, after, vt, AnyRegister(dest)));
}
uint32_t before = masm.size();
switch (vt) {
case ArrayBufferView::TYPE_INT8: masm.movxblWithPatch(srcAddr, ToRegister(out)); break;
case ArrayBufferView::TYPE_UINT8: masm.movzblWithPatch(srcAddr, ToRegister(out)); break;
case ArrayBufferView::TYPE_INT16: masm.movxwlWithPatch(srcAddr, ToRegister(out)); break;
case ArrayBufferView::TYPE_UINT16: masm.movzwlWithPatch(srcAddr, ToRegister(out)); break;
case ArrayBufferView::TYPE_INT32: masm.movlWithPatch(srcAddr, ToRegister(out)); break;
case ArrayBufferView::TYPE_UINT32: masm.movlWithPatch(srcAddr, ToRegister(out)); break;
case ArrayBufferView::TYPE_FLOAT64: masm.movsdWithPatch(srcAddr, ToFloatRegister(out)); break;
default: JS_NOT_REACHED("unexpected array type");
}
loadViewTypeElement(vt, srcAddr, out);
uint32_t after = masm.size();
masm.bind(ool->rejoin());
return gen->noteHeapAccess(AsmJSHeapAccess(cmp.offset(), before, after, vt, ToAnyRegister(out)));
}
bool
CodeGeneratorX86::visitOutOfLineAsmJSLoadHeapOutOfBounds(OutOfLineAsmJSLoadHeapOutOfBounds *ool)
CodeGeneratorX86::visitOutOfLineLoadTypedArrayOutOfBounds(OutOfLineLoadTypedArrayOutOfBounds *ool)
{
if (ool->dest().isFloat())
masm.movsd(&js_NaN, ool->dest().fpu());
@ -459,9 +509,54 @@ CodeGeneratorX86::visitOutOfLineAsmJSLoadHeapOutOfBounds(OutOfLineAsmJSLoadHeapO
return true;
}
void
CodeGeneratorX86::storeViewTypeElement(ArrayBufferView::ViewType vt, const LAllocation *value,
const Address &dstAddr)
{
switch (vt) {
case ArrayBufferView::TYPE_INT8: masm.movbWithPatch(ToRegister(value), dstAddr); break;
case ArrayBufferView::TYPE_UINT8_CLAMPED:
case ArrayBufferView::TYPE_UINT8: masm.movbWithPatch(ToRegister(value), dstAddr); break;
case ArrayBufferView::TYPE_INT16: masm.movwWithPatch(ToRegister(value), dstAddr); break;
case ArrayBufferView::TYPE_UINT16: masm.movwWithPatch(ToRegister(value), dstAddr); break;
case ArrayBufferView::TYPE_INT32: masm.movlWithPatch(ToRegister(value), dstAddr); break;
case ArrayBufferView::TYPE_UINT32: masm.movlWithPatch(ToRegister(value), dstAddr); break;
case ArrayBufferView::TYPE_FLOAT64: masm.movsdWithPatch(ToFloatRegister(value), dstAddr); break;
default: JS_NOT_REACHED("unexpected array type");
}
}
bool
CodeGeneratorX86::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic *ins)
{
MStoreTypedArrayElementStatic *mir = ins->mir();
ArrayBufferView::ViewType vt = mir->viewType();
Register ptr = ToRegister(ins->ptr());
const LAllocation *value = ins->value();
masm.cmpl(ptr, Imm32(mir->length()));
Label rejoin;
masm.j(Assembler::AboveOrEqual, &rejoin);
Address dstAddr(ptr, (int32_t) mir->base());
if (vt == ArrayBufferView::TYPE_FLOAT32) {
masm.convertDoubleToFloat(ToFloatRegister(value), ScratchFloatReg);
masm.movssWithPatch(ScratchFloatReg, dstAddr);
masm.bind(&rejoin);
return true;
}
storeViewTypeElement(vt, value, dstAddr);
masm.bind(&rejoin);
return true;
}
bool
CodeGeneratorX86::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins)
{
// This is identical to StoreTypedArrayElementStatic, except that the
// array's base and length are not known ahead of time and can be patched
// later on.
MAsmJSStoreHeap *mir = ins->mir();
ArrayBufferView::ViewType vt = mir->viewType();
@ -482,16 +577,7 @@ CodeGeneratorX86::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins)
return gen->noteHeapAccess(AsmJSHeapAccess(cmp.offset(), before, after));
}
uint32_t before = masm.size();
switch (vt) {
case ArrayBufferView::TYPE_INT8: masm.movbWithPatch(ToRegister(value), dstAddr); break;
case ArrayBufferView::TYPE_UINT8: masm.movbWithPatch(ToRegister(value), dstAddr); break;
case ArrayBufferView::TYPE_INT16: masm.movwWithPatch(ToRegister(value), dstAddr); break;
case ArrayBufferView::TYPE_UINT16: masm.movwWithPatch(ToRegister(value), dstAddr); break;
case ArrayBufferView::TYPE_INT32: masm.movlWithPatch(ToRegister(value), dstAddr); break;
case ArrayBufferView::TYPE_UINT32: masm.movlWithPatch(ToRegister(value), dstAddr); break;
case ArrayBufferView::TYPE_FLOAT64: masm.movsdWithPatch(ToFloatRegister(value), dstAddr); break;
default: JS_NOT_REACHED("unexpected array type");
}
storeViewTypeElement(vt, value, dstAddr);
uint32_t after = masm.size();
masm.bind(&rejoin);
return gen->noteHeapAccess(AsmJSHeapAccess(cmp.offset(), before, after));

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

@ -13,7 +13,7 @@
namespace js {
namespace ion {
class OutOfLineAsmJSLoadHeapOutOfBounds;
class OutOfLineLoadTypedArrayOutOfBounds;
class OutOfLineTruncate;
class CodeGeneratorX86 : public CodeGeneratorX86Shared
@ -28,6 +28,10 @@ class CodeGeneratorX86 : public CodeGeneratorX86Shared
ValueOperand ToOutValue(LInstruction *ins);
ValueOperand ToTempValue(LInstruction *ins, size_t pos);
void loadViewTypeElement(ArrayBufferView::ViewType vt, const Address &srcAddr,
const LDefinition *out);
void storeViewTypeElement(ArrayBufferView::ViewType vt, const LAllocation *value,
const Address &dstAddr);
void storeElementTyped(const LAllocation *value, MIRType valueType, MIRType elementType,
const Register &elements, const LAllocation *index);
@ -52,6 +56,8 @@ class CodeGeneratorX86 : public CodeGeneratorX86Shared
bool visitCompareVAndBranch(LCompareVAndBranch *lir);
bool visitUInt32ToDouble(LUInt32ToDouble *lir);
bool visitTruncateDToInt32(LTruncateDToInt32 *ins);
bool visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic *ins);
bool visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic *ins);
bool visitAsmJSLoadHeap(LAsmJSLoadHeap *ins);
bool visitAsmJSStoreHeap(LAsmJSStoreHeap *ins);
bool visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins);
@ -59,7 +65,7 @@ class CodeGeneratorX86 : public CodeGeneratorX86Shared
bool visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr *ins);
bool visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc *ins);
bool visitOutOfLineAsmJSLoadHeapOutOfBounds(OutOfLineAsmJSLoadHeapOutOfBounds *ool);
bool visitOutOfLineLoadTypedArrayOutOfBounds(OutOfLineLoadTypedArrayOutOfBounds *ool);
bool visitOutOfLineTruncate(OutOfLineTruncate *ool);
void postAsmJSCall(LAsmJSCall *lir);

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

@ -280,6 +280,30 @@ LIRGeneratorX86::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins)
return add(lir, ins);
}
bool
LIRGeneratorX86::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins)
{
// The code generated for StoreTypedArrayElementStatic is identical to that
// for AsmJSStoreHeap, and the same concerns apply.
LStoreTypedArrayElementStatic *lir;
switch (ins->viewType()) {
case ArrayBufferView::TYPE_INT8: case ArrayBufferView::TYPE_UINT8:
case ArrayBufferView::TYPE_UINT8_CLAMPED:
lir = new LStoreTypedArrayElementStatic(useRegister(ins->ptr()),
useFixed(ins->value(), eax));
break;
case ArrayBufferView::TYPE_INT16: case ArrayBufferView::TYPE_UINT16:
case ArrayBufferView::TYPE_INT32: case ArrayBufferView::TYPE_UINT32:
case ArrayBufferView::TYPE_FLOAT32: case ArrayBufferView::TYPE_FLOAT64:
lir = new LStoreTypedArrayElementStatic(useRegisterAtStart(ins->ptr()),
useRegisterAtStart(ins->value()));
break;
default: JS_NOT_REACHED("unexpected array type");
}
return add(lir, ins);
}
bool
LIRGeneratorX86::visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins)
{

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

@ -51,11 +51,16 @@ class LIRGeneratorX86 : public LIRGeneratorX86Shared
bool visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins);
bool visitAsmJSStoreHeap(MAsmJSStoreHeap *ins);
bool visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins);
bool visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins);
bool lowerPhi(MPhi *phi);
static bool allowTypedElementHoleCheck() {
return true;
}
static bool allowStaticTypedArrayAccesses() {
return true;
}
};
typedef LIRGeneratorX86 LIRGeneratorSpecific;

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

@ -2754,7 +2754,10 @@ types::TypeCanHaveExtraIndexedProperties(JSContext *cx, StackTypeSet *types)
{
Class *clasp = types->getKnownClass();
if (!clasp || ClassCanHaveExtraProperties(clasp))
// Note: typed arrays have indexed properties not accounted for by type
// information, though these are all in bounds and will be accounted for
// by JIT paths.
if (!clasp || (ClassCanHaveExtraProperties(clasp) && !IsTypedArrayClass(clasp)))
return true;
if (types->hasObjectFlags(cx, types::OBJECT_FLAG_SPARSE_INDEXES))

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

@ -321,6 +321,7 @@ TypedArrayShift(ArrayBufferView::ViewType viewType)
switch (viewType) {
case ArrayBufferView::TYPE_INT8:
case ArrayBufferView::TYPE_UINT8:
case ArrayBufferView::TYPE_UINT8_CLAMPED:
return 0;
case ArrayBufferView::TYPE_INT16:
case ArrayBufferView::TYPE_UINT16: