mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-22 02:09:28 +00:00
Bug 868715 part 7. Add tracing to dictionaries. r=peterv
This commit is contained in:
parent
ac6b11ed0d
commit
79374d2426
@ -476,77 +476,6 @@ private:
|
||||
double mMsecSinceEpoch;
|
||||
};
|
||||
|
||||
class NonNullLazyRootedObject : public Maybe<JS::Rooted<JSObject*> >
|
||||
{
|
||||
public:
|
||||
operator JSObject&() const
|
||||
{
|
||||
MOZ_ASSERT(!empty() && ref(), "Can not alias null.");
|
||||
return *ref();
|
||||
}
|
||||
|
||||
operator JS::Rooted<JSObject*>&()
|
||||
{
|
||||
// Assert if we're empty, on purpose
|
||||
return ref();
|
||||
}
|
||||
|
||||
JSObject** Slot() // To make us look like a NonNull
|
||||
{
|
||||
// Assert if we're empty, on purpose
|
||||
return ref().address();
|
||||
}
|
||||
};
|
||||
|
||||
class LazyRootedObject : public Maybe<JS::Rooted<JSObject*> >
|
||||
{
|
||||
public:
|
||||
operator JSObject*() const
|
||||
{
|
||||
return empty() ? static_cast<JSObject*>(nullptr) : ref();
|
||||
}
|
||||
|
||||
operator JS::Rooted<JSObject*>&()
|
||||
{
|
||||
// Assert if we're empty, on purpose
|
||||
return ref();
|
||||
}
|
||||
|
||||
JSObject** operator&()
|
||||
{
|
||||
// Assert if we're empty, on purpose
|
||||
return ref().address();
|
||||
}
|
||||
};
|
||||
|
||||
class LazyRootedValue : public Maybe<JS::Rooted<JS::Value> >
|
||||
{
|
||||
public:
|
||||
operator JS::Value() const
|
||||
{
|
||||
// Assert if we're empty, on purpose
|
||||
return ref();
|
||||
}
|
||||
|
||||
operator JS::Rooted<JS::Value>& ()
|
||||
{
|
||||
// Assert if we're empty, on purpose
|
||||
return ref();
|
||||
}
|
||||
|
||||
operator JS::Handle<JS::Value>()
|
||||
{
|
||||
// Assert if we're empty, on purpose
|
||||
return ref();
|
||||
}
|
||||
|
||||
JS::Value* operator&()
|
||||
{
|
||||
// Assert if we're empty, on purpose
|
||||
return ref().address();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -1353,13 +1353,6 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
T** Slot() {
|
||||
#ifdef DEBUG
|
||||
inited = true;
|
||||
#endif
|
||||
return &ptr;
|
||||
}
|
||||
|
||||
T* Ptr() {
|
||||
MOZ_ASSERT(inited);
|
||||
MOZ_ASSERT(ptr, "NonNull<T> was set to null");
|
||||
@ -1737,6 +1730,54 @@ private:
|
||||
SequenceType mSequenceType;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class MOZ_STACK_CLASS DictionaryRooter : JS::CustomAutoRooter
|
||||
{
|
||||
public:
|
||||
explicit DictionaryRooter(JSContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
|
||||
mDictionaryType(eNone)
|
||||
{
|
||||
}
|
||||
|
||||
void SetDictionary(T* aDictionary)
|
||||
{
|
||||
mDictionary = aDictionary;
|
||||
mDictionaryType = eDictionary;
|
||||
}
|
||||
|
||||
void SetDictionary(Nullable<T>* aDictionary)
|
||||
{
|
||||
mNullableDictionary = aDictionary;
|
||||
mDictionaryType = eNullableDictionary;
|
||||
}
|
||||
|
||||
private:
|
||||
enum DictionaryType {
|
||||
eDictionary,
|
||||
eNullableDictionary,
|
||||
eNone
|
||||
};
|
||||
|
||||
virtual void trace(JSTracer *trc) MOZ_OVERRIDE {
|
||||
if (mDictionaryType == eDictionary) {
|
||||
mDictionary->TraceDictionary(trc);
|
||||
} else {
|
||||
MOZ_ASSERT(mDictionaryType == eNullableDictionary);
|
||||
if (!mNullableDictionary->IsNull()) {
|
||||
mNullableDictionary->Value().TraceDictionary(trc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
union {
|
||||
T* mDictionary;
|
||||
Nullable<T>* mNullableDictionary;
|
||||
};
|
||||
|
||||
DictionaryType mDictionaryType;
|
||||
};
|
||||
|
||||
inline bool
|
||||
IdEquals(jsid id, const char* string)
|
||||
{
|
||||
|
@ -2618,35 +2618,12 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
|
||||
# A helper function for converting things that look like a JSObject*.
|
||||
def handleJSObjectType(type, isMember, failureCode):
|
||||
if isMember == "Dictionary":
|
||||
if type.nullable():
|
||||
declType = CGGeneric("LazyRootedObject")
|
||||
else:
|
||||
declType = CGGeneric("NonNullLazyRootedObject")
|
||||
|
||||
# If cx is null then LazyRootedObject will not be
|
||||
# constructed and behave as nullptr.
|
||||
templateBody = "${declName}.construct(cx, &${val}.toObject());"
|
||||
|
||||
# Cast of nullptr to (JSObject*) is required for template deduction.
|
||||
setToNullCode = "${declName}.construct(cx, static_cast<JSObject*>(nullptr));"
|
||||
|
||||
# If cx is null then LazyRootedObject will not be
|
||||
# constructed and behave as nullptr.
|
||||
templateBody = CGIfWrapper(CGGeneric(templateBody), "cx").define()
|
||||
setToNullCode = CGIfWrapper(CGGeneric(setToNullCode), "cx").define()
|
||||
|
||||
template = wrapObjectTemplate(templateBody, type, setToNullCode,
|
||||
failureCode)
|
||||
|
||||
return JSToNativeConversionInfo(template, declType=declType,
|
||||
dealWithOptional=isOptional)
|
||||
|
||||
if not isMember:
|
||||
declType = CGGeneric("JS::Rooted<JSObject*>")
|
||||
else:
|
||||
assert isMember == "Sequence" or isMember == "Variadic"
|
||||
# We'll get traced by the sequence tracer
|
||||
assert (isMember == "Sequence" or isMember == "Variadic" or
|
||||
isMember == "Dictionary")
|
||||
# We'll get traced by the sequence or dictionary tracer
|
||||
declType = CGGeneric("JSObject*")
|
||||
templateBody = "${declName} = &${valHandle}.toObject();"
|
||||
setToNullCode = "${declName} = nullptr;"
|
||||
@ -3345,21 +3322,17 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||
assert not isEnforceRange and not isClamp
|
||||
|
||||
declArgs = None
|
||||
if isMember == "Dictionary":
|
||||
declType = "LazyRootedValue"
|
||||
templateBody = "${declName}.construct(cx, ${val});"
|
||||
nullHandling = "${declName}.construct(cx, JS::NullValue());"
|
||||
if (isMember == "Variadic" or isMember == "Sequence" or
|
||||
isMember == "Dictionary"):
|
||||
# Rooting is handled by the sequence and dictionary tracers.
|
||||
declType = "JS::Value"
|
||||
else:
|
||||
if isMember == "Variadic" or isMember == "Sequence":
|
||||
# Rooting is handled by the sequence tracer.
|
||||
declType = "JS::Value"
|
||||
else:
|
||||
assert not isMember
|
||||
declType = "JS::Rooted<JS::Value>"
|
||||
declArgs = "cx"
|
||||
assert not isMember
|
||||
declType = "JS::Rooted<JS::Value>"
|
||||
declArgs = "cx"
|
||||
|
||||
templateBody = "${declName} = ${val};"
|
||||
nullHandling = "${declName} = JS::NullValue()"
|
||||
templateBody = "${declName} = ${val};"
|
||||
nullHandling = "${declName} = JS::NullValue()"
|
||||
|
||||
templateBody = handleDefaultNull(templateBody, nullHandling)
|
||||
return JSToNativeConversionInfo(templateBody,
|
||||
@ -3414,7 +3387,20 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||
"%s\n"
|
||||
"}" % (val, exceptionCodeIndented.define()))
|
||||
|
||||
return JSToNativeConversionInfo(template, declType=declType)
|
||||
# Dictionary arguments that might contain traceable things need to get
|
||||
# traced
|
||||
if not isMember and typeNeedsCx(type, descriptorProvider):
|
||||
holderType = CGTemplatedType("DictionaryRooter", declType);
|
||||
template = ("${holderName}.SetDictionary(&${declName});\n" +
|
||||
template)
|
||||
holderArgs = "cx"
|
||||
else:
|
||||
holderType = None
|
||||
holderArgs = None
|
||||
|
||||
return JSToNativeConversionInfo(template, declType=declType,
|
||||
holderType=holderType,
|
||||
holderArgs=holderArgs)
|
||||
|
||||
if type.isVoid():
|
||||
assert not isOptional
|
||||
@ -3759,7 +3745,7 @@ class CGArgumentConverter(CGThing):
|
||||
sequenceWrapLevel = 0
|
||||
|
||||
def getWrapTemplateForType(type, descriptorProvider, result, successCode,
|
||||
isCreator, exceptionCode, isMember=False):
|
||||
isCreator, exceptionCode):
|
||||
"""
|
||||
Reflect a C++ value stored in "result", of IDL type "type" into JS. The
|
||||
"successCode" is the code to run once we have successfully done the
|
||||
@ -3982,10 +3968,7 @@ if (!returnArray) {
|
||||
if type.nullable():
|
||||
toValue = "JS::ObjectOrNullValue(%s)"
|
||||
else:
|
||||
if isMember:
|
||||
toValue = "JS::ObjectValue(%s)"
|
||||
else:
|
||||
toValue = "JS::ObjectValue(*%s)"
|
||||
toValue = "JS::ObjectValue(*%s)"
|
||||
# NB: setValue(..., True) calls JS_WrapValue(), so is fallible
|
||||
return (setValue(toValue % result, True), False)
|
||||
|
||||
@ -4038,10 +4021,9 @@ if (!returnArray) {
|
||||
else:
|
||||
raise TypeError("Need to learn to wrap primitive: %s" % type)
|
||||
|
||||
def wrapForType(type, descriptorProvider, templateValues, isMember=False):
|
||||
def wrapForType(type, descriptorProvider, templateValues):
|
||||
"""
|
||||
Reflect a C++ value of IDL type "type" into JS. isMember should
|
||||
be true if the type is of a dictionary member. TemplateValues is a dict
|
||||
Reflect a C++ value of IDL type "type" into JS. TemplateValues is a dict
|
||||
that should contain:
|
||||
|
||||
* 'jsvalRef': a C++ reference to the jsval in which to store the result of
|
||||
@ -4072,8 +4054,7 @@ def wrapForType(type, descriptorProvider, templateValues, isMember=False):
|
||||
templateValues.get('successCode', None),
|
||||
templateValues.get('isCreator', False),
|
||||
templateValues.get('exceptionCode',
|
||||
"return false;"),
|
||||
isMember)[0]
|
||||
"return false;"))[0]
|
||||
|
||||
defaultValues = {'obj': 'obj'}
|
||||
return string.Template(wrap).substitute(defaultValues, **templateValues)
|
||||
@ -4315,12 +4296,10 @@ def wrapTypeIntoCurrentCompartment(type, value, isMember=True):
|
||||
"}" % value)
|
||||
|
||||
if type.isObject():
|
||||
if not isMember:
|
||||
value = value + ".address()"
|
||||
elif not type.nullable():
|
||||
value = "%s.Slot()" % value
|
||||
else:
|
||||
if isMember:
|
||||
value = "&%s" % value
|
||||
else:
|
||||
value = value + ".address()"
|
||||
return CGGeneric("if (!JS_WrapObject(cx, %s)) {\n"
|
||||
" return false;\n"
|
||||
"}" % value)
|
||||
@ -7528,6 +7507,8 @@ class CGDictionary(CGThing):
|
||||
" return false;\n"
|
||||
"}\n" % self.makeClassName(d.parent))
|
||||
ensureObject = "JS::Rooted<JSObject*> obj(cx, &vp->toObject());\n"
|
||||
traceParent = ("%s::TraceDictionary(trc);\n" %
|
||||
self.makeClassName(d.parent))
|
||||
else:
|
||||
initParent = ""
|
||||
toObjectParent = ""
|
||||
@ -7536,6 +7517,7 @@ class CGDictionary(CGThing):
|
||||
" return false;\n"
|
||||
"}\n"
|
||||
"*vp = JS::ObjectValue(*obj);\n")
|
||||
traceParent = ""
|
||||
|
||||
memberInits = [CGIndenter(self.getMemberConversion(m)).define()
|
||||
for m in self.memberInfo]
|
||||
@ -7550,6 +7532,9 @@ class CGDictionary(CGThing):
|
||||
reindent=True)
|
||||
memberDefines = [CGIndenter(self.getMemberDefinition(m)).define()
|
||||
for m in self.memberInfo]
|
||||
memberTraces = [CGIndenter(self.getMemberTrace(m)).define()
|
||||
for m in self.dictionary.members
|
||||
if typeNeedsCx(m.type, self.descriptorProvider)]
|
||||
|
||||
return string.Template(
|
||||
# NOTE: jsids are per-runtime, so don't use them in workers
|
||||
@ -7618,7 +7603,8 @@ class CGDictionary(CGThing):
|
||||
"void\n"
|
||||
"${selfName}::TraceDictionary(JSTracer* trc)\n"
|
||||
"{\n"
|
||||
" // XXXbz Need an implementation\n"
|
||||
"${traceParent}"
|
||||
"${traceMembers}\n"
|
||||
"}").substitute({
|
||||
"selfName": self.makeClassName(d),
|
||||
"initParent": CGIndenter(CGGeneric(initParent)).define(),
|
||||
@ -7627,6 +7613,8 @@ class CGDictionary(CGThing):
|
||||
"isMainThread": toStringBool(not self.workers),
|
||||
"toObjectParent": CGIndenter(CGGeneric(toObjectParent)).define(),
|
||||
"ensureObject": CGIndenter(CGGeneric(ensureObject)).define(),
|
||||
"traceMembers": "\n\n".join(memberTraces),
|
||||
"traceParent": CGIndenter(CGGeneric(traceParent)).define(),
|
||||
"defineMembers": "\n\n".join(memberDefines)
|
||||
})
|
||||
|
||||
@ -7751,11 +7739,11 @@ class CGDictionary(CGThing):
|
||||
'jsvalPtr': "temp.address()",
|
||||
'isCreator': False,
|
||||
'obj': "parentObject"
|
||||
}, isMember=True)
|
||||
})
|
||||
conversion = CGGeneric(innerTemplate)
|
||||
conversion = CGWrapper(conversion,
|
||||
pre=("JS::Rooted<JS::Value> temp(cx);\n"
|
||||
"const %s& currentValue = %s;\n" %
|
||||
"%s const & currentValue = %s;\n" %
|
||||
(declType.define(), memberData)
|
||||
))
|
||||
|
||||
@ -7772,6 +7760,44 @@ class CGDictionary(CGThing):
|
||||
conversion = CGIfWrapper(conversion, "%s.WasPassed()" % memberLoc)
|
||||
return conversion
|
||||
|
||||
def getMemberTrace(self, member):
|
||||
type = member.type;
|
||||
assert typeNeedsCx(type, self.descriptorProvider)
|
||||
memberLoc = self.makeMemberName(member.identifier.name)
|
||||
if member.defaultValue:
|
||||
memberData = memberLoc
|
||||
else:
|
||||
# The data is inside the Optional<>
|
||||
memberData = "%s.Value()" % memberLoc
|
||||
|
||||
memberName = "%s.%s" % (self.makeClassName(self.dictionary),
|
||||
memberLoc)
|
||||
|
||||
if type.isObject():
|
||||
trace = CGGeneric('JS_CallObjectTracer(trc, %s, "%s");' %
|
||||
("&"+memberData, memberName))
|
||||
elif type.isAny():
|
||||
trace = CGGeneric('JS_CallValueTracer(trc, %s, "%s");' %
|
||||
("&"+memberData, memberName))
|
||||
elif type.isSequence() or type.isDictionary():
|
||||
if type.nullable():
|
||||
memberNullable = memberData
|
||||
memberData = "%s.Value()" % memberData
|
||||
if type.isSequence():
|
||||
trace = CGGeneric('DoTraceSequence(trc, %s);' % memberData)
|
||||
else:
|
||||
assert type.isDictionary()
|
||||
trace = CGGeneric('%s.TraceDictionary(trc);' % memberData)
|
||||
if type.nullable():
|
||||
trace = CGIfWrapper(trace, "!%s.IsNull()" % memberNullable)
|
||||
else:
|
||||
assert 0 # unknown type
|
||||
|
||||
if not member.defaultValue:
|
||||
trace = CGIfWrapper(trace, "%s.WasPassed()" % memberLoc)
|
||||
|
||||
return trace
|
||||
|
||||
@staticmethod
|
||||
def makeIdName(name):
|
||||
return name + "_id"
|
||||
|
@ -680,10 +680,12 @@ dictionary DictContainingSequence {
|
||||
sequence<long> ourSequence;
|
||||
sequence<TestInterface> ourSequence2;
|
||||
sequence<any> ourSequence3;
|
||||
// XXXbz we can't make up our minds about how to represent 'object';
|
||||
// will be fixed once we trace dictionaries.
|
||||
//sequence<object> ourSequence4;
|
||||
sequence<object> ourSequence4;
|
||||
sequence<object?> ourSequence5;
|
||||
sequence<object>? ourSequence6;
|
||||
sequence<object?>? ourSequence7;
|
||||
sequence<object>? ourSequence8 = null;
|
||||
sequence<object?>? ourSequence9 = null;
|
||||
};
|
||||
|
||||
dictionary DictForConstructor {
|
||||
|
Loading…
x
Reference in New Issue
Block a user