зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1526403 - Part 3: Add inlining support for TypedArray "byteOffset" getter. r=jandem
This commit is contained in:
Родитель
d0a6de319b
Коммит
249b82f253
|
@ -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);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче