docs: function (sender, frameId, contextId, args) {
    const metaToValue = function (meta) {
      switch (meta.type) {
        case 'value':
          return meta.value
        case 'remote-object':
          return objectsRegistry.get(meta.id)
        case 'array':
          return unwrapArgs(sender, frameId, contextId, meta.value)
        case 'buffer':
          return bufferUtils.metaToBuffer(meta.value)
        case 'date':
          return new Date(meta.value)
        case 'promise':
          return Promise.resolve({
            then: metaToValue(meta.then)
          })
        case 'object': {
          const ret = {}
          Object.defineProperty(ret.constructor, 'name', { value: meta.name })
  
          for (const { name, value } of meta.members) {
            ret[name] = metaToValue(value)
          }
          return ret
        }
        case 'function-with-return-value':
          const returnValue = metaToValue(meta.value)
          return function () {
            return returnValue
          }
        case 'function': {
          // Merge contextId and meta.id, since meta.id can be the same in
          // different webContents.
          const objectId = [contextId, meta.id]
  
          // Cache the callbacks in renderer.
          if (rendererFunctions.has(objectId)) {
            return rendererFunctions.get(objectId)
          }
  
          const callIntoRenderer = function (...args) {
            let succeed = false
            if (!sender.isDestroyed()) {
              succeed = sender._sendToFrameInternal(frameId, 'ELECTRON_RENDERER_CALLBACK', contextId, meta.id, valueToMeta(sender, contextId, args))
            }
            if (!succeed) {
              removeRemoteListenersAndLogWarning(this, callIntoRenderer)
            }
          }
          v8Util.setHiddenValue(callIntoRenderer, 'location', meta.location)
          Object.defineProperty(callIntoRenderer, 'length', { value: meta.length })
  
          v8Util.setRemoteCallbackFreer(callIntoRenderer, contextId, meta.id, sender)
          rendererFunctions.set(objectId, callIntoRenderer)
          return callIntoRenderer
        }
        default:
          throw new TypeError(`Unknown type: ${meta.type}`)
      }
    }
    return args.map(metaToValue)
  }