constructor(project) {
    this.project = project;

    // The cache of bundle-host package infos and their individual addon caches.
    // The cache is keyed by package info (representing a bundle host (project or
    // lazy engine)) and an addon instance cache to bundle with that bundle host.
    this.bundleHostCache = new Map();

    // Indicate if ember-engines transitive dedupe is enabled.
    this.engineAddonTransitiveDedupeEnabled = !!process.env.EMBER_ENGINES_ADDON_DEDUPE;
    this._perBundleAddonCacheUtil = resolvePerBundleAddonCacheUtil(this.project);

    // For stats purposes, counts on the # addons and proxies created. Addons we
    // can compare against the bundleHostCache addon caches. Proxies, not so much,
    // but we'll count them here.
    this.numAddonInstances = 0;
    this.numProxies = 0;
  }
For large applications with many addons (and many instances of each, resulting in
potentially many millions of addon instances during a build), the build can become
very, very slow (tens of minutes) partially due to the sheer number of addon instances.
The PerBundleAddonCache deals with this slowness by doing 3 things:

(1) Making only a single copy of each of certain addons and their dependent addons
(2) Replacing any other instances of those addons with Proxy copies to the single instance
(3) Having the Proxies return an empty array for their dependent addons, rather
    than proxying to the contents of the single addon instance. This gives up the
    ability of the Proxies to traverse downward into their child addons,
    something that many addons do not do anyway, for the huge reduction in duplications
    of those child addons. For applications that enable `ember-engines` dedupe logic,
    that logic is stateful, and having the Proxies allow access to the child addons array
    just breaks everything, because that logic will try multiple times to remove items
    it thinks are duplicated, messing up the single copy of the child addon array.
    See the explanation of the dedupe logic in
   {@link https://github.com/ember-engines/ember-engines/blob/master/packages/ember-engines/lib/utils/deeply-non-duplicated-addon.js}

What follows are the more technical details of how the PerBundleAddonCache implements
the above 3 behaviors.

This class supports per-bundle-host (bundle host = project or lazy engine)
caching of addon instances. During addon initialization we cannot add a
cache to each bundle host object AFTER it is instantiated because running the
addon constructor ultimately causes Addon class `setupRegistry` code to
run which instantiates child addons, which need the cache to already be
in place for the parent bundle host.
We handle this by providing a global cache that exists independent of the
bundle host objects. That is this object.

There are a number of "behaviors" being implemented by this object and
its contents. They are:
(1) Any addon that is a lazy engine has only a single real instance per
project - all other references to the lazy engine are to be proxies. These
lazy engines are compared by name, not by packageInfo.realPath.
(2) Any addon that is not a lazy engine, there is only a single real instance
of the addon per "bundle host" (i.e. lazy engine or project).
(3) An optimization - any addon that is in a lazy engine but that is also
in bundled by its LCA host - the single instance is the one bundled by this
host. All other instances (in any lazy engine) are proxies.

NOTE: the optimization is only enabled if the environment variable that controls
`ember-engines` transitive deduplication (process.env.EMBER_ENGINES_ADDON_DEDUPE)
is set to a truthy value. For more info, see:
https://github.com/ember-engines/ember-engines/blob/master/packages/ember-engines/lib/engine-addon.js#L396

@public
@class PerBundleAddonCache