<html><head><meta http-equiv="Content-Type" content="text/html charset=windows-1252"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div>I’m working on mach-o support for the linker and want transparent support for mach-o as yaml or binary.  I also want to make sure that it is possible to make a mach-o linker that does *not* support yaml or archives (such as for an embedded JIT linker).  In working out how to do this I noticed a bunch of design issues in lld.  </div><div><br></div>1) LinkingContext has a bunch of oddball methods that have just been added because it was convenient (such as getDefaultHandler which is really only needed by the Archive Reader). <br>2) The native file format does not record the “universe” for the kind field of References.  That is, a mach-o file could be converted to native and an ELF file converted to native and both may have a reference of kind 42, but the same 42 has different semantics.<br>3) identify_magic() is called redundantly in lots of places.<br>4) We don’t have a way for yaml to hand off control if a yaml test case contains heterogenous yaml file types.<br><div>5) Readers have been refactored into a trivial role.  They just instantiate some File subclass.</div><div><br></div><div><br></div><div>There is a design pattern that solves all these problems.  Have a global registry of “handlers”.  Require clients to call functions to which register the handlers they request.  Then any code that needs a handler calls the global registry to call the needed handler.</div><div><br></div><div>I see the need for three registries:  a file parser registry, a yaml document tag registry, and a kind string registry.</div><div><br></div><div>Here is one way to implement a registry for the file parser: </div><div><br></div><div><font face="Monaco" size="1">class InputParserRegistry {<br>public:<br>  // A function to quickly check if a file can be parsed.  Usually only the <br>  // magic parameter is checked.  But it can also check the file extension, or<br>  // even look at more of the buffer if needed.<br>  typedef bool (*InputFileChecker)(file_magic magic, StringRef fileExtension, <br>                                   const MemoryBuffer &mb);<br>                                    <br>  // A function to parse the supplied input file.<br>  typedef error_code (*InputFileParser)(std::unique_ptr<MemoryBuffer> &mb,<br>                                std::vector<std::unique_ptr<File>> &result);<br>                                <br>  // Registers a checker and parser with the global registry. <br>  // Usually, the checker and parser are static methods in some lld::File <br>  // subclass that will be instantiated.<br>  static void registerParser(InputFileChecker checker, <br>                             InputFileParser parser);<br>                                    <br>  // Walks registered checkers to parse the specified file.  <br>  static error_code parseFile(std::unique_ptr<MemoryBuffer> &mb,<br>                              std::vector<std::unique_ptr<File>> &result);<br>};<br></font><br><br></div><div>The mach-o linker tool would call:</div><div><font face="Monaco" size="1">   registryAddSupportMachO();</font></div><span style="font-family: Monaco; font-size: x-small;">   registryAddSupportArchives();</span><br style="font-family: Monaco; font-size: x-small;"><div><font face="Monaco" size="1">   registryAddSupportNative();<br></font><br></div><div>The implementation of registryAddSupportMachO would look like:</div><div><span style="font-family: Monaco; font-size: x-small;">  void registryAddSupportMachO() {</span></div><div><font face="Monaco" size="1">    InputParserRegistry::</font><span style="font-family: Monaco; font-size: x-small;">registerParser(FileMachO::check, FileMachO::parse);</span></div><div><font face="Monaco" size="1">  }</font></div><div><br></div><div>The code (in custom InputGraph nodes) no longer needs to call identify_magic, or look at the file extension, or handle archives.  All it does is:</div><div><div><font face="Monaco" size="1">  InputParserRegistry::</font><span style="font-family: Monaco; font-size: x-small;">parseFile(_buffer, _files);</span></div></div><div><span style="font-family: Monaco; font-size: x-small;"><br></span></div><div><div>I’ve looked at the llvm::Registry<> classes.  It does not seem to be a good match for what we need here:  It is designed around using static variables whose construction does the registration.  I prefer explicit calls to register to enable clients to *not* drag in support they don’t want.  The  Registry<> model also assume you want to instantiate the object with the default constructor, which we don’t.  And we have no need for listeners or name/description. Yes, by overriding SimpleRegistryEntry and RegistryTraits we could use  llvm::Registry<>, but I’m not sure it is worth the effort.</div><div><br></div></div><div><br></div><div>Overall, I want to see what you think of this pattern.  Once we have it worked out, I want to do a similar registry for:</div><div>1) yaml doc tags (so that various kinds of yaml (archive, atom, mach-o, elf, etc) can be intermixed in one test case.</div><div>2) Add a namespace registry for kind values.</div><div><br></div><div>-Nick</div><div><br></div></body></html>