docs: function defineProperty(obj, keyName, desc, data, meta) {
      var possibleDesc, existingDesc, watching, value;
  
      if (!meta) {
        meta = _emberMetalMeta.meta(obj);
      }
      var watchEntry = meta.peekWatching(keyName);
      possibleDesc = obj[keyName];
      existingDesc = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor ? possibleDesc : undefined;
  
      watching = watchEntry !== undefined && watchEntry > 0;
  
      if (existingDesc) {
        existingDesc.teardown(obj, keyName);
      }
  
      if (desc instanceof Descriptor) {
        value = desc;
  
        if (watching) {
          Object.defineProperty(obj, keyName, {
            configurable: true,
            enumerable: true,
            writable: true,
            value: value
          });
        } else {
          obj[keyName] = value;
        }
  
        if (desc.setup) {
          desc.setup(obj, keyName);
        }
      } else {
        if (desc == null) {
          value = data;
  
          if (watching) {
            meta.writeValues(keyName, data);
  
            var defaultDescriptor = {
              configurable: true,
              enumerable: true,
              set: MANDATORY_SETTER_FUNCTION(keyName),
              get: DEFAULT_GETTER_FUNCTION(keyName)
            };
  
            if (REDEFINE_SUPPORTED) {
              Object.defineProperty(obj, keyName, defaultDescriptor);
            } else {
              handleBrokenPhantomDefineProperty(obj, keyName, defaultDescriptor);
            }
          } else {
            obj[keyName] = data;
          }
        } else {
          value = desc;
  
          // fallback to ES5
          Object.defineProperty(obj, keyName, desc);
        }
      }
  
      // if key is being watched, override chains that
      // were initialized with the prototype
      if (watching) {
        _emberMetalProperty_events.overrideChains(obj, keyName, meta);
      }
  
      // The `value` passed to the `didDefineProperty` hook is
      // either the descriptor or data, whichever was passed.
      if (obj.didDefineProperty) {
        obj.didDefineProperty(obj, keyName, value);
      }
  
      return this;
    }