deepFreezeBreakObjectInternal_ = function(arg) {
  if (!arg) {
    return;
  }
  switch (typeof arg) {
    case 'object':
      break;
    default:
      return;
  }

  const keys = [
    ...Object.getOwnPropertyNames(arg),
    ...Object.getOwnPropertySymbols(arg),
  ];
  const descriptorBundle = {};
  for (const key of keys) {
    const descriptor = Object.getOwnPropertyDescriptor(arg, key);
    if (!descriptor.enumerable) {
      continue;
    }

    let child;
    try {
      child = arg[key];
    } catch (e) {
      if (e !== throwingGetterError_) {
        // We aren't sure what the error here is. Enhance and return it to
        // callers.
        throw enhanceError(e);
      } else {
        // Here we have already broken this object (via some other path to the
        // object in the parent).
        continue;
      }
    }
    deepFreezeBreakObjectInternal_(child);
    // Batch-overwrite the original arg's value with a throwing getter
    descriptorBundle[key] = throwingPropertyDescriptor_;
  }
  Object.defineProperties(arg, descriptorBundle);
}
Replaces object property accesses with throwing getters to discourage the use
of the non-frozen version of an object used with deepFreeze.
@param {?Object} arg The object whose accessors should be broken.
@private