summaryrefslogtreecommitdiffstats
path: root/js/xpconnect/src/XPCSelfHostedShmem.cpp
blob: e5c8578ccdec0f974057acc72890484f52df27f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "XPCSelfHostedShmem.h"
#include "xpcprivate.h"

// static
mozilla::StaticRefPtr<xpc::SelfHostedShmem>
    xpc::SelfHostedShmem::sSelfHostedXdr;

NS_IMPL_ISUPPORTS(xpc::SelfHostedShmem, nsIMemoryReporter)

// static
xpc::SelfHostedShmem& xpc::SelfHostedShmem::GetSingleton() {
  MOZ_ASSERT_IF(!sSelfHostedXdr, NS_IsMainThread());

  if (!sSelfHostedXdr) {
    sSelfHostedXdr = new SelfHostedShmem;
  }

  return *sSelfHostedXdr;
}

void xpc::SelfHostedShmem::InitMemoryReporter() {
  mozilla::RegisterWeakMemoryReporter(this);
}

// static
void xpc::SelfHostedShmem::Shutdown() {
  MOZ_ASSERT(NS_IsMainThread());
  // NOTE: We cannot call UnregisterWeakMemoryReporter(sSelfHostedXdr) as the
  // service is shutdown at the time this call is made. In any cases, this would
  // already be done when the memory reporter got destroyed.
  sSelfHostedXdr = nullptr;
}

void xpc::SelfHostedShmem::InitFromParent(ContentType aXdr) {
  MOZ_ASSERT(XRE_IsParentProcess());
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(!mLen, "Shouldn't call this more than once");

  size_t len = aXdr.Length();
  auto shm = mozilla::MakeUnique<base::SharedMemory>();
  if (NS_WARN_IF(!shm->CreateFreezeable(len))) {
    return;
  }

  if (NS_WARN_IF(!shm->Map(len))) {
    return;
  }

  void* address = shm->memory();
  memcpy(address, aXdr.Elements(), aXdr.LengthBytes());

  base::SharedMemory roCopy;
  if (NS_WARN_IF(!shm->ReadOnlyCopy(&roCopy))) {
    return;
  }

  mMem = std::move(shm);
  mHandle = roCopy.TakeHandle();
  mLen = len;
}

bool xpc::SelfHostedShmem::InitFromChild(::base::SharedMemoryHandle aHandle,
                                         size_t aLen) {
  MOZ_ASSERT(!XRE_IsParentProcess());
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(!mLen, "Shouldn't call this more than once");

  auto shm = mozilla::MakeUnique<base::SharedMemory>();
  if (NS_WARN_IF(!shm->SetHandle(std::move(aHandle), /* read_only */ true))) {
    return false;
  }

  if (NS_WARN_IF(!shm->Map(aLen))) {
    return false;
  }

  // Note: mHandle remains empty, as content processes are not spawning more
  // content processes.
  mMem = std::move(shm);
  mLen = aLen;
  return true;
}

xpc::SelfHostedShmem::ContentType xpc::SelfHostedShmem::Content() const {
  if (!mMem) {
    MOZ_ASSERT(mLen == 0);
    return ContentType();
  }
  return ContentType(reinterpret_cast<uint8_t*>(mMem->memory()), mLen);
}

const mozilla::UniqueFileHandle& xpc::SelfHostedShmem::Handle() const {
  return mHandle;
}

NS_IMETHODIMP
xpc::SelfHostedShmem::CollectReports(nsIHandleReportCallback* aHandleReport,
                                     nsISupports* aData, bool aAnonymize) {
  // If this is the parent process, then we have a handle and this instance owns
  // the data and shares it with other processes, otherwise this is shared data.
  if (XRE_IsParentProcess()) {
    // This does not exactly report the amount of data mapped by the system,
    // but the space requested when creating the handle.
    MOZ_COLLECT_REPORT("explicit/js-non-window/shared-memory/self-hosted-xdr",
                       KIND_NONHEAP, UNITS_BYTES, mLen,
                       "Memory used to initialize the JS engine with the "
                       "self-hosted code encoded by the parent process.");
  }
  return NS_OK;
}