void ProxyFunctionWrapper()

in shell/renderer/api/electron_api_context_bridge.cc [389:480]


void ProxyFunctionWrapper(const v8::FunctionCallbackInfo<v8::Value>& info) {
  TRACE_EVENT0("electron", "ContextBridge::ProxyFunctionWrapper");
  CHECK(info.Data()->IsObject());
  v8::Local<v8::Object> data = info.Data().As<v8::Object>();
  bool support_dynamic_properties = false;
  gin::Arguments args(info);
  // Context the proxy function was called from
  v8::Local<v8::Context> calling_context = args.isolate()->GetCurrentContext();

  // Pull the original function and its context off of the data private key
  v8::MaybeLocal<v8::Value> sdp_value =
      GetPrivate(calling_context, data,
                 context_bridge::kSupportsDynamicPropertiesPrivateKey);
  v8::MaybeLocal<v8::Value> maybe_func = GetPrivate(
      calling_context, data, context_bridge::kProxyFunctionPrivateKey);
  v8::Local<v8::Value> func_value;
  if (sdp_value.IsEmpty() || maybe_func.IsEmpty() ||
      !gin::ConvertFromV8(args.isolate(), sdp_value.ToLocalChecked(),
                          &support_dynamic_properties) ||
      !maybe_func.ToLocal(&func_value))
    return;

  v8::Local<v8::Function> func = func_value.As<v8::Function>();
  v8::Local<v8::Context> func_owning_context = func->CreationContext();

  {
    v8::Context::Scope func_owning_context_scope(func_owning_context);
    context_bridge::ObjectCache object_cache;

    std::vector<v8::Local<v8::Value>> original_args;
    std::vector<v8::Local<v8::Value>> proxied_args;
    args.GetRemaining(&original_args);

    for (auto value : original_args) {
      auto arg =
          PassValueToOtherContext(calling_context, func_owning_context, value,
                                  &object_cache, support_dynamic_properties, 0);
      if (arg.IsEmpty())
        return;
      proxied_args.push_back(arg.ToLocalChecked());
    }

    v8::MaybeLocal<v8::Value> maybe_return_value;
    bool did_error = false;
    v8::Local<v8::Value> error_message;
    {
      v8::TryCatch try_catch(args.isolate());
      maybe_return_value = func->Call(func_owning_context, func,
                                      proxied_args.size(), proxied_args.data());
      if (try_catch.HasCaught()) {
        did_error = true;
        v8::Local<v8::Value> exception = try_catch.Exception();

        const char err_msg[] =
            "An unknown exception occurred in the isolated context, an error "
            "occurred but a valid exception was not thrown.";

        if (!exception->IsNull() && exception->IsObject()) {
          v8::MaybeLocal<v8::Value> maybe_message =
              exception.As<v8::Object>()->Get(
                  func_owning_context,
                  gin::ConvertToV8(args.isolate(), "message"));

          if (!maybe_message.ToLocal(&error_message) ||
              !error_message->IsString()) {
            error_message = gin::StringToV8(args.isolate(), err_msg);
          }
        } else {
          error_message = gin::StringToV8(args.isolate(), err_msg);
        }
      }
    }

    if (did_error) {
      v8::Context::Scope calling_context_scope(calling_context);
      args.isolate()->ThrowException(
          v8::Exception::Error(error_message.As<v8::String>()));
      return;
    }

    if (maybe_return_value.IsEmpty())
      return;

    auto ret = PassValueToOtherContext(
        func_owning_context, calling_context,
        maybe_return_value.ToLocalChecked(), &object_cache,
        support_dynamic_properties, 0, BridgeErrorTarget::kDestination);
    if (ret.IsEmpty())
      return;
    info.GetReturnValue().Set(ret.ToLocalChecked());
  }
}