зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1651037 part 5 - Change some MIR instructions to prepare for MNurseryObject use. r=iain,evilpie
WrappedFunction only needs the JSFunction* for natives. This way we can still optimize scripted calls to nursery-allocated functions. Depends on D82670 Differential Revision: https://phabricator.services.mozilla.com/D82671
This commit is contained in:
Родитель
db18f35257
Коммит
e81bd0d0ab
|
@ -5098,7 +5098,7 @@ void CodeGenerator::visitCallNative(LCallNative* call) {
|
|||
// Push a Value containing the callee object: natives are allowed to access
|
||||
// their callee before setting the return value. The StackPointer is moved
|
||||
// to &vp[0].
|
||||
masm.Push(ObjectValue(*target->rawJSFunction()));
|
||||
masm.Push(ObjectValue(*target->rawNativeJSFunction()));
|
||||
|
||||
// Preload arguments into registers.
|
||||
masm.loadJSContext(argContextReg);
|
||||
|
@ -5108,7 +5108,7 @@ void CodeGenerator::visitCallNative(LCallNative* call) {
|
|||
masm.Push(argUintNReg);
|
||||
|
||||
if (call->mir()->maybeCrossRealm()) {
|
||||
masm.movePtr(ImmGCPtr(target->rawJSFunction()), tempReg);
|
||||
masm.movePtr(ImmGCPtr(target->rawNativeJSFunction()), tempReg);
|
||||
masm.switchToObjectRealm(tempReg, tempReg);
|
||||
}
|
||||
|
||||
|
@ -5247,7 +5247,7 @@ void CodeGenerator::visitCallDOMNative(LCallDOMNative* call) {
|
|||
// Push a Value containing the callee object: natives are allowed to access
|
||||
// their callee before setting the return value. After this the StackPointer
|
||||
// points to &vp[0].
|
||||
masm.Push(ObjectValue(*target->rawJSFunction()));
|
||||
masm.Push(ObjectValue(*target->rawNativeJSFunction()));
|
||||
|
||||
// Now compute the argv value. Since StackPointer is pointing to &vp[0] and
|
||||
// argv is &vp[2] we just need to add 2*sizeof(Value) to the current
|
||||
|
@ -5277,7 +5277,7 @@ void CodeGenerator::visitCallDOMNative(LCallDOMNative* call) {
|
|||
|
||||
if (call->mir()->maybeCrossRealm()) {
|
||||
// We use argJSContext as scratch register here.
|
||||
masm.movePtr(ImmGCPtr(target->rawJSFunction()), argJSContext);
|
||||
masm.movePtr(ImmGCPtr(target->rawNativeJSFunction()), argJSContext);
|
||||
masm.switchToObjectRealm(argJSContext, argJSContext);
|
||||
}
|
||||
|
||||
|
|
|
@ -6263,7 +6263,7 @@ AbortReasonOr<Ok> IonBuilder::makeCall(const Maybe<CallTargets>& targets,
|
|||
|
||||
if (call->isCallDOMNative()) {
|
||||
return pushDOMTypeBarrier(call, types,
|
||||
call->getSingleTarget()->rawJSFunction());
|
||||
call->getSingleTarget()->rawNativeJSFunction());
|
||||
}
|
||||
|
||||
return pushTypeBarrier(call, types, BarrierKind::TypeSet);
|
||||
|
|
|
@ -1481,21 +1481,28 @@ bool MParameter::congruentTo(const MDefinition* ins) const {
|
|||
}
|
||||
|
||||
WrappedFunction::WrappedFunction(JSFunction* fun)
|
||||
: fun_(fun), nargs_(fun->nargs()), flags_(fun->flags()) {}
|
||||
: nativeFun_(fun->isNativeWithoutJitEntry() ? fun : nullptr),
|
||||
nargs_(fun->nargs()),
|
||||
flags_(fun->flags()) {
|
||||
MOZ_ASSERT(!JitOptions.warpBuilder);
|
||||
}
|
||||
|
||||
WrappedFunction::WrappedFunction(JSFunction* fun, uint16_t nargs,
|
||||
WrappedFunction::WrappedFunction(JSFunction* nativeFun, uint16_t nargs,
|
||||
FunctionFlags flags)
|
||||
: fun_(fun), nargs_(nargs), flags_(flags) {
|
||||
: nativeFun_(nativeFun), nargs_(nargs), flags_(flags) {
|
||||
MOZ_ASSERT_IF(nativeFun, isNativeWithoutJitEntry());
|
||||
|
||||
#ifdef DEBUG
|
||||
// If we are not running off-main thread we can assert that the
|
||||
// metadata is consistent.
|
||||
if (!CanUseExtraThreads()) {
|
||||
MOZ_ASSERT(fun->nargs() == nargs);
|
||||
if (!CanUseExtraThreads() && nativeFun) {
|
||||
MOZ_ASSERT(nativeFun->nargs() == nargs);
|
||||
|
||||
MOZ_ASSERT(fun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry());
|
||||
MOZ_ASSERT(fun->hasJitEntry() == hasJitEntry());
|
||||
MOZ_ASSERT(fun->isConstructor() == isConstructor());
|
||||
MOZ_ASSERT(fun->isClassConstructor() == isClassConstructor());
|
||||
MOZ_ASSERT(nativeFun->isNativeWithoutJitEntry() ==
|
||||
isNativeWithoutJitEntry());
|
||||
MOZ_ASSERT(nativeFun->hasJitEntry() == hasJitEntry());
|
||||
MOZ_ASSERT(nativeFun->isConstructor() == isConstructor());
|
||||
MOZ_ASSERT(nativeFun->isClassConstructor() == isClassConstructor());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -5847,18 +5854,25 @@ MDefinition* MGuardNullOrUndefined::foldsTo(TempAllocator& alloc) {
|
|||
}
|
||||
|
||||
MDefinition* MGuardObjectIdentity::foldsTo(TempAllocator& alloc) {
|
||||
if (!object()->isConstant()) {
|
||||
return this;
|
||||
if (object()->isConstant() && expected()->isConstant()) {
|
||||
JSObject* obj = &object()->toConstant()->toObject();
|
||||
JSObject* other = &expected()->toConstant()->toObject();
|
||||
if (!bailOnEquality()) {
|
||||
if (obj == other) {
|
||||
return object();
|
||||
}
|
||||
} else {
|
||||
if (obj != other) {
|
||||
return object();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSObject* obj = &object()->toConstant()->toObject();
|
||||
JSObject* other = &expected()->toConstant()->toObject();
|
||||
if (!bailOnEquality()) {
|
||||
if (obj == other) {
|
||||
return object();
|
||||
}
|
||||
} else {
|
||||
if (obj != other) {
|
||||
if (!bailOnEquality() && object()->isNurseryObject() &&
|
||||
expected()->isNurseryObject()) {
|
||||
uint32_t objIndex = object()->toNurseryObject()->nurseryIndex();
|
||||
uint32_t otherIndex = expected()->toNurseryObject()->nurseryIndex();
|
||||
if (objIndex == otherIndex) {
|
||||
return object();
|
||||
}
|
||||
}
|
||||
|
@ -5867,7 +5881,7 @@ MDefinition* MGuardObjectIdentity::foldsTo(TempAllocator& alloc) {
|
|||
}
|
||||
|
||||
MDefinition* MGuardSpecificFunction::foldsTo(TempAllocator& alloc) {
|
||||
if (function()->isConstant()) {
|
||||
if (function()->isConstant() && expected()->isConstant()) {
|
||||
JSObject* fun = &function()->toConstant()->toObject();
|
||||
JSObject* other = &expected()->toConstant()->toObject();
|
||||
if (fun == other) {
|
||||
|
@ -5875,6 +5889,14 @@ MDefinition* MGuardSpecificFunction::foldsTo(TempAllocator& alloc) {
|
|||
}
|
||||
}
|
||||
|
||||
if (function()->isNurseryObject() && expected()->isNurseryObject()) {
|
||||
uint32_t funIndex = function()->toNurseryObject()->nurseryIndex();
|
||||
uint32_t otherIndex = expected()->toNurseryObject()->nurseryIndex();
|
||||
if (funIndex == otherIndex) {
|
||||
return function();
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -2606,18 +2606,19 @@ class MInitElemGetterSetter
|
|||
NAMED_OPERANDS((0, object), (1, idValue), (2, value))
|
||||
};
|
||||
|
||||
// WrappedFunction wraps a JSFunction so it can safely be used off-thread.
|
||||
// In particular, a function's flags can be modified on the main thread as
|
||||
// functions are relazified and delazified, so we must be careful not to access
|
||||
// these flags off-thread.
|
||||
// WrappedFunction stores information about a function that can safely be used
|
||||
// off-thread. In particular, a function's flags can be modified on the main
|
||||
// thread as functions are relazified and delazified, so we must be careful not
|
||||
// to access these flags off-thread.
|
||||
class WrappedFunction : public TempObject {
|
||||
CompilerFunction fun_;
|
||||
// If this is a native function without a JitEntry, the JSFunction*.
|
||||
CompilerFunction nativeFun_;
|
||||
uint16_t nargs_;
|
||||
js::FunctionFlags flags_;
|
||||
|
||||
public:
|
||||
explicit WrappedFunction(JSFunction* fun);
|
||||
WrappedFunction(JSFunction* fun, uint16_t nargs, FunctionFlags flags);
|
||||
WrappedFunction(JSFunction* nativeFun, uint16_t nargs, FunctionFlags flags);
|
||||
|
||||
// Note: When adding new accessors be sure to add consistency asserts
|
||||
// to the constructor.
|
||||
|
@ -2634,19 +2635,24 @@ class WrappedFunction : public TempObject {
|
|||
// These fields never change, they can be accessed off-main thread.
|
||||
JSNative native() const {
|
||||
MOZ_ASSERT(isNativeWithoutJitEntry());
|
||||
return fun_->nativeUnchecked();
|
||||
return nativeFun_->nativeUnchecked();
|
||||
}
|
||||
bool hasJitInfo() const {
|
||||
return flags_.isBuiltinNative() && fun_->jitInfoUnchecked();
|
||||
return flags_.isBuiltinNative() && nativeFun_->jitInfoUnchecked();
|
||||
}
|
||||
const JSJitInfo* jitInfo() const {
|
||||
MOZ_ASSERT(hasJitInfo());
|
||||
return fun_->jitInfoUnchecked();
|
||||
return nativeFun_->jitInfoUnchecked();
|
||||
}
|
||||
|
||||
JSFunction* rawJSFunction() const { return fun_; }
|
||||
JSFunction* rawNativeJSFunction() const { return nativeFun_; }
|
||||
|
||||
bool appendRoots(MRootList& roots) const { return roots.append(fun_); }
|
||||
bool appendRoots(MRootList& roots) const {
|
||||
if (nativeFun_) {
|
||||
return roots.append(nativeFun_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class MCall : public MVariadicInstruction, public CallPolicy::Data {
|
||||
|
@ -9238,7 +9244,7 @@ class MGuardObjectIdentity : public MBinaryInstruction,
|
|||
bool bailOnEquality)
|
||||
: MBinaryInstruction(classOpcode, obj, expected),
|
||||
bailOnEquality_(bailOnEquality) {
|
||||
MOZ_ASSERT(expected->isConstant());
|
||||
MOZ_ASSERT(expected->isConstant() || expected->isNurseryObject());
|
||||
setGuard();
|
||||
setMovable();
|
||||
setResultType(MIRType::Object);
|
||||
|
@ -9275,7 +9281,7 @@ class MGuardSpecificFunction : public MBinaryInstruction,
|
|||
: MBinaryInstruction(classOpcode, obj, expected),
|
||||
nargs_(nargs),
|
||||
flags_(flags) {
|
||||
MOZ_ASSERT(expected->isConstant());
|
||||
MOZ_ASSERT(expected->isConstant() || expected->isNurseryObject());
|
||||
setGuard();
|
||||
setMovable();
|
||||
setResultType(MIRType::Object);
|
||||
|
|
|
@ -1643,15 +1643,26 @@ bool WarpCacheIRTranspiler::emitCallFunction(ObjOperandId calleeId,
|
|||
WrappedFunction* wrappedTarget = nullptr;
|
||||
if (callee->isGuardSpecificFunction()) {
|
||||
auto* guard = callee->toGuardSpecificFunction();
|
||||
JSFunction* target =
|
||||
&guard->expected()->toConstant()->toObject().as<JSFunction>();
|
||||
|
||||
wrappedTarget =
|
||||
new (alloc()) WrappedFunction(target, guard->nargs(), guard->flags());
|
||||
MDefinition* expectedDef = guard->expected();
|
||||
MOZ_ASSERT(expectedDef->isConstant() || expectedDef->isNurseryObject());
|
||||
|
||||
MOZ_ASSERT_IF(kind == CallKind::Native,
|
||||
wrappedTarget->isNativeWithoutJitEntry());
|
||||
MOZ_ASSERT_IF(kind == CallKind::Scripted, wrappedTarget->hasJitEntry());
|
||||
// If this is a native without a JitEntry, WrappedFunction needs to know the
|
||||
// target JSFunction.
|
||||
// TODO: support nursery-allocated natives with WrappedFunction, maybe by
|
||||
// storing the JSNative in the Baseline stub like flags/nargs.
|
||||
bool isNative = guard->flags().isNativeWithoutJitEntry();
|
||||
if (!isNative || expectedDef->isConstant()) {
|
||||
JSFunction* nativeTarget = nullptr;
|
||||
if (isNative) {
|
||||
nativeTarget = &expectedDef->toConstant()->toObject().as<JSFunction>();
|
||||
}
|
||||
wrappedTarget = new (alloc())
|
||||
WrappedFunction(nativeTarget, guard->nargs(), guard->flags());
|
||||
MOZ_ASSERT_IF(kind == CallKind::Native,
|
||||
wrappedTarget->isNativeWithoutJitEntry());
|
||||
MOZ_ASSERT_IF(kind == CallKind::Scripted, wrappedTarget->hasJitEntry());
|
||||
}
|
||||
}
|
||||
|
||||
bool needsThisCheck = false;
|
||||
|
|
Загрузка…
Ссылка в новой задаче