Bug 942631 part 5. Add C++ API for clearing the cached value of a [Cached] property or regetting a [StoreInSlot] property. r=peterv
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 04 Dec 2013 08:02:18 -0500
changeset 174461 fad25ed7cdef3f852e086bac57680602436db71e
parent 174460 a7878aac67f021cab53447ee30b385f5b43277e7
child 174462 f96a77402a2684a9d86716cb62fe147e79d3c42c
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv
bugs942631
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 942631 part 5. Add C++ API for clearing the cached value of a [Cached] property or regetting a [StoreInSlot] property. r=peterv
dom/bindings/Codegen.py
dom/bindings/test/TestCodeGen.webidl
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2425,22 +2425,22 @@ class CGWrapGlobalMethod(CGAbstractMetho
 
   // XXXkhuey can't do this yet until workers can lazy resolve.
   // JS_FireOnNewGlobalObject(aCx, obj);
 
   return obj;""" % (AssertInheritanceChain(self.descriptor),
                     self.descriptor.nativeType,
                     InitUnforgeableProperties(self.descriptor, self.properties))
 
-class CGUpdateMemberSlotsMethod(CGAbstractMethod):
+class CGUpdateMemberSlotsMethod(CGAbstractStaticMethod):
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'aCx'),
                 Argument('JS::Handle<JSObject*>', 'aWrapper'),
                 Argument(descriptor.nativeType + '*' , 'aObject')]
-        CGAbstractMethod.__init__(self, descriptor, 'UpdateMemberSlots', 'bool', args)
+        CGAbstractStaticMethod.__init__(self, descriptor, 'UpdateMemberSlots', 'bool', args)
 
     def definition_body(self):
         slotMembers = (m for m in self.descriptor.interface.members if
                        m.isAttr() and m.getExtendedAttribute("StoreInSlot"))
         storeSlots = (
             CGGeneric(
                 'static_assert(%d < js::shadow::Object::MAX_FIXED_SLOTS,\n'
                 '              "Not enough fixed slots to fit \'%s.%s\'");\n'
@@ -2454,16 +2454,67 @@ class CGUpdateMemberSlotsMethod(CGAbstra
             for m in slotMembers)
         body = CGList(storeSlots, "\n\n")
         body.prepend(CGGeneric("JS::Rooted<JS::Value> temp(aCx);\n"
                                "JSJitGetterCallArgs args(&temp);"))
         body.append(CGGeneric("return true;"))
 
         return CGIndenter(body).define()
 
+class CGClearCachedValueMethod(CGAbstractMethod):
+    def __init__(self, descriptor, member):
+        self.member = member
+        # If we're StoreInSlot, we'll need to call the getter
+        if member.getExtendedAttribute("StoreInSlot"):
+            args = [Argument('JSContext*', 'aCx')]
+            returnType = 'bool'
+        else:
+            args = []
+            returnType = 'void'
+        args.append(Argument(descriptor.nativeType + '*', 'aObject'))
+        name = ("ClearCached%sValue" % MakeNativeName(member.identifier.name))
+        CGAbstractMethod.__init__(self, descriptor, name, returnType, args)
+
+    def definition_body(self):
+        slotIndex = memberReservedSlot(self.member)
+        if self.member.getExtendedAttribute("StoreInSlot"):
+            # We have to root things and save the old value in case
+            # regetting fails, so we can restore it.
+            declObj = "JS::Rooted<JSObject*> obj(aCx);"
+            noopRetval = " true"
+            saveMember = (
+                "JS::Rooted<JS::Value> oldValue(aCx, js::GetReservedSlot(obj, %d));\n" %
+                slotIndex)
+            regetMember = ("\n"
+                           "JS::Rooted<JS::Value> temp(aCx);\n"
+                           "JSJitGetterCallArgs args(&temp);\n"
+                           "if (!get_%s(aCx, obj, aObject, args)) {\n"
+                           "  js::SetReservedSlot(obj, %d, oldValue);\n"
+                           "  nsJSUtils::ReportPendingException(aCx);\n"
+                           "  return false;\n"
+                           "}\n"
+                           "return true;" % (self.member.identifier.name, slotIndex))
+        else:
+            declObj = "JSObject* obj;"
+            noopRetval = ""
+            saveMember = ""
+            regetMember = ""
+
+        return CGIndenter(CGGeneric(
+                "%s\n"
+                "obj = aObject->GetWrapper();\n"
+                "if (!obj) {\n"
+                "  return%s;\n"
+                "}\n"
+                "%s"
+                "js::SetReservedSlot(obj, %d, JS::UndefinedValue());"
+                "%s"
+                % (declObj, noopRetval, saveMember, slotIndex, regetMember)
+                )).define()
+
 builtinNames = {
     IDLType.Tags.bool: 'bool',
     IDLType.Tags.int8: 'int8_t',
     IDLType.Tags.int16: 'int16_t',
     IDLType.Tags.int32: 'int32_t',
     IDLType.Tags.int64: 'int64_t',
     IDLType.Tags.uint8: 'uint8_t',
     IDLType.Tags.uint16: 'uint16_t',
@@ -8537,16 +8588,23 @@ class CGDescriptor(CGThing):
                 cgThings.append(CGWrapGlobalMethod(descriptor, properties))
             elif descriptor.wrapperCache:
                 cgThings.append(CGWrapWithCacheMethod(descriptor, properties))
                 cgThings.append(CGWrapMethod(descriptor))
             else:
                 cgThings.append(CGWrapNonWrapperCacheMethod(descriptor,
                                                             properties))
 
+        # If we're not wrappercached, we don't know how to clear our
+        # cached values, since we can't get at the JSObject.
+        if descriptor.wrapperCache:
+            cgThings.extend(CGClearCachedValueMethod(descriptor, m) for
+                            m in descriptor.interface.members if
+                            m.isAttr() and m.slotIndex is not None)
+
         # CGCreateInterfaceObjectsMethod needs to come after our
         # CGDOMJSClass, if any.
         cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
 
         # CGGetProtoObjectMethod and CGGetConstructorObjectMethod need
         # to come after CGCreateInterfaceObjectsMethod.
         if descriptor.interface.hasInterfacePrototypeObject():
             cgThings.append(CGGetProtoObjectMethod(descriptor))
@@ -9389,16 +9447,23 @@ class CGBindingRoot(CGThing):
                 return False
             try:
                 typeDesc = provider.getDescriptor(type.inner.identifier.name)
             except NoSuchDescriptorError:
                 return False
             return typeDesc.hasXPConnectImpls
         addHeaderBasedOnTypes("nsDOMQS.h", checkForXPConnectImpls)
 
+        def descriptorClearsPropsInSlots(descriptor):
+            if not descriptor.wrapperCache:
+                return False
+            return any(m.isAttr() and m.getExtendedAttribute("StoreInSlot")
+                       for m in descriptor.interface.members)
+        bindingHeaders["nsJSUtils.h"] = any(descriptorClearsPropsInSlots(d) for d in descriptors)
+
         # Do codegen for all the enums
         enums = config.getEnums(webIDLFile)
         cgthings = [ CGEnum(e) for e in enums ]
 
         hasCode = (descriptors or callbackDescriptors or dictionaries or
                    mainCallbacks or workerCallbacks)
         bindingHeaders["mozilla/dom/BindingUtils.h"] = hasCode
         bindingHeaders["mozilla/dom/OwningNonNull.h"] = hasCode
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -119,17 +119,17 @@ interface TestInterface {
   byte receiveByte();
   void passOptionalByte(optional byte arg);
   void passOptionalByteBeforeRequired(optional byte arg1, byte arg2);
   void passOptionalByteWithDefault(optional byte arg = 0);
   void passOptionalByteWithDefaultBeforeRequired(optional byte arg1 = 0, byte arg2);
   void passNullableByte(byte? arg);
   void passOptionalNullableByte(optional byte? arg);
   void passVariadicByte(byte... arg);
-  [Cached, Pure]
+  [StoreInSlot, Pure]
   readonly attribute byte cachedByte;
 
   readonly attribute short readonlyShort;
   attribute short writableShort;
   void passShort(short arg);
   short receiveShort();
   void passOptionalShort(optional short arg);
   void passOptionalShortWithDefault(optional short arg = 5);