зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1686532 - Add dom::TypedArray_base::Reset() as a signal to the hazard analysis that no invalidatable data is being held onto r=jonco
Differential Revision: https://phabricator.services.mozilla.com/D100429
This commit is contained in:
Родитель
a75149f6b8
Коммит
4bf3434c15
|
@ -45,10 +45,7 @@ struct TypedArray_base : public SpiderMonkeyInterfaceObjectStorage,
|
|||
mLength(aOther.mLength),
|
||||
mShared(aOther.mShared),
|
||||
mComputed(aOther.mComputed) {
|
||||
aOther.mData = nullptr;
|
||||
aOther.mLength = 0;
|
||||
aOther.mShared = false;
|
||||
aOther.mComputed = false;
|
||||
aOther.Reset();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -139,6 +136,16 @@ struct TypedArray_base : public SpiderMonkeyInterfaceObjectStorage,
|
|||
mComputed = true;
|
||||
}
|
||||
|
||||
inline void Reset() {
|
||||
// This method mostly exists to inform the GC rooting hazard analysis that
|
||||
// the variable can be considered dead, at least until you do anything else
|
||||
// with it.
|
||||
mData = nullptr;
|
||||
mLength = 0;
|
||||
mShared = false;
|
||||
mComputed = false;
|
||||
}
|
||||
|
||||
private:
|
||||
TypedArray_base(const TypedArray_base&) = delete;
|
||||
};
|
||||
|
|
|
@ -182,11 +182,15 @@ function edgeUsesVariable(edge, variable, body)
|
|||
switch (edge.Kind) {
|
||||
|
||||
case "Assign": {
|
||||
// Detect `Return := nullptr`.
|
||||
if (isReturningImmobileValue(edge, variable))
|
||||
return 0;
|
||||
const [lhs, rhs] = edge.Exp;
|
||||
// Detect `lhs := ...variable...`
|
||||
if (expressionUsesVariable(rhs, variable))
|
||||
return src;
|
||||
// Detect `...variable... := rhs` but not `variable := rhs`. The latter
|
||||
// overwrites the previous value of `variable` without using it.
|
||||
if (expressionUsesVariable(lhs, variable) && !expressionIsVariable(lhs, variable))
|
||||
return src;
|
||||
return 0;
|
||||
|
@ -276,6 +280,16 @@ function expressionIsVariable(exp, variable)
|
|||
return exp.Kind == "Var" && sameVariable(exp.Variable, variable);
|
||||
}
|
||||
|
||||
function expressionIsMethodOnVariable(exp, variable)
|
||||
{
|
||||
// This might be calling a method on a base class, in which case exp will
|
||||
// be an unnamed field of the variable instead of the variable itself.
|
||||
while (exp.Kind == "Fld" && exp.Field.Name[0].startsWith("field:"))
|
||||
exp = exp.Exp[0];
|
||||
|
||||
return exp.Kind == "Var" && sameVariable(exp.Variable, variable);
|
||||
}
|
||||
|
||||
// Return whether the edge terminates the live range of a variable's value when
|
||||
// searching in reverse through the CFG, by setting it to some new value.
|
||||
// Examples of killing 'obj's live range:
|
||||
|
@ -453,33 +467,32 @@ function edgeInvalidatesVariable(edge, variable, body)
|
|||
if (edge.Type.Kind == 'Function' &&
|
||||
edge.Type.TypeFunctionCSU &&
|
||||
edge.PEdgeCallInstance &&
|
||||
edge.PEdgeCallInstance.Exp.Kind == 'Var' &&
|
||||
expressionIsVariable(edge.PEdgeCallInstance.Exp, variable))
|
||||
do {
|
||||
expressionIsMethodOnVariable(edge.PEdgeCallInstance.Exp, variable))
|
||||
{
|
||||
const typeName = edge.Type.TypeFunctionCSU.Type.Name;
|
||||
const m = typeName.match(/^(((\w|::)+?)(\w+))</);
|
||||
if (!m)
|
||||
break;
|
||||
const [, type, namespace,, classname] = m;
|
||||
if (m) {
|
||||
const [, type, namespace,, classname] = m;
|
||||
|
||||
// special-case: the initial constructor that doesn't provide a value.
|
||||
// Useful for things like Maybe<T>.
|
||||
if (callee.Kind == 'Var' &&
|
||||
typesWithSafeConstructors.has(type) &&
|
||||
callee.Variable.Name[0].includes(`${namespace}${classname}<T>::${classname}()`))
|
||||
{
|
||||
return true;
|
||||
// special-case: the initial constructor that doesn't provide a value.
|
||||
// Useful for things like Maybe<T>.
|
||||
const ctorName = `${namespace}${classname}<T>::${classname}()`;
|
||||
if (callee.Kind == 'Var' &&
|
||||
typesWithSafeConstructors.has(type) &&
|
||||
callee.Variable.Name[0].includes(ctorName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// special-case: UniquePtr::reset() and similar.
|
||||
if (callee.Kind == 'Var' &&
|
||||
type in resetterMethods &&
|
||||
resetterMethods[type].has(callee.Variable.Name[1]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// special-case: UniquePtr::reset() and similar.
|
||||
if (callee.Kind == 'Var' &&
|
||||
type in resetterMethods &&
|
||||
resetterMethods[type].has(callee.Variable.Name[1]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} while(0);
|
||||
}
|
||||
|
||||
// special-case: passing UniquePtr<T> by value.
|
||||
if (edge.Type.Kind == 'Function' &&
|
||||
|
|
|
@ -31,6 +31,7 @@ var resetterMethods = {
|
|||
'mozilla::UniquePtr': new Set(["reset"]),
|
||||
'js::UniquePtr': new Set(["reset"]),
|
||||
'mozilla::dom::Nullable': new Set(["SetNull"]),
|
||||
'mozilla::dom::TypedArray_base': new Set(["Reset"]),
|
||||
};
|
||||
|
||||
function indirectCallCannotGC(fullCaller, fullVariable)
|
||||
|
|
Загрузка…
Ссылка в новой задаче