Bug 1379680. Add an ipc ByteBuf type. r=billm
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Wed, 29 Nov 2017 10:11:15 -0500
changeset 448521 cbfc68a9fa54b09b4ffcb2cce6eb2fd5570fedfc
parent 448520 66ba728d4fe90ac1eb4e79d072e219be5a36037c
child 448522 7de1ab07869e102c183b85921abdaa32acbaef7b
child 448546 a92a2a4fa4fbb5b69281c80ced79dcb63b66c8b8
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs1379680
milestone59.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 1379680. Add an ipc ByteBuf type. r=billm This adds a ByteBuf type that can be sent by taking ownership of its buffer instead of having to make a copy.
gfx/layers/ipc/PWebRenderBridge.ipdl
gfx/layers/wr/WebRenderBridgeChild.cpp
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/layers/wr/WebRenderBridgeParent.h
ipc/chromium/src/chrome/common/ipc_message_utils.h
ipc/glue/ByteBuf.h
ipc/glue/ProtocolUtils.h
ipc/glue/moz.build
ipc/ipdl/ipdl/builtin.py
ipc/ipdl/ipdl/lower.py
ipc/ipdl/ipdl/type.py
--- a/gfx/layers/ipc/PWebRenderBridge.ipdl
+++ b/gfx/layers/ipc/PWebRenderBridge.ipdl
@@ -45,17 +45,17 @@ parent:
   // Creates a set of mappings between TextureReadLocks and an associated
   // ReadLockHandle that can be used in Update, and persist until the
   // next Update call.
   async InitReadLocks(ReadLockInit[] locks);
 
   sync Create(IntSize aSize);
   async DeleteCompositorAnimations(uint64_t[] aIds);
   async SetDisplayList(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
-                       LayoutSize aContentSize, ByteBuffer aDL, BuiltDisplayListDescriptor aDLDesc,
+                       LayoutSize aContentSize, ByteBuf aDL, BuiltDisplayListDescriptor aDLDesc,
                        WebRenderScrollData aScrollData,
                        OpUpdateResource[] aResourceUpdates, Shmem[] aSmallShmems, Shmem[] aLargeShmems,
                        IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime);
   async EmptyTransaction(FocusTarget focusTarget,
                          WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
                          IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime);
   async SetFocusTarget(FocusTarget focusTarget);
   async UpdateResources(OpUpdateResource[] aResourceUpdates, Shmem[] aSmallShmems, Shmem[] aLargeShmems);
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -139,17 +139,19 @@ WebRenderBridgeChild::EndTransaction(con
                                      const gfx::IntSize& aSize,
                                      uint64_t aTransactionId,
                                      const WebRenderScrollData& aScrollData,
                                      const mozilla::TimeStamp& aTxnStartTime)
 {
   MOZ_ASSERT(!mDestroyed);
   MOZ_ASSERT(mIsInTransaction);
 
-  ByteBuffer dlData(Move(aDL.dl));
+  ByteBuf dlData(aDL.dl.inner.data, aDL.dl.inner.length, aDL.dl.inner.capacity);
+  aDL.dl.inner.capacity = 0;
+  aDL.dl.inner.data = nullptr;
 
   TimeStamp fwdTime;
 #if defined(ENABLE_FRAME_LATENCY_LOG)
   fwdTime = TimeStamp::Now();
 #endif
 
   nsTArray<OpUpdateResource> resourceUpdates;
   nsTArray<ipc::Shmem> smallShmems;
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -556,17 +556,17 @@ WebRenderBridgeParent::GetScrollData() c
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
                                           InfallibleTArray<WebRenderParentCommand>&& aCommands,
                                           InfallibleTArray<OpDestroy>&& aToDestroy,
                                           const uint64_t& aFwdTransactionId,
                                           const uint64_t& aTransactionId,
                                           const wr::LayoutSize& aContentSize,
-                                          const wr::ByteBuffer& dl,
+                                          ipc::ByteBuf&& dl,
                                           const wr::BuiltDisplayListDescriptor& dlDesc,
                                           const WebRenderScrollData& aScrollData,
                                           nsTArray<OpUpdateResource>&& aResourceUpdates,
                                           nsTArray<ipc::Shmem>&& aSmallShmems,
                                           nsTArray<ipc::Shmem>&& aLargeShmems,
                                           const wr::IdNamespace& aIdNamespace,
                                           const TimeStamp& aTxnStartTime,
                                           const TimeStamp& aFwdTime)
@@ -604,17 +604,17 @@ WebRenderBridgeParent::RecvSetDisplayLis
   if (mIdNamespace == aIdNamespace) {
     if (mWidget) {
       LayoutDeviceIntSize size = mWidget->GetClientSize();
       mApi->SetWindowParameters(size);
     }
     gfx::Color clearColor(0.f, 0.f, 0.f, 0.f);
     mApi->SetDisplayList(clearColor, wr::NewEpoch(wrEpoch), LayerSize(aSize.width, aSize.height),
                         mPipelineId, aContentSize,
-                        dlDesc, dl.mData, dl.mLength,
+                        dlDesc, dl.mData, dl.mLen,
                         resources);
 
     ScheduleComposition();
 
     if (ShouldParentObserveEpoch()) {
       mCompositorBridge->ObserveLayerUpdate(GetLayersId(), GetChildLayerObserverEpoch(), true);
     }
   }
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -77,17 +77,17 @@ public:
                                               nsTArray<ipc::Shmem>&& aSmallShmems,
                                               nsTArray<ipc::Shmem>&& aLargeShmems) override;
   mozilla::ipc::IPCResult RecvSetDisplayList(const gfx::IntSize& aSize,
                                              InfallibleTArray<WebRenderParentCommand>&& aCommands,
                                              InfallibleTArray<OpDestroy>&& aToDestroy,
                                              const uint64_t& aFwdTransactionId,
                                              const uint64_t& aTransactionId,
                                              const wr::LayoutSize& aContentSize,
-                                             const wr::ByteBuffer& dl,
+                                             ipc::ByteBuf&& dl,
                                              const wr::BuiltDisplayListDescriptor& dlDesc,
                                              const WebRenderScrollData& aScrollData,
                                              nsTArray<OpUpdateResource>&& aResourceUpdates,
                                              nsTArray<ipc::Shmem>&& aSmallShmems,
                                              nsTArray<ipc::Shmem>&& aLargeShmems,
                                              const wr::IdNamespace& aIdNamespace,
                                              const TimeStamp& aTxnStartTime,
                                              const TimeStamp& aFwdTime) override;
--- a/ipc/chromium/src/chrome/common/ipc_message_utils.h
+++ b/ipc/chromium/src/chrome/common/ipc_message_utils.h
@@ -107,16 +107,21 @@ class MessageIterator {
 template <class P> struct ParamTraits;
 
 template <class P>
 static inline void WriteParam(Message* m, const P& p) {
   ParamTraits<P>::Write(m, p);
 }
 
 template <class P>
+static inline void WriteParam(Message* m, P& p) {
+  ParamTraits<P>::Write(m, p);
+}
+
+template <class P>
 static inline bool WARN_UNUSED_RESULT ReadParam(const Message* m, PickleIterator* iter,
                                                 P* p) {
   return ParamTraits<P>::Read(m, iter, p);
 }
 
 template <class P>
 static inline void LogParam(const P& p, std::wstring* l) {
   ParamTraits<P>::Log(p, l);
new file mode 100644
--- /dev/null
+++ b/ipc/glue/ByteBuf.h
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* A type that can be sent without needing to make a copy during
+ * serialization. In addition the receiver can take ownership of the
+ * data to avoid having to make an additional copy. */
+
+#ifndef mozilla_ipc_ByteBuf_h
+#define mozilla_ipc_ByteBuf_h
+
+#include "ipc/IPCMessageUtils.h"
+
+namespace mozilla {
+
+namespace ipc {
+
+class ByteBuf final
+{
+  friend struct IPC::ParamTraits<mozilla::ipc::ByteBuf>;
+public:
+  bool
+  Allocate(size_t aLength)
+  {
+    MOZ_ASSERT(mData == nullptr);
+    mData = (uint8_t*)malloc(aLength);
+    if (!mData) {
+      return false;
+    }
+    mLen = aLength;
+    mCapacity = aLength;
+    return true;
+  }
+
+  ByteBuf()
+    : mData(nullptr)
+    , mLen(0)
+    , mCapacity(0)
+  {}
+
+  ByteBuf(uint8_t *aData, size_t aLen, size_t aCapacity)
+    : mData(aData)
+    , mLen(aLen)
+    , mCapacity(aCapacity)
+  {}
+
+  ByteBuf(const ByteBuf& aFrom) = delete;
+
+  ByteBuf(ByteBuf&& aFrom)
+    : mData(aFrom.mData)
+    , mLen(aFrom.mLen)
+    , mCapacity(aFrom.mCapacity)
+  {
+    aFrom.mData = nullptr;
+    aFrom.mLen = 0;
+    aFrom.mCapacity = 0;
+  }
+
+  ~ByteBuf()
+  {
+    free(mData);
+  }
+
+  uint8_t* mData;
+  size_t mLen;
+  size_t mCapacity;
+};
+
+
+} // namespace ipc
+} // namespace mozilla
+
+
+namespace IPC {
+
+template<>
+struct ParamTraits<mozilla::ipc::ByteBuf>
+{
+  typedef mozilla::ipc::ByteBuf paramType;
+
+  // this is where we transfer the memory from the ByteBuf to IPDL, avoiding a copy
+  static void Write(Message* aMsg, paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.mLen);
+    // hand over ownership of the buffer to the Message
+    aMsg->WriteBytesZeroCopy(aParam.mData, aParam.mLen, aParam.mCapacity);
+    aParam.mData = nullptr;
+    aParam.mCapacity = 0;
+    aParam.mLen = 0;
+  }
+
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+  {
+    // We make a copy from the BufferList so that we get a contigous result.
+    // For users the can handle a non-contiguous result using ExtractBuffers
+    // is an option, alternatively if the users don't need to take ownership of
+    // the data they can use the removed FlattenBytes (bug 1297981)
+    size_t length;
+    return ReadParam(aMsg, aIter, &length)
+      && aResult->Allocate(length)
+      && aMsg->ReadBytesInto(aIter, aResult->mData, length);
+  }
+
+  static void Log(const paramType& aParam, std::wstring* aLog)
+  {
+    aLog->append(L"(byte buf)");
+  }
+};
+
+
+} // namespace IPC
+
+
+#endif // ifndef mozilla_ipc_Shmem_h
--- a/ipc/glue/ProtocolUtils.h
+++ b/ipc/glue/ProtocolUtils.h
@@ -13,16 +13,17 @@
 #include "base/process_util.h"
 #include "chrome/common/ipc_message_utils.h"
 
 #include "prenv.h"
 
 #include "IPCMessageStart.h"
 #include "mozilla/AlreadyAddRefed.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/ipc/ByteBuf.h"
 #include "mozilla/ipc/FileDescriptor.h"
 #include "mozilla/ipc/Shmem.h"
 #include "mozilla/ipc/Transport.h"
 #include "mozilla/ipc/MessageLink.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/Mutex.h"
--- a/ipc/glue/moz.build
+++ b/ipc/glue/moz.build
@@ -10,16 +10,17 @@ EXPORTS += [
     'nsIIPCSerializableURI.h',
 ]
 
 EXPORTS.mozilla.ipc += [
     'BackgroundChild.h',
     'BackgroundParent.h',
     'BackgroundUtils.h',
     'BrowserProcessSubThread.h',
+    'ByteBuf.h',
     'CrashReporterClient.h',
     'CrashReporterHost.h',
     'CrashReporterMetadataShmem.h',
     'CrossProcessMutex.h',
     'CrossProcessSemaphore.h',
     'FileDescriptor.h',
     'FileDescriptorSetChild.h',
     'FileDescriptorSetParent.h',
--- a/ipc/ipdl/ipdl/builtin.py
+++ b/ipc/ipdl/ipdl/builtin.py
@@ -34,16 +34,17 @@ Types = (
 
     # Mozilla types: "less" standard things we know how serialize/deserialize
     'nsresult',
     'nsString',
     'nsCString',
     'nsDependentSubstring',
     'nsDependentCSubstring',
     'mozilla::ipc::Shmem',
+    'mozilla::ipc::ByteBuf',
     'mozilla::ipc::FileDescriptor'
 )
 
 
 HeaderIncludes = (
     'mozilla/Attributes.h',
     'IPCMessageStart.h',
     'ipc/IPCMessageUtils.h',
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -555,16 +555,19 @@ class _ConvertToCxxType(TypeVisitor):
 
     def visitArrayType(self, a):
         basecxxtype = a.basetype.accept(self)
         return _cxxArrayType(basecxxtype)
 
     def visitShmemType(self, s):
         return Type(self.typename(s))
 
+    def visitByteBufType(self, s):
+        return Type(self.typename(s))
+
     def visitFDType(self, s):
         return Type(self.typename(s))
 
     def visitEndpointType(self, s):
         return Type(self.typename(s))
 
     def visitProtocolType(self, p): assert 0
     def visitMessageType(self, m): assert 0
@@ -581,23 +584,27 @@ def _cxxRefType(ipdltype, side):
 
 def _cxxConstRefType(ipdltype, side):
     t = _cxxBareType(ipdltype, side)
     if ipdltype.isIPDL() and ipdltype.isActor():
         return t
     if ipdltype.isIPDL() and ipdltype.isShmem():
         t.ref = 1
         return t
+    if ipdltype.isIPDL() and ipdltype.isByteBuf():
+        t.ref = 1
+        return t
     t.const = 1
     t.ref = 1
     return t
 
 def _cxxTypeNeedsMove(ipdltype):
     return ipdltype.isIPDL() and (ipdltype.isArray() or
                                   ipdltype.isShmem() or
+                                  ipdltype.isByteBuf() or
                                   ipdltype.isEndpoint())
 
 def _cxxMoveRefType(ipdltype, side):
     t = _cxxBareType(ipdltype, side)
     if _cxxTypeNeedsMove(ipdltype):
         t.ref = 2
         return t
     return _cxxConstRefType(ipdltype, side)
@@ -763,16 +770,18 @@ class _StructField(_CompoundTypeComponen
             ref = ExprDeref(ref)
         return ref
 
     def constRefExpr(self, thisexpr=None):
         # sigh, gross hack
         refexpr = self.refExpr(thisexpr)
         if 'Shmem' == self.ipdltype.name():
             refexpr = ExprCast(refexpr, Type('Shmem', ref=1), const=1)
+        if 'ByteBuf' == self.ipdltype.name():
+            refexpr = ExprCast(refexpr, Type('ByteBuf', ref=1), const=1)
         if 'FileDescriptor' == self.ipdltype.name():
             refexpr = ExprCast(refexpr, Type('FileDescriptor', ref=1), const=1)
         return refexpr
 
     def argVar(self):
         return ExprVar('_'+ self.name)
 
     def memberVar(self):
@@ -926,16 +935,18 @@ IPDL union type."""
         if self.ipdltype.isIPDL() and self.ipdltype.isActor():
             return ExprLiteral.NULL
         # XXX sneaky here, maybe need ExprCtor()?
         return ExprCall(self.bareType())
 
     def getConstValue(self):
         v = ExprDeref(self.callGetConstPtr())
         # sigh
+        if 'ByteBuf' == self.ipdltype.name():
+            v = ExprCast(v, Type('ByteBuf', ref=1), const=1)
         if 'Shmem' == self.ipdltype.name():
             v = ExprCast(v, Type('Shmem', ref=1), const=1)
         if 'FileDescriptor' == self.ipdltype.name():
             v = ExprCast(v, Type('FileDescriptor', ref=1), const=1)
         return v
 
 ##--------------------------------------------------
 
@@ -1865,16 +1876,21 @@ stmt.  Some types generate both kinds.''
     def visitArrayType(self, t):
         return TypeVisitor.visitArrayType(self, t)
 
     def visitShmemType(self, s):
         if s in self.visited: return
         self.visited.add(s)
         self.maybeTypedef('mozilla::ipc::Shmem', 'Shmem')
 
+    def visitByteBufType(self, s):
+        if s in self.visited: return
+        self.visited.add(s)
+        self.maybeTypedef('mozilla::ipc::ByteBuf', 'ByteBuf')
+
     def visitFDType(self, s):
         if s in self.visited: return
         self.visited.add(s)
         self.maybeTypedef('mozilla::ipc::FileDescriptor', 'FileDescriptor')
 
     def visitVoidType(self, v): assert 0
     def visitMessageType(self, v): assert 0
     def visitProtocolType(self, v): assert 0
@@ -3379,16 +3395,17 @@ class _GenerateProtocolActorCode(ipdl.as
         # pickling of "normal", non-IPDL types
         self.implementGenericPickling()
 
         # pickling for IPDL types
         specialtypes = set()
         class findSpecialTypes(TypeVisitor):
             def visitActorType(self, a): specialtypes.add(a)
             def visitShmemType(self, s): specialtypes.add(s)
+            def visitByteBufType(self, s): specialtypes.add(s)
             def visitFDType(self, s): specialtypes.add(s)
             def visitStructType(self, s):
                 specialtypes.add(s)
                 return TypeVisitor.visitStructType(self, s)
             def visitUnionType(self, u):
                 specialtypes.add(u)
                 return TypeVisitor.visitUnionType(self, u)
             def visitArrayType(self, a):
@@ -3403,22 +3420,23 @@ class _GenerateProtocolActorCode(ipdl.as
                 # understood yet
                 if mtype.isDtor() and mtype.constructedType().isToplevel():
                     continue
                 param.ipdltype.accept(findSpecialTypes())
             for ret in md.returns:
                 ret.ipdltype.accept(findSpecialTypes())
 
         for t in specialtypes:
-            if t.isActor():    self.implementActorPickling(t)
-            elif t.isArray():  self.implementSpecialArrayPickling(t)
-            elif t.isShmem():  self.implementShmemPickling(t)
-            elif t.isFD():     self.implementFDPickling(t)
-            elif t.isStruct(): self.implementStructPickling(t)
-            elif t.isUnion():  self.implementUnionPickling(t)
+            if t.isActor():     self.implementActorPickling(t)
+            elif t.isArray():   self.implementSpecialArrayPickling(t)
+            elif t.isShmem():   self.implementShmemPickling(t)
+            elif t.isByteBuf(): self.implementByteBufPickling(t)
+            elif t.isFD():      self.implementFDPickling(t)
+            elif t.isStruct():  self.implementStructPickling(t)
+            elif t.isUnion():   self.implementUnionPickling(t)
             else:
                 assert 0 and 'unknown special type'
 
     def implementGenericPickling(self):
         var = self.var
         msgvar = self.msgvar
         itervar = self.itervar
 
@@ -3429,16 +3447,29 @@ class _GenerateProtocolActorCode(ipdl.as
 
         read = MethodDefn(self.readMethodDecl(
             Type('T', ptr=1), var, template=Type('T')))
         read.addstmt(StmtReturn(ExprCall(ExprVar('IPC::ReadParam'),
                                          args=[ msgvar, itervar, var ])))
 
         self.cls.addstmts([ write, Whitespace.NL, read, Whitespace.NL ])
 
+    def implementByteBufPickling(self, bytebuftype):
+        var = self.var
+        msgvar = self.msgvar
+        itervar = self.itervar
+        intype = _cxxRefType(bytebuftype, self.side)
+
+        write = MethodDefn(self.writeMethodDecl(intype, var))
+        write.addstmt(StmtExpr(ExprCall(ExprVar('IPC::WriteParam'),
+                                        args=[ msgvar, var ])))
+
+        self.cls.addstmts([ write, Whitespace.NL ])
+        # the rest of generic pickling will work fine for us
+
     def implementActorPickling(self, actortype):
         # Note that we pickle based on *protocol* type and *not* actor
         # type.  The actor type includes a |nullable| qualifier, but
         # this method is not specialized based on nullability.  The
         # |actortype| nullability is ignored in this method.
         var = self.var
         idvar = ExprVar('id')
         intype = _cxxConstRefType(actortype, self.side)
--- a/ipc/ipdl/ipdl/type.py
+++ b/ipc/ipdl/ipdl/type.py
@@ -62,16 +62,19 @@ class TypeVisitor:
             component.accept(self, *args)
 
     def visitArrayType(self, a, *args):
         a.basetype.accept(self, *args)
 
     def visitShmemType(self, s, *args):
         pass
 
+    def visitByteBufType(self, s, *args):
+        pass
+
     def visitShmemChmodType(self, c, *args):
         c.shmem.accept(self)
 
     def visitFDType(self, s, *args):
         pass
 
     def visitEndpointType(self, s, *args):
         pass
@@ -142,16 +145,17 @@ class IPDLType(Type):
     def isProtocol(self): return False
     def isActor(self): return False
     def isStruct(self): return False
     def isUnion(self): return False
     def isArray(self): return False
     def isAtom(self):  return True
     def isCompound(self): return False
     def isShmem(self): return False
+    def isByteBuf(self): return False
     def isFD(self): return False
     def isEndpoint(self): return False
 
     def isAsync(self): return self.sendSemantics == ASYNC
     def isSync(self): return self.sendSemantics == SYNC
     def isInterrupt(self): return self.sendSemantics is INTR
 
     def hasReply(self):  return (self.isSync() or self.isInterrupt())
@@ -363,16 +367,26 @@ class ShmemType(IPDLType):
         self.qname = qname
     def isShmem(self): return True
 
     def name(self):
         return self.qname.baseid
     def fullname(self):
         return str(self.qname)
 
+class ByteBufType(IPDLType):
+    def __init__(self, qname):
+        self.qname = qname
+    def isByteBuf(self): return True
+
+    def name(self):
+        return self.qname.baseid
+    def fullname(self):
+        return str(self.qname)
+
 class FDType(IPDLType):
     def __init__(self, qname):
         self.qname = qname
     def isFD(self): return True
 
     def name(self):
         return self.qname.baseid
     def fullname(self):
@@ -720,16 +734,18 @@ class GatherDecls(TcheckVisitor):
             utype.components.append(self._canonicalType(cdecl.type, c))
 
     def visitUsingStmt(self, using):
         fullname = str(using.type)
         if using.type.basename() == fullname:
             fullname = None
         if fullname == 'mozilla::ipc::Shmem':
             ipdltype = ShmemType(using.type.spec)
+        elif fullname == 'mozilla::ipc::ByteBuf':
+            ipdltype = ByteBufType(using.type.spec)
         elif fullname == 'mozilla::ipc::FileDescriptor':
             ipdltype = FDType(using.type.spec)
         else:
             ipdltype = ImportedCxxType(using.type.spec)
             existingType = self.symtab.lookup(ipdltype.fullname())
             if existingType and existingType.fullname == ipdltype.fullname():
                 using.decl = existingType
                 return