Bug 1526403 - Part 3: Add inlining support for TypedArray "byteOffset" getter. r=jandem

This commit is contained in:
André Bargull 2019-02-11 05:08:33 -08:00
Родитель d0a6de319b
Коммит 249b82f253
14 изменённых файлов: 145 добавлений и 48 удалений

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

@ -128,6 +128,7 @@ static inline const MDefinition* GetObject(const MDefinition* ins) {
case MDefinition::Opcode::MaybeCopyElementsForWrite:
case MDefinition::Opcode::MaybeToDoubleElement:
case MDefinition::Opcode::TypedArrayLength:
case MDefinition::Opcode::TypedArrayByteOffset:
case MDefinition::Opcode::SetTypedObjectOffset:
case MDefinition::Opcode::SetDisjointTypedElements:
case MDefinition::Opcode::ArrayPopShift:

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

@ -7449,6 +7449,12 @@ void CodeGenerator::visitTypedArrayLength(LTypedArrayLength* lir) {
masm.unboxInt32(Address(obj, TypedArrayObject::lengthOffset()), out);
}
void CodeGenerator::visitTypedArrayByteOffset(LTypedArrayByteOffset* lir) {
Register obj = ToRegister(lir->object());
Register out = ToRegister(lir->output());
masm.unboxInt32(Address(obj, TypedArrayObject::byteOffsetOffset()), out);
}
void CodeGenerator::visitTypedArrayElements(LTypedArrayElements* lir) {
Register obj = ToRegister(lir->object());
Register out = ToRegister(lir->output());

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

@ -149,6 +149,7 @@
_(IntrinsicIsPossiblyWrappedTypedArray) \
_(IntrinsicTypedArrayLength) \
_(IntrinsicPossiblyWrappedTypedArrayLength) \
_(IntrinsicTypedArrayByteOffset) \
_(IntrinsicSetDisjointTypedElements) \
\
_(IntrinsicObjectIsTypedObject) \

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

@ -9156,6 +9156,21 @@ void IonBuilder::addTypedArrayLengthAndData(MDefinition* obj,
}
}
MInstruction* IonBuilder::addTypedArrayByteOffset(MDefinition* obj) {
MInstruction* byteOffset;
if (TypedArrayObject* tarr = tryTypedArrayEmbedConstantElements(obj)) {
obj->setImplicitlyUsedUnchecked();
int32_t offset = AssertedCast<int32_t>(tarr->byteOffset());
byteOffset = MConstant::New(alloc(), Int32Value(offset));
} else {
byteOffset = MTypedArrayByteOffset::New(alloc(), obj);
}
current->add(byteOffset);
return byteOffset;
}
AbortReasonOr<Ok> IonBuilder::jsop_getelem_typed(MDefinition* obj,
MDefinition* index,
Scalar::Type arrayType) {

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

@ -516,6 +516,10 @@ class IonBuilder : public MIRGenerator,
return length;
}
// Add an instruction to compute a typed array's byte offset to the current
// block.
MInstruction* addTypedArrayByteOffset(MDefinition* obj);
AbortReasonOr<Ok> improveThisTypesForCall();
MDefinition* getCallee();
@ -783,6 +787,7 @@ class IonBuilder : public MIRGenerator,
InliningResult inlineIsPossiblyWrappedTypedArray(CallInfo& callInfo);
InliningResult inlineTypedArrayLength(CallInfo& callInfo);
InliningResult inlinePossiblyWrappedTypedArrayLength(CallInfo& callInfo);
InliningResult inlineTypedArrayByteOffset(CallInfo& callInfo);
InliningResult inlineSetDisjointTypedElements(CallInfo& callInfo);
// TypedObject intrinsics and natives.

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

@ -2836,6 +2836,12 @@ void LIRGenerator::visitTypedArrayLength(MTypedArrayLength* ins) {
ins);
}
void LIRGenerator::visitTypedArrayByteOffset(MTypedArrayByteOffset* ins) {
MOZ_ASSERT(ins->object()->type() == MIRType::Object);
define(new (alloc()) LTypedArrayByteOffset(useRegisterAtStart(ins->object())),
ins);
}
void LIRGenerator::visitTypedArrayElements(MTypedArrayElements* ins) {
MOZ_ASSERT(ins->type() == MIRType::Elements);
define(new (alloc()) LTypedArrayElements(useRegisterAtStart(ins->object())),

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

@ -371,6 +371,8 @@ IonBuilder::InliningResult IonBuilder::inlineNativeCall(CallInfo& callInfo,
return inlinePossiblyWrappedTypedArrayLength(callInfo);
case InlinableNative::IntrinsicTypedArrayLength:
return inlineTypedArrayLength(callInfo);
case InlinableNative::IntrinsicTypedArrayByteOffset:
return inlineTypedArrayByteOffset(callInfo);
case InlinableNative::IntrinsicSetDisjointTypedElements:
return inlineSetDisjointTypedElements(callInfo);
@ -431,6 +433,18 @@ IonBuilder::InliningResult IonBuilder::inlineNativeGetter(CallInfo& callInfo,
return InliningStatus_Inlined;
}
// Try to optimize typed array byteOffsets.
if (TypedArrayObject::isOriginalByteOffsetGetter(native)) {
if (thisTypes->forAllClasses(constraints(), IsTypedArrayClass) !=
TemporaryTypeSet::ForAllResult::ALL_TRUE) {
return InliningStatus_NotInlined;
}
MInstruction* byteOffset = addTypedArrayByteOffset(thisArg);
current->push(byteOffset);
return InliningStatus_Inlined;
}
// Try to optimize RegExp getters.
RegExpFlag mask = NoFlags;
if (RegExpObject::isOriginalFlagGetter(native, &mask)) {
@ -3195,6 +3209,28 @@ IonBuilder::InliningResult IonBuilder::inlineTypedArrayLength(
return inlinePossiblyWrappedTypedArrayLength(callInfo);
}
IonBuilder::InliningResult IonBuilder::inlineTypedArrayByteOffset(
CallInfo& callInfo) {
MOZ_ASSERT(!callInfo.constructing());
MOZ_ASSERT(callInfo.argc() == 1);
if (callInfo.getArg(0)->type() != MIRType::Object) {
return InliningStatus_NotInlined;
}
if (getInlineReturnType() != MIRType::Int32) {
return InliningStatus_NotInlined;
}
if (!IsTypedArrayObject(constraints(), callInfo.getArg(0))) {
return InliningStatus_NotInlined;
}
MInstruction* byteOffset = addTypedArrayByteOffset(callInfo.getArg(0));
current->push(byteOffset);
callInfo.setImplicitlyUsedUnchecked();
return InliningStatus_Inlined;
}
IonBuilder::InliningResult IonBuilder::inlineSetDisjointTypedElements(
CallInfo& callInfo) {
MOZ_ASSERT(!callInfo.constructing());

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

@ -459,33 +459,6 @@ static bool MaybeCallable(CompilerConstraintList* constraints,
return types->maybeCallable(constraints);
}
/* static */ const char* AliasSet::Name(size_t flag) {
switch (flag) {
case 0:
return "ObjectFields";
case 1:
return "Element";
case 2:
return "UnboxedElement";
case 3:
return "DynamicSlot";
case 4:
return "FixedSlot";
case 5:
return "DOMProperty";
case 6:
return "FrameArgument";
case 7:
return "WasmGlobalVar";
case 8:
return "WasmHeap";
case 9:
return "TypedArrayLength";
default:
MOZ_CRASH("Unknown flag");
}
}
void MTest::cacheOperandMightEmulateUndefined(
CompilerConstraintList* constraints) {
MOZ_ASSERT(operandMightEmulateUndefined());

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

@ -332,21 +332,21 @@ class AliasSet {
public:
enum Flag {
None_ = 0,
ObjectFields = 1 << 0, // shape, class, slots, length etc.
Element = 1 << 1, // A Value member of obj->elements or
// a typed object.
UnboxedElement = 1 << 2, // An unboxed scalar or reference member of
// typed object or unboxed object.
DynamicSlot = 1 << 3, // A Value member of obj->slots.
FixedSlot = 1 << 4, // A Value member of obj->fixedSlots().
DOMProperty = 1 << 5, // A DOM property
FrameArgument = 1 << 6, // An argument kept on the stack frame
WasmGlobalVar = 1 << 7, // An asm.js/wasm private global var
WasmHeap = 1 << 8, // An asm.js/wasm heap load
WasmHeapMeta = 1 << 9, // The asm.js/wasm heap base pointer and
// bounds check limit, in Tls.
TypedArrayLength = 1 << 10, // A typed array's length
WasmGlobalCell = 1 << 11, // A wasm global cell
ObjectFields = 1 << 0, // shape, class, slots, length etc.
Element = 1 << 1, // A Value member of obj->elements or
// a typed object.
UnboxedElement = 1 << 2, // An unboxed scalar or reference member of
// typed object or unboxed object.
DynamicSlot = 1 << 3, // A Value member of obj->slots.
FixedSlot = 1 << 4, // A Value member of obj->fixedSlots().
DOMProperty = 1 << 5, // A DOM property
FrameArgument = 1 << 6, // An argument kept on the stack frame
WasmGlobalVar = 1 << 7, // An asm.js/wasm private global var
WasmHeap = 1 << 8, // An asm.js/wasm heap load
WasmHeapMeta = 1 << 9, // The asm.js/wasm heap base pointer and
// bounds check limit, in Tls.
TypedArrayLengthOrOffset = 1 << 10, // A typed array's length or byteOffset
WasmGlobalCell = 1 << 11, // A wasm global cell
Last = WasmGlobalCell,
Any = Last | (Last - 1),
@ -362,8 +362,6 @@ class AliasSet {
explicit AliasSet(uint32_t flags) : flags_(flags) {}
public:
static const char* Name(size_t flag);
inline bool isNone() const { return flags_ == None_; }
uint32_t flags() const { return flags_ & Any; }
inline bool isStore() const { return !!(flags_ & Store_); }
@ -7142,7 +7140,31 @@ class MTypedArrayLength : public MUnaryInstruction,
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::TypedArrayLength);
return AliasSet::Load(AliasSet::TypedArrayLengthOrOffset);
}
void computeRange(TempAllocator& alloc) override;
};
// Read the byteOffset of a typed array.
class MTypedArrayByteOffset : public MUnaryInstruction,
public SingleObjectPolicy::Data {
explicit MTypedArrayByteOffset(MDefinition* obj)
: MUnaryInstruction(classOpcode, obj) {
setResultType(MIRType::Int32);
setMovable();
}
public:
INSTRUCTION_HEADER(TypedArrayByteOffset)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, object))
bool congruentTo(const MDefinition* ins) const override {
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::TypedArrayLengthOrOffset);
}
void computeRange(TempAllocator& alloc) override;

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

@ -1755,6 +1755,10 @@ void MTypedArrayLength::computeRange(TempAllocator& alloc) {
setRange(Range::NewUInt32Range(alloc, 0, INT32_MAX));
}
void MTypedArrayByteOffset::computeRange(TempAllocator& alloc) {
setRange(Range::NewUInt32Range(alloc, 0, INT32_MAX));
}
void MStringLength::computeRange(TempAllocator& alloc) {
static_assert(JSString::MAX_LENGTH <= UINT32_MAX,
"NewUInt32Range requires a uint32 value");

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

@ -3833,6 +3833,19 @@ class LTypedArrayLength : public LInstructionHelper<1, 1, 0> {
const LAllocation* object() { return getOperand(0); }
};
// Read the byteOffset of a typed array.
class LTypedArrayByteOffset : public LInstructionHelper<1, 1, 0> {
public:
LIR_HEADER(TypedArrayByteOffset)
explicit LTypedArrayByteOffset(const LAllocation& obj)
: LInstructionHelper(classOpcode) {
setOperand(0, obj);
}
const LAllocation* object() { return getOperand(0); }
};
// Load a typed array's elements vector.
class LTypedArrayElements : public LInstructionHelper<1, 1, 0> {
public:

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

@ -2603,7 +2603,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
IntrinsicIsTypedArrayConstructor),
JS_FN("TypedArrayBuffer", intrinsic_TypedArrayBuffer, 1, 0),
JS_FN("TypedArrayByteOffset", intrinsic_TypedArrayByteOffset, 1, 0),
JS_INLINABLE_FN("TypedArrayByteOffset", intrinsic_TypedArrayByteOffset, 1,
0, IntrinsicTypedArrayByteOffset),
JS_FN("TypedArrayElementShift", intrinsic_TypedArrayElementShift, 1, 0),
JS_INLINABLE_FN("TypedArrayLength", intrinsic_TypedArrayLength, 1, 0,

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

@ -1452,6 +1452,12 @@ static bool TypedArray_lengthGetter(JSContext* cx, unsigned argc, Value* vp) {
return TypedArrayObject::Getter<TypedArrayObject::lengthValue>(cx, argc, vp);
}
static bool TypedArray_byteOffsetGetter(JSContext* cx, unsigned argc,
Value* vp) {
return TypedArrayObject::Getter<TypedArrayObject::byteOffsetValue>(cx, argc,
vp);
}
bool BufferGetterImpl(JSContext* cx, const CallArgs& args) {
MOZ_ASSERT(TypedArrayObject::is(args.thisv()));
Rooted<TypedArrayObject*> tarray(
@ -1506,8 +1512,7 @@ static bool TypedArray_toStringTagGetter(JSContext* cx, unsigned argc,
JS_PSG("buffer", TypedArray_bufferGetter, 0),
JS_PSG("byteLength",
TypedArrayObject::Getter<TypedArrayObject::byteLengthValue>, 0),
JS_PSG("byteOffset",
TypedArrayObject::Getter<TypedArrayObject::byteOffsetValue>, 0),
JS_PSG("byteOffset", TypedArray_byteOffsetGetter, 0),
JS_SYM_GET(toStringTag, TypedArray_toStringTagGetter, 0),
JS_PS_END};
@ -2031,6 +2036,10 @@ const Class TypedArrayObject::protoClasses[Scalar::MaxTypedArrayViewType] = {
return native == TypedArray_lengthGetter;
}
/* static */ bool TypedArrayObject::isOriginalByteOffsetGetter(Native native) {
return native == TypedArray_byteOffsetGetter;
}
bool js::IsTypedArrayConstructor(const JSObject* obj) {
#define CHECK_TYPED_ARRAY_CONSTRUCTOR(T, N) \
if (IsNativeFunction(obj, N##Array::class_constructor)) { \

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

@ -43,6 +43,9 @@ class TypedArrayObject : public ArrayBufferViewObject {
static constexpr int lengthOffset() {
return NativeObject::getFixedSlotOffset(LENGTH_SLOT);
}
static constexpr int byteOffsetOffset() {
return NativeObject::getFixedSlotOffset(BYTEOFFSET_SLOT);
}
static constexpr int dataOffset() {
return NativeObject::getPrivateDataOffset(DATA_SLOT);
}
@ -148,6 +151,8 @@ class TypedArrayObject : public ArrayBufferViewObject {
static bool isOriginalLengthGetter(Native native);
static bool isOriginalByteOffsetGetter(Native native);
static void finalize(FreeOp* fop, JSObject* obj);
static size_t objectMoved(JSObject* obj, JSObject* old);