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:
Jan de Mooij 2020-07-09 07:02:25 +00:00
Родитель db18f35257
Коммит e81bd0d0ab
5 изменённых файлов: 84 добавлений и 45 удалений

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

@ -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;