зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1657285 - Part 3: Optimise IsTypedArrayConstructor in CacheIR and Warp. r=jandem
Add `IsTypedArrayConstructorResult` to CacheIR to test if a constructor is definitely a TypedArray constructor. The `IsTypedArrayConstructor` intrinsic returns `true` when the input is TypedArray constructor function. It allows the constructor to be from a different realm, but it doesn't unwraps wrappers. (So false-negatives are possible. This is okay because the function is only used to guard a fast-path.) Drive-by change: - Change `IsTypedArrayConstructor` to use `Scalar::Type` for its parameter. This function is only called from asm.js code which already passes a `Scalar::Type`. - Also change it to use the `JS_FOR_EACH_TYPED_ARRAY` macro used elsewhere in TypedArrayObject.cpp. Differential Revision: https://phabricator.services.mozilla.com/D85970
This commit is contained in:
Родитель
67568a0e4c
Коммит
2c1cb8b174
|
@ -6923,6 +6923,29 @@ AttachDecision CallIRGenerator::tryAttachIsTypedArray(HandleFunction callee,
|
|||
return AttachDecision::Attach;
|
||||
}
|
||||
|
||||
AttachDecision CallIRGenerator::tryAttachIsTypedArrayConstructor(
|
||||
HandleFunction callee) {
|
||||
// Self-hosted code calls this with a single object argument.
|
||||
MOZ_ASSERT(argc_ == 1);
|
||||
MOZ_ASSERT(args_[0].isObject());
|
||||
|
||||
// Initialize the input operand.
|
||||
Int32OperandId argcId(writer.setInputOperandId(0));
|
||||
|
||||
// Note: we don't need to call emitNativeCalleeGuard for intrinsics.
|
||||
|
||||
ValOperandId argId = writer.loadArgumentFixedSlot(ArgumentKind::Arg0, argc_);
|
||||
ObjOperandId objArgId = writer.guardToObject(argId);
|
||||
writer.isTypedArrayConstructorResult(objArgId);
|
||||
|
||||
// This stub does not need to be monitored because it always returns a bool.
|
||||
writer.returnFromIC();
|
||||
cacheIRStubKind_ = BaselineCacheIRStubKind::Regular;
|
||||
|
||||
trackAttached("IsTypedArrayConstructor");
|
||||
return AttachDecision::Attach;
|
||||
}
|
||||
|
||||
AttachDecision CallIRGenerator::tryAttachTypedArrayByteOffset(
|
||||
HandleFunction callee) {
|
||||
// Self-hosted code calls this with a single TypedArrayObject argument.
|
||||
|
@ -7866,6 +7889,8 @@ AttachDecision CallIRGenerator::tryAttachInlinableNative(
|
|||
return tryAttachIsTypedArray(callee, /* isPossiblyWrapped = */ false);
|
||||
case InlinableNative::IntrinsicIsPossiblyWrappedTypedArray:
|
||||
return tryAttachIsTypedArray(callee, /* isPossiblyWrapped = */ true);
|
||||
case InlinableNative::IntrinsicIsTypedArrayConstructor:
|
||||
return tryAttachIsTypedArrayConstructor(callee);
|
||||
case InlinableNative::IntrinsicTypedArrayByteOffset:
|
||||
return tryAttachTypedArrayByteOffset(callee);
|
||||
case InlinableNative::IntrinsicTypedArrayElementShift:
|
||||
|
|
|
@ -1668,6 +1668,7 @@ class MOZ_RAII CallIRGenerator : public IRGenerator {
|
|||
AttachDecision tryAttachMathMinMax(HandleFunction callee, bool isMax);
|
||||
AttachDecision tryAttachIsTypedArray(HandleFunction callee,
|
||||
bool isPossiblyWrapped);
|
||||
AttachDecision tryAttachIsTypedArrayConstructor(HandleFunction callee);
|
||||
AttachDecision tryAttachTypedArrayByteOffset(HandleFunction callee);
|
||||
AttachDecision tryAttachTypedArrayElementShift(HandleFunction callee);
|
||||
AttachDecision tryAttachTypedArrayLength(HandleFunction callee,
|
||||
|
|
|
@ -4038,6 +4038,18 @@ bool CacheIRCompiler::emitTypedArrayElementShiftResult(ObjOperandId objId) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CacheIRCompiler::emitIsTypedArrayConstructorResult(ObjOperandId objId) {
|
||||
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
|
||||
|
||||
AutoOutputRegister output(*this);
|
||||
AutoScratchRegisterMaybeOutput scratch(allocator, masm, output);
|
||||
Register obj = allocator.useRegister(masm, objId);
|
||||
|
||||
masm.setIsDefinitelyTypedArrayConstructor(obj, scratch);
|
||||
masm.tagValue(JSVAL_TYPE_BOOLEAN, scratch, output.valueReg());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CacheIRCompiler::emitGetNextMapSetEntryForIteratorResult(
|
||||
ObjOperandId iterId, ObjOperandId resultArrId, bool isMap) {
|
||||
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
|
||||
|
|
|
@ -962,6 +962,13 @@
|
|||
obj: ObjId
|
||||
isPossiblyWrapped: BoolImm
|
||||
|
||||
- name: IsTypedArrayConstructorResult
|
||||
shared: true
|
||||
transpile: true
|
||||
cost_estimate: 2
|
||||
args:
|
||||
obj: ObjId
|
||||
|
||||
- name: TypedArrayByteOffsetResult
|
||||
shared: true
|
||||
transpile: true
|
||||
|
|
|
@ -14511,6 +14511,14 @@ void CodeGenerator::visitInitHomeObject(LInitHomeObject* lir) {
|
|||
masm.storeValue(homeObject, addr);
|
||||
}
|
||||
|
||||
void CodeGenerator::visitIsTypedArrayConstructor(
|
||||
LIsTypedArrayConstructor* lir) {
|
||||
Register object = ToRegister(lir->object());
|
||||
Register output = ToRegister(lir->output());
|
||||
|
||||
masm.setIsDefinitelyTypedArrayConstructor(object, output);
|
||||
}
|
||||
|
||||
template <size_t NumDefs>
|
||||
void CodeGenerator::emitIonToWasmCallBase(LIonToWasmCallBase<NumDefs>* lir) {
|
||||
wasm::JitCallStackArgVector stackArgs;
|
||||
|
|
|
@ -5227,6 +5227,14 @@ void LIRGenerator::visitInitHomeObject(MInitHomeObject* ins) {
|
|||
add(lir, ins);
|
||||
}
|
||||
|
||||
void LIRGenerator::visitIsTypedArrayConstructor(MIsTypedArrayConstructor* ins) {
|
||||
MDefinition* object = ins->object();
|
||||
MOZ_ASSERT(object->type() == MIRType::Object);
|
||||
|
||||
auto* lir = new (alloc()) LIsTypedArrayConstructor(useRegister(object));
|
||||
define(lir, ins);
|
||||
}
|
||||
|
||||
void LIRGenerator::visitConstant(MConstant* ins) {
|
||||
if (!IsFloatingPointType(ins->type()) && ins->canEmitAtUses()) {
|
||||
emitAtUses(ins);
|
||||
|
|
|
@ -11654,6 +11654,24 @@ class MInitHomeObject : public MBinaryInstruction,
|
|||
}
|
||||
};
|
||||
|
||||
// Return true if the object is definitely a TypedArray constructor, but not
|
||||
// necessarily from the currently active realm. Return false if the object is
|
||||
// not a TypedArray constructor or if it's a wrapper.
|
||||
class MIsTypedArrayConstructor : public MUnaryInstruction,
|
||||
public SingleObjectPolicy::Data {
|
||||
explicit MIsTypedArrayConstructor(MDefinition* object)
|
||||
: MUnaryInstruction(classOpcode, object) {
|
||||
setResultType(MIRType::Boolean);
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(IsTypedArrayConstructor)
|
||||
TRIVIAL_NEW_WRAPPERS
|
||||
NAMED_OPERANDS((0, object))
|
||||
|
||||
AliasSet getAliasSet() const override { return AliasSet::None(); }
|
||||
};
|
||||
|
||||
// Flips the input's sign bit, independently of the rest of the number's
|
||||
// payload. Note this is different from multiplying by minus-one, which has
|
||||
// side-effects for e.g. NaNs.
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "vm/ArrayBufferViewObject.h"
|
||||
#include "vm/FunctionFlags.h" // js::FunctionFlags
|
||||
#include "vm/TraceLogging.h"
|
||||
#include "vm/TypedArrayObject.h"
|
||||
|
||||
#include "gc/Nursery-inl.h"
|
||||
#include "jit/shared/Lowering-shared-inl.h"
|
||||
|
@ -1836,6 +1837,39 @@ void MacroAssembler::setIsCrossRealmArrayConstructor(Register obj,
|
|||
bind(&done);
|
||||
}
|
||||
|
||||
void MacroAssembler::setIsDefinitelyTypedArrayConstructor(Register obj,
|
||||
Register output) {
|
||||
Label isFalse, isTrue, done;
|
||||
|
||||
// The object must be a function. (Wrappers are not supported.)
|
||||
branchTestObjClass(Assembler::NotEqual, obj, &JSFunction::class_, output, obj,
|
||||
&isFalse);
|
||||
|
||||
// Load the native into |output|.
|
||||
loadPtr(Address(obj, JSFunction::offsetOfNativeOrEnv()), output);
|
||||
|
||||
auto branchIsTypedArrayCtor = [&](Scalar::Type type) {
|
||||
// The function must be a TypedArrayConstructor native (from any realm).
|
||||
JSNative constructor = TypedArrayConstructorNative(type);
|
||||
branchPtr(Assembler::Equal, output, ImmPtr(constructor), &isTrue);
|
||||
};
|
||||
|
||||
#define TYPED_ARRAY_CONSTRUCTOR_NATIVE(T, N) branchIsTypedArrayCtor(Scalar::N);
|
||||
JS_FOR_EACH_TYPED_ARRAY(TYPED_ARRAY_CONSTRUCTOR_NATIVE)
|
||||
#undef TYPED_ARRAY_CONSTRUCTOR_NATIVE
|
||||
|
||||
// Falls through to the false case.
|
||||
|
||||
bind(&isFalse);
|
||||
move32(Imm32(0), output);
|
||||
jump(&done);
|
||||
|
||||
bind(&isTrue);
|
||||
move32(Imm32(1), output);
|
||||
|
||||
bind(&done);
|
||||
}
|
||||
|
||||
void MacroAssembler::guardGroupHasUnanalyzedNewScript(Register group,
|
||||
Register scratch,
|
||||
Label* fail) {
|
||||
|
|
|
@ -3700,6 +3700,8 @@ class MacroAssembler : public MacroAssemblerSpecific {
|
|||
|
||||
void setIsCrossRealmArrayConstructor(Register obj, Register output);
|
||||
|
||||
void setIsDefinitelyTypedArrayConstructor(Register obj, Register output);
|
||||
|
||||
private:
|
||||
void isCallableOrConstructor(bool isCallable, Register obj, Register output,
|
||||
Label* isProxy);
|
||||
|
|
|
@ -2011,6 +2011,17 @@ bool WarpCacheIRTranspiler::emitTypedArrayElementShiftResult(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool WarpCacheIRTranspiler::emitIsTypedArrayConstructorResult(
|
||||
ObjOperandId objId) {
|
||||
MDefinition* obj = getOperand(objId);
|
||||
|
||||
auto* ins = MIsTypedArrayConstructor::New(alloc(), obj);
|
||||
add(ins);
|
||||
|
||||
pushResult(ins);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WarpCacheIRTranspiler::emitGetNextMapSetEntryForIteratorResult(
|
||||
ObjOperandId iterId, ObjOperandId resultArrId, bool isMap) {
|
||||
MDefinition* iter = getOperand(iterId);
|
||||
|
|
|
@ -7754,6 +7754,18 @@ class LInitHomeObject : public LInstructionHelper<0, 1 + BOX_PIECES, 0> {
|
|||
const LAllocation* function() { return getOperand(0); }
|
||||
};
|
||||
|
||||
class LIsTypedArrayConstructor : public LInstructionHelper<1, 1, 0> {
|
||||
public:
|
||||
LIR_HEADER(IsTypedArrayConstructor)
|
||||
|
||||
explicit LIsTypedArrayConstructor(const LAllocation& object)
|
||||
: LInstructionHelper(classOpcode) {
|
||||
setOperand(0, object);
|
||||
}
|
||||
|
||||
const LAllocation* object() { return getOperand(0); }
|
||||
};
|
||||
|
||||
template <size_t NumDefs>
|
||||
class LIonToWasmCallBase : public LVariadicInstruction<NumDefs, 2> {
|
||||
using Base = LVariadicInstruction<NumDefs, 2>;
|
||||
|
|
|
@ -2254,33 +2254,18 @@ bool js::IsTypedArrayConstructor(const JSObject* obj) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool js::IsTypedArrayConstructor(HandleValue v, uint32_t type) {
|
||||
switch (type) {
|
||||
case Scalar::Int8:
|
||||
return IsNativeFunction(v, Int8Array::class_constructor);
|
||||
case Scalar::Uint8:
|
||||
return IsNativeFunction(v, Uint8Array::class_constructor);
|
||||
case Scalar::Int16:
|
||||
return IsNativeFunction(v, Int16Array::class_constructor);
|
||||
case Scalar::Uint16:
|
||||
return IsNativeFunction(v, Uint16Array::class_constructor);
|
||||
case Scalar::Int32:
|
||||
return IsNativeFunction(v, Int32Array::class_constructor);
|
||||
case Scalar::Uint32:
|
||||
return IsNativeFunction(v, Uint32Array::class_constructor);
|
||||
case Scalar::BigInt64:
|
||||
return IsNativeFunction(v, BigInt64Array::class_constructor);
|
||||
case Scalar::BigUint64:
|
||||
return IsNativeFunction(v, BigUint64Array::class_constructor);
|
||||
case Scalar::Float32:
|
||||
return IsNativeFunction(v, Float32Array::class_constructor);
|
||||
case Scalar::Float64:
|
||||
return IsNativeFunction(v, Float64Array::class_constructor);
|
||||
case Scalar::Uint8Clamped:
|
||||
return IsNativeFunction(v, Uint8ClampedArray::class_constructor);
|
||||
case Scalar::MaxTypedArrayViewType:
|
||||
break;
|
||||
bool js::IsTypedArrayConstructor(HandleValue v, Scalar::Type type) {
|
||||
return IsNativeFunction(v, TypedArrayConstructorNative(type));
|
||||
}
|
||||
|
||||
JSNative js::TypedArrayConstructorNative(Scalar::Type type) {
|
||||
#define TYPED_ARRAY_CONSTRUCTOR_NATIVE(T, N) \
|
||||
if (type == Scalar::N) { \
|
||||
return N##Array::class_constructor; \
|
||||
}
|
||||
JS_FOR_EACH_TYPED_ARRAY(TYPED_ARRAY_CONSTRUCTOR_NATIVE)
|
||||
#undef TYPED_ARRAY_CONSTRUCTOR_NATIVE
|
||||
|
||||
MOZ_CRASH("unexpected typed array type");
|
||||
}
|
||||
|
||||
|
|
|
@ -222,7 +222,9 @@ inline Scalar::Type GetTypedArrayClassType(const JSClass* clasp) {
|
|||
|
||||
bool IsTypedArrayConstructor(const JSObject* obj);
|
||||
|
||||
bool IsTypedArrayConstructor(HandleValue v, uint32_t type);
|
||||
bool IsTypedArrayConstructor(HandleValue v, Scalar::Type type);
|
||||
|
||||
JSNative TypedArrayConstructorNative(Scalar::Type type);
|
||||
|
||||
// In WebIDL terminology, a BufferSource is either an ArrayBuffer or a typed
|
||||
// array view. In either case, extract the dataPointer/byteLength.
|
||||
|
|
Загрузка…
Ссылка в новой задаче