Commit c0359728 authored by Steve Fink's avatar Steve Fink
Browse files

Bug 1686532 - Add dom::TypedArray_base::Reset() as a signal to the hazard...

Bug 1686532 - Add dom::TypedArray_base::Reset() as a signal to the hazard analysis that no invalidatable data is being held onto. r=jonco, a=RyanVM

Differential Revision: https://phabricator.services.mozilla.com/D100429
parent bbd12050
......@@ -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;
// 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;
}
if (m) {
const [, type, namespace,, classname] = m;
// 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)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment