зеркало из https://github.com/mozilla/gecko-dev.git
Bug 864214 - Generate MIR nodes for accessing statically known typed arrays on x86, r=luke,jandem.
This commit is contained in:
Родитель
5e695a24f0
Коммит
921409a189
|
@ -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:
|
||||
|
|
Загрузка…
Ссылка в новой задаче