Backed out changeset 58f0722012cd (bug 1475415) for force-cargo-library-build bustages CLOSED TREE

This commit is contained in:
shindli 2018-09-24 19:37:49 +03:00
Родитель 8724a9004a
Коммит 87009004b2
69 изменённых файлов: 1 добавлений и 10568 удалений

35
Cargo.lock сгенерированный
Просмотреть файл

@ -900,7 +900,6 @@ dependencies = [
"encoding_glue 0.1.0",
"env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"geckoservo 0.0.1",
"ipdl_bindings 0.1.0",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"mozurl 0.0.1",
"mp4parse_capi 0.10.1",
@ -1040,23 +1039,6 @@ dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ipdl"
version = "0.1.0"
dependencies = [
"pipdl 0.1.0",
]
[[package]]
name = "ipdl_bindings"
version = "0.1.0"
dependencies = [
"ipdl 0.1.0",
"mfbt-maybe 0.1.0",
"nsstring 0.1.0",
"thin-vec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itertools"
version = "0.7.6"
@ -1323,10 +1305,6 @@ name = "memoffset"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "mfbt-maybe"
version = "0.1.0"
[[package]]
name = "miniz_oxide"
version = "0.1.2"
@ -1677,10 +1655,6 @@ dependencies = [
"siphasher 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pipdl"
version = "0.1.0"
[[package]]
name = "pkg-config"
version = "0.3.9"
@ -2316,14 +2290,6 @@ name = "thin-slice"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "thin-vec"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.3.5"
@ -3069,7 +3035,6 @@ dependencies = [
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
"checksum thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
"checksum thin-vec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "73fdf4b84c65a85168477b7fb6c498e0716bc9487fba24623389ea7f51708044"
"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
"checksum thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf947d192a9be60ef5131cc7a4648886ba89d712f16700ebbf80c8a69d05d48f"
"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"

Просмотреть файл

@ -7422,16 +7422,6 @@ nsGlobalWindowInner::MessageManager()
return mChromeFields.mMessageManager;
}
IPDL*
nsGlobalWindowInner::IPDL()
{
MOZ_ASSERT(IsChromeWindow());
if (!mChromeFields.mIPDL) {
mChromeFields.mIPDL = new class IPDL(this);
}
return mChromeFields.mIPDL;
}
ChromeMessageBroadcaster*
nsGlobalWindowInner::GetGroupMessageManager(const nsAString& aGroup)
{

Просмотреть файл

@ -37,7 +37,6 @@
#include "mozilla/dom/DOMPrefs.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/ChromeMessageBroadcaster.h"
#include "mozilla/dom/IPDL.h"
#include "mozilla/dom/NavigatorBinding.h"
#include "mozilla/dom/StorageEvent.h"
#include "mozilla/dom/StorageEventBinding.h"
@ -939,7 +938,6 @@ public:
void NotifyDefaultButtonLoaded(mozilla::dom::Element& aDefaultButton,
mozilla::ErrorResult& aError);
mozilla::dom::ChromeMessageBroadcaster* MessageManager();
mozilla::dom::IPDL* IPDL();
mozilla::dom::ChromeMessageBroadcaster* GetGroupMessageManager(const nsAString& aGroup);
void BeginWindowMove(mozilla::dom::Event& aMouseDownEvent,
mozilla::ErrorResult& aError);
@ -1491,8 +1489,6 @@ protected:
RefPtr<mozilla::dom::ChromeMessageBroadcaster> mMessageManager;
nsRefPtrHashtable<nsStringHashKey,
mozilla::dom::ChromeMessageBroadcaster> mGroupMessageManagers;
RefPtr<mozilla::dom::IPDL> mIPDL;
} mChromeFields;
// These fields are used by the inner and outer windows to prevent

Просмотреть файл

@ -1,14 +0,0 @@
include protocol PTest;
sync protocol PSubTest {
manager PTest;
both:
async AsyncMessage(int inNumber) returns(int outNumber);
parent:
sync SyncMessage(int inNumber) returns(int outNumber);
child:
async __delete__();
};

Просмотреть файл

@ -1,14 +0,0 @@
include protocol PSubTest;
sync protocol PTest {
manages PSubTest;
both:
async AsyncMessage(int inNumber) returns(int outNumber);
parent:
sync SyncMessage(int inNumber) returns(int outNumber);
child:
async PSubTest();
};

Просмотреть файл

@ -1 +0,0 @@
var IPDLGlob = new IPDL();

Просмотреть файл

@ -1,42 +0,0 @@
"use strict";
IPDLGlob.registerProtocol("PTest", "resource://test/PTest.ipdl");
IPDLGlob.registerProtocol("PSubTest", "resource://test/PSubTest.ipdl");
// Child process tests
async function run_test() {
IPDLGlob.registerTopLevelClass(TestChild);
// Note that we stop the test in the parent process test
}
class TestChild extends IPDLGlob.PTestChild {
allocPSubTest() {
return new SubTestChild();
}
async recvPSubTestConstructor(protocol) {
test_ipdlChildSendSyncMessage(protocol);
await test_ipdlChildSendAsyncMessage(protocol);
}
recvAsyncMessage(input) {
return input + 1;
}
}
class SubTestChild extends IPDLGlob.PSubTestChild {
recvAsyncMessage(input) {
return input + 1;
}
}
function test_ipdlChildSendSyncMessage(protocol) {
Assert.equal(protocol.sendSyncMessage(42), 43);
}
async function test_ipdlChildSendAsyncMessage(protocol) {
await protocol.sendAsyncMessage(42).then(res => {
Assert.equal(res, 43);
});
}

Просмотреть файл

@ -1,76 +0,0 @@
"use strict";
IPDLGlob.registerProtocol("PTest", "resource://test/PTest.ipdl");
IPDLGlob.registerProtocol("PSubTest", "resource://test/PSubTest.ipdl");
// Parent process test starting
function run_test() {
do_load_child_test_harness();
// Switch test termination to manual
do_test_pending();
do_get_idle();
IPDLGlob.registerTopLevelClass(TestParent);
// Load the child process test script
sendCommand('load("head_ipdl.js"); load("test_ipdl_child.js");', function() {
// Setup child protocol and run its tests
sendCommand("run_test();", async function() {
// Run parent tests
var protocol = IPDLGlob.getTopLevelInstances()[0];
try {
await test_ipdlParentSendAsyncMessage(protocol);
await test_ipdlParentSendPSubTestConstructor(protocol);
} catch (errMsg) {
do_test_finished();
throw new Error(errMsg);
}
// We're done, bye.
do_test_finished();
});
});
}
class TestParent extends IPDLGlob.PTestParent {
recvSyncMessage(input) {
return input + 1;
}
recvAsyncMessage(input) {
return input + 1;
}
allocPSubTest() {
return new SubTestParent();
}
}
class SubTestParent extends IPDLGlob.PSubTestParent {
recvSyncMessage(input) {
return input + 1;
}
recvAsyncMessage(input) {
return input + 1;
}
}
async function test_ipdlParentSendAsyncMessage(protocol) {
await protocol.sendAsyncMessage(42).then(res => {
equal(res, 43);
});
}
async function test_ipdlParentSendPSubTestConstructor(protocol) {
await protocol.sendPSubTestConstructor().then(async subprotocol => {
await subprotocol.sendAsyncMessage(42).then(res => {
equal(res, 43);
});
await subprotocol.send__delete__();
});
}

Просмотреть файл

@ -22,8 +22,6 @@ support-files =
isequalnode_data.xml
nodelist_data_1.xml
nodelist_data_2.xul
PTest.ipdl
PSubTest.ipdl
test_delete_range.xml
[test_bug553888.js]
@ -54,13 +52,6 @@ head = head_xml.js
[test_xmlserializer.js]
[test_cancelPrefetch.js]
[test_chromeutils_base64.js]
[test_ipdl_parent.js]
head = head_ipdl.js
skip-if = toolkit == 'android'
firefox-appdir = browser
[test_ipdl_child.js]
skip-if = true # Used by test_ipdl_parent only
head = head_ipdl.js
[test_generate_xpath.js]
head = head_xml.js
[test_js_dev_error_interceptor.js]

Просмотреть файл

@ -490,10 +490,6 @@ DOMInterfaces = {
'headerFile': 'DOMIntersectionObserver.h',
},
'IPDL': {
'implicitJSContext': [ 'registerProtocol']
},
'KeyEvent': {
'concrete': False
},

Просмотреть файл

@ -1,16 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*/
// UPDATE IPDL::sPropertyNames IF YOU ADD METHODS OR ATTRIBUTES HERE.
[ChromeConstructor, ChromeOnly, Exposed=(Window, System, Worker), NeedResolve]
interface IPDL {
void registerProtocol(DOMString protocolName, DOMString protocolURI, optional boolean eagerLoad = false);
void registerTopLevelClass(object classConstructor);
object getTopLevelInstance(optional unsigned long id);
sequence<object> getTopLevelInstances();
};

Просмотреть файл

@ -35,7 +35,6 @@ WEBIDL_FILES = [
'DominatorTree.webidl',
'HeapSnapshot.webidl',
'InspectorUtils.webidl',
'IPDL.webidl',
'IteratorResult.webidl',
'MatchGlob.webidl',
'MatchPattern.webidl',

Просмотреть файл

@ -62,7 +62,6 @@
#include "mozilla/ipc/PChildToParentStreamChild.h"
#include "mozilla/intl/LocaleService.h"
#include "mozilla/ipc/TestShellChild.h"
#include "mozilla/ipdl/ipc/PContentChildIPCInterface.h"
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
#include "mozilla/jsipc/PJavaScript.h"
#include "mozilla/layers/APZChild.h"
@ -2628,26 +2627,6 @@ ContentChild::RecvUpdateSharedData(const FileDescriptor& aMapFile,
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentChild::RecvAsyncMessageIPDL(const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessage,
const ClonedMessageData& aData,
AsyncMessageIPDLResolver&& aResolve)
{
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(
"ContentChild::RecvAsyncMessageIPDL", OTHER, aMessage);
if (mIPDLIPCInterface) {
nsTArray<StructuredCloneData> returnData;
auto res = mIPDLIPCInterface->RecvMessage(aProtocolName, aChannelId, aMessage, aData, &returnData);
aResolve(std::move(returnData));
return res;
}
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentChild::RecvGeolocationUpdate(nsIDOMGeoPosition* aPosition)
{
@ -3921,13 +3900,6 @@ ContentChild::GetSpecificMessageEventTarget(const Message& aMsg)
}
}
void
ContentChild::RegisterIPDLIPCInterface(
mozilla::ipdl::ipc::PContentChildIPCInterface* aIPDLIPCInterface)
{
mIPDLIPCInterface = aIPDLIPCInterface;
}
#ifdef NIGHTLY_BUILD
void
ContentChild::OnChannelReceivedMessage(const Message& aMsg)

Просмотреть файл

@ -64,12 +64,6 @@ class OptionalURIParams;
class URIParams;
}// namespace ipc
namespace ipdl {
namespace ipc {
class PContentChildIPCInterface;
} // namespace ipc
} // namespace ipdl
namespace dom {
namespace ipc {
@ -406,13 +400,6 @@ public:
const IPC::Principal& aPrincipal,
const ClonedMessageData& aData) override;
// See PContent.ipdl for doc.
virtual mozilla::ipc::IPCResult RecvAsyncMessageIPDL(const nsCString& aProtocol,
const uint32_t& aChannelId,
const nsCString& aMessage,
const ClonedMessageData& aData,
AsyncMessageIPDLResolver&& aResolve) override;
mozilla::ipc::IPCResult RecvRegisterStringBundles(nsTArray<StringBundleDescriptor>&& stringBundles) override;
mozilla::ipc::IPCResult RecvUpdateSharedData(const FileDescriptor& aMapFile,
@ -761,9 +748,6 @@ public:
}
#endif
void RegisterIPDLIPCInterface(
mozilla::ipdl::ipc::PContentChildIPCInterface* aIPDLIPCInterface);
private:
static void ForceKillTimerCallback(nsITimer* aTimer, void* aClosure);
void StartForceKillTimer();
@ -869,8 +853,6 @@ private:
mozilla::Atomic<bool> mShuttingDown;
mozilla::ipdl::ipc::PContentChildIPCInterface* mIPDLIPCInterface;
#ifdef NIGHTLY_BUILD
// NOTE: This member is atomic because it can be accessed from off-main-thread.
mozilla::Atomic<uint32_t> mPendingInputEvents;

Просмотреть файл

@ -77,7 +77,6 @@
#include "mozilla/ipc/PChildToParentStreamParent.h"
#include "mozilla/ipc/TestShellParent.h"
#include "mozilla/ipc/IPCStreamUtils.h"
#include "mozilla/ipdl/ipc/PContentParentIPCInterface.h"
#include "mozilla/intl/LocaleService.h"
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
#include "mozilla/layers/PAPZParent.h"
@ -2326,7 +2325,6 @@ ContentParent::ContentParent(ContentParent* aOpener,
, mIsRemoteInputEventQueueEnabled(false)
, mIsInputPriorityEventEnabled(false)
, mHangMonitorActor(nullptr)
, mIPDLIPCInterface(nullptr)
{
// Insert ourselves into the global linked list of ContentParent objects.
if (!sContentParents) {
@ -4008,23 +4006,6 @@ ContentParent::RecvSyncMessage(const nsString& aMsg,
aPrincipal, aRetvals);
}
mozilla::ipc::IPCResult
ContentParent::RecvSyncMessageIPDL(const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessage,
const ClonedMessageData& aData,
nsTArray<StructuredCloneData>* returnData)
{
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(
"ContentParent::RecvSyncMessageIPDL", OTHER, aMessage);
if (mIPDLIPCInterface) {
return mIPDLIPCInterface->RecvMessage(aProtocolName, aChannelId, aMessage, aData, returnData);
}
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentParent::RecvRpcMessage(const nsString& aMsg,
const ClonedMessageData& aData,
@ -4046,26 +4027,6 @@ ContentParent::RecvAsyncMessage(const nsString& aMsg,
aData);
}
mozilla::ipc::IPCResult
ContentParent::RecvAsyncMessageIPDL(const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessage,
const ClonedMessageData& aData,
AsyncMessageIPDLResolver&& aResolve)
{
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(
"ContentParent::RecvAsyncMessageIPDL", OTHER, aMessage);
if (mIPDLIPCInterface) {
nsTArray<StructuredCloneData> returnData;
auto res = mIPDLIPCInterface->RecvMessage(aProtocolName, aChannelId, aMessage, aData, &returnData);
aResolve(std::move(returnData));
return res;
}
return IPC_OK();
}
static int32_t
AddGeolocationListener(nsIDOMGeoPositionCallback* watcher,
nsIDOMGeoPositionErrorCallback* errorCallBack,
@ -6095,10 +6056,3 @@ ContentParent::RecvDetachBrowsingContext(const BrowsingContextId& aContextId,
return IPC_OK();
}
void
ContentParent::RegisterIPDLIPCInterface(
mozilla::ipdl::ipc::PContentParentIPCInterface* aIPDLIPCInterface)
{
mIPDLIPCInterface = aIPDLIPCInterface;
}

Просмотреть файл

@ -84,12 +84,6 @@ class ProtocolFuzzerHelper;
#endif
} // namespace ipc
namespace ipdl {
namespace ipc {
class PContentParentIPCInterface;
} // namespace ipc
} // namespace ipdl
namespace jsipc {
class PJavaScriptParent;
} // namespace jsipc
@ -1079,13 +1073,6 @@ private:
const IPC::Principal& aPrincipal,
nsTArray<StructuredCloneData>* aRetvals) override;
// See PContent.ipdl for doc.
virtual mozilla::ipc::IPCResult RecvSyncMessageIPDL(const nsCString& aProtocol,
const uint32_t& aChannelId,
const nsCString& aMessage,
const ClonedMessageData& aData,
nsTArray<StructuredCloneData>* returnData) override;
virtual mozilla::ipc::IPCResult RecvRpcMessage(const nsString& aMsg,
const ClonedMessageData& aData,
InfallibleTArray<CpowEntry>&& aCpows,
@ -1097,13 +1084,6 @@ private:
const IPC::Principal& aPrincipal,
const ClonedMessageData& aData) override;
// See PContent.ipdl for doc.
virtual mozilla::ipc::IPCResult RecvAsyncMessageIPDL(const nsCString& aProtocol,
const uint32_t& aChannelId,
const nsCString& aMessage,
const ClonedMessageData& aData,
AsyncMessageIPDLResolver&& aResolve) override;
virtual mozilla::ipc::IPCResult RecvAddGeolocationListener(const IPC::Principal& aPrincipal,
const bool& aHighAccuracy) override;
virtual mozilla::ipc::IPCResult RecvRemoveGeolocationListener() override;
@ -1291,10 +1271,6 @@ public:
bool CanCommunicateWith(ContentParentId aOtherProcess);
void RegisterIPDLIPCInterface(
mozilla::ipdl::ipc::PContentParentIPCInterface* aIPDLIPCInterface);
nsresult SaveRecording(nsIFile* aFile, bool* aRetval);
bool IsRecordingOrReplaying() const {
@ -1407,8 +1383,6 @@ private:
UniquePtr<mozilla::ipc::CrashReporterHost> mCrashReporter;
mozilla::ipdl::ipc::PContentParentIPCInterface* mIPDLIPCInterface;
static uint64_t sNextTabParentId;
static nsDataHashtable<nsUint64HashKey, TabParent*> sNextTabParents;
};

Просмотреть файл

@ -1,484 +0,0 @@
#include "mozilla/dom/IPDL.h"
#include "mozilla/dom/IPDLBinding.h"
#include "mozilla/ipdl/IPDLProtocol.h"
#include "mozilla/ipdl/IPDLProtocolInstance.h"
#include "mozilla/ipdl/ipc/PContentChildIPCInterface.h"
#include "mozilla/ipdl/ipc/PContentParentIPCInterface.h"
#include "nsReadableUtils.h"
#include "nsIObserverService.h"
#include "nsJSUtils.h"
#include "nsWrapperCacheInlines.h"
#include "mozilla/Services.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ContentChild.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_CLASS(IPDL)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IPDL)
tmp->mTopLevelClassConstructor = nullptr;
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParsedProtocolClassTable)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTopLevelParentInstances)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTopLevelChildInstance)
mozilla::DropJSObjects(tmp);
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IPDL)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParsedProtocolClassTable)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTopLevelParentInstances)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTopLevelChildInstance)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IPDL)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mTopLevelClassConstructor)
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(IPDL)
NS_IMPL_CYCLE_COLLECTING_RELEASE(IPDL)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IPDL)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
NS_INTERFACE_MAP_END
IPDL::IPDL(nsIGlobalObject* aParentObject)
: mParentObject(aParentObject)
, mChildInterface(nullptr)
{
mozilla::HoldJSObjects(this);
// Register to listen to new Content notifications.
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
os->AddObserver(this, "ipc:content-created", /* ownsWeak */ true);
}
}
/* virtual */
IPDL::~IPDL() {}
void
IPDL::RegisterTopLevelClass(JSContext* aCx,
JS::Handle<JSObject*> aClassConstructor)
{
mTopLevelClassConstructor = aClassConstructor;
Sequence<JS::HandleValue> emptyArray;
// When we register the top level class, we want to trigger a content creation
// event for all existing content protocol instances.
for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
NewTopLevelProtocolParent(aCx, emptyArray, cp);
}
if (ContentChild::GetSingleton()) {
NewTopLevelProtocolChild(aCx, emptyArray);
}
}
void
IPDL::GetTopLevelInstance(JSContext* aCx,
const Optional<uint32_t>& aId,
JS::MutableHandle<JSObject*> aRetval)
{
// If we got an ID, then we return a parent instance, otherwise we return the
// child instance.
if (aId.WasPassed() && !ContentChild::GetSingleton()) {
if (auto instance = mTopLevelParentInstances.GetWeak(aId.Value())) {
aRetval.set(instance->GetInstanceObject());
} else {
JS_ReportErrorUTF8(aCx, "Unknown parent instance ID");
return;
}
} else {
if (mTopLevelChildInstance) {
aRetval.set(mTopLevelChildInstance->GetInstanceObject());
} else {
JS_ReportErrorUTF8(aCx, "No top level child instance");
return;
}
}
}
void
IPDL::GetTopLevelInstances(JSContext* aCx, nsTArray<JSObject*>& aRetval)
{
// Return all instances depending on the side we're on.
if (mTopLevelChildInstance) {
aRetval.AppendElement(mTopLevelChildInstance->GetInstanceObject());
} else {
for (auto i = mTopLevelParentInstances.Iter(); !i.Done(); i.Next()) {
aRetval.AppendElement(i.Data()->GetInstanceObject());
}
}
}
void
IPDL::RegisterProtocol(JSContext* aCx,
const nsAString& aProtocolName,
const nsAString& aProtocolURI,
bool aEagerLoad)
{
mProtocolURIs.Put(aProtocolName, nsString(aProtocolURI));
if (aEagerLoad) {
JS::RootedObject wrapper(aCx, GetWrapper());
auto lookup = mParsedProtocolClassTable.LookupForAdd(aProtocolName);
if (!lookup) {
RefPtr<ipdl::IPDLProtocol> newIPDLProtocol = NewIPDLProtocol(aProtocolName, wrapper, aCx);
if (!newIPDLProtocol) {
lookup.OrRemove();
return;
}
lookup.OrInsert([&newIPDLProtocol]() { return std::move(newIPDLProtocol); });
}
}
}
bool
IPDL::DoResolve(JSContext* aCx,
JS::Handle<JSObject*> aObj,
JS::Handle<jsid> aId,
JS::MutableHandle<JS::PropertyDescriptor> aRv)
{
// If it's not an ID, skip this.
if (!JSID_IS_STRING(aId)) {
return true;
}
// Get the property name.
nsAutoJSString propertyName;
if (!propertyName.init(aCx, JSID_TO_STRING(aId))) {
return true;
}
// Check it's not a real existing property.
if (IsRealProperty(propertyName)) {
return true;
}
// Otherwise, resolve the protocol property.
return ResolveProtocolProperty(propertyName, aObj, aCx, aRv);
}
void
IPDL::GetOwnPropertyNames(JSContext* aCx,
JS::AutoIdVector& aNames,
bool aEnumerableOnly,
mozilla::ErrorResult& aRv)
{
if (aEnumerableOnly) {
return;
}
// We want to return the real properties + the existing protocol names we
// already parsed.
if (!aNames.initCapacity(mParsedProtocolIDs.Capacity() +
sPropertyNamesLength)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
// We add the protocol names.
JS::RootedId id(aCx);
for (auto& name : mParsedProtocolIDs) {
if (!JS_CharsToId(aCx, JS::TwoByteChars(name.get(), name.Length()), &id)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
if (!aNames.append(id)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
}
// We add the real properties.
for (auto& propertyName : sPropertyNames) {
if (!JS_CharsToId(
aCx,
JS::TwoByteChars(propertyName.get(), propertyName.Length()),
&id)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
if (!aNames.append(id)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
}
}
nsISupports*
IPDL::GetParentObject()
{
return mParentObject;
}
/* static */ bool
IPDL::MayResolve(jsid aId)
{
return true;
}
/* virtual */ JSObject*
IPDL::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto)
{
return IPDL_Binding::Wrap(aCx, this, aGivenProto);
}
/* static */ already_AddRefed<IPDL>
IPDL::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
RefPtr<IPDL> ipdl = new IPDL(global);
return ipdl.forget();
}
bool
IPDL::IsRealProperty(const nsAString& aPropertyName)
{
// Simple loop through the real property names.
for (auto& propertyName : sPropertyNames) {
if (aPropertyName.Equals(propertyName)) {
return true;
}
}
return false;
}
bool
IPDL::ResolveProtocolProperty(const nsString& aProtocolPropertyName,
JS::Handle<JSObject*> aObj,
JSContext* aCx,
JS::MutableHandle<JS::PropertyDescriptor> aRv)
{
// If we haven't parsed this protocol yet, do it and create a new IPDLProtocol
// object.
auto ipdlProtocol = mParsedProtocolClassTable.LookupForAdd(aProtocolPropertyName);
if (!ipdlProtocol) {
RefPtr<ipdl::IPDLProtocol> newIPDLProtocol = NewIPDLProtocol(aProtocolPropertyName, aObj, aCx);
if (!newIPDLProtocol) {
ipdlProtocol.OrRemove();
return false;
}
ipdlProtocol.OrInsert([&newIPDLProtocol]() { return std::move(newIPDLProtocol); });
}
aRv.object().set(aObj);
aRv.value().setObject(*ipdlProtocol.Data()->GetProtocolClassConstructor());
aRv.setAttributes(0);
aRv.setGetter(nullptr);
aRv.setSetter(nullptr);
return true;
}
Maybe<ipdl::IPDLSide>
IPDL::GetProtocolSide(const nsAString& aProtocolName)
{
NS_NAMED_LITERAL_STRING(parentLiteral, "Parent");
NS_NAMED_LITERAL_STRING(childLiteral, "Child");
// Find the parent suffix.
if (StringEndsWith(aProtocolName, parentLiteral)) {
return Some(ipdl::IPDLSide::Parent);
}
// Find the child suffix.
if (StringEndsWith(aProtocolName, childLiteral)) {
return Some(ipdl::IPDLSide::Child);
}
return Nothing();
}
void
IPDL::StripParentSuffix(const nsAString& aProtocolName, nsAString& aRetVal)
{
NS_NAMED_LITERAL_STRING(parentLiteral, "Parent");
aRetVal = Substring(
aProtocolName, 0, aProtocolName.Length() - parentLiteral.Length());
}
void
IPDL::StripChildSuffix(const nsAString& aProtocolName, nsAString& aRetVal)
{
NS_NAMED_LITERAL_STRING(childLiteral, "Child");
aRetVal =
Substring(aProtocolName, 0, aProtocolName.Length() - childLiteral.Length());
}
ipdl::ipc::PContentChildIPCInterface*
IPDL::GetOrInitChildInterface()
{
if (!mChildInterface && ContentChild::GetSingleton()) {
mChildInterface.reset(new ipdl::ipc::PContentChildIPCInterface(
this, ContentChild::GetSingleton()));
}
return mChildInterface.get();
}
already_AddRefed<ipdl::IPDLProtocol>
IPDL::NewIPDLProtocol(const nsAString& aProtocolName,
JS::Handle<JSObject*> aObj,
JSContext* aCx)
{
auto ipdlSide = GetProtocolSide(aProtocolName);
nsAutoString unsidedProtocolName;
// Assign a name depending on the protocol side.
if (!ipdlSide) {
return nullptr;
}
switch (*ipdlSide) {
case ipdl::IPDLSide::Parent:
StripParentSuffix(aProtocolName, unsidedProtocolName);
break;
case ipdl::IPDLSide::Child:
GetOrInitChildInterface();
StripChildSuffix(aProtocolName, unsidedProtocolName);
break;
default:
return nullptr;
}
if (!mParsedProtocolIDs.AppendElement(aProtocolName)) {
return nullptr;
}
if (!mProtocolURIs.Contains(unsidedProtocolName)) {
return nullptr;
}
// Create our new IPDLProtocol object and return it.
auto newIPDLProtocol = MakeRefPtr<ipdl::IPDLProtocol>(
this,
*ipdlSide,
NS_ConvertUTF16toUTF8(mProtocolURIs.Get(unsidedProtocolName)),
xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx)),
aObj,
aCx);
// Some error during parsing or construction.
if (!newIPDLProtocol->GetProtocolClassConstructor()) {
return nullptr;
}
return newIPDLProtocol.forget();
}
JSObject*
IPDL::NewTopLevelProtocolParent(JSContext* aCx,
const Sequence<JS::Handle<JS::Value>>& aArgs,
ContentParent* aCp)
{
// If we don't already have an IPCInterface for this content parent, create
// it.
auto parentInterface = mParentInterfaces.LookupForAdd(aCp->ChildID()).OrInsert([this, aCp]() {
return new ipdl::ipc::PContentParentIPCInterface(this, aCp);
});
JS::RootedObject constructor(aCx, mTopLevelClassConstructor.get());
// Prepare the arguments into a vector.
JS::AutoValueVector argVector(aCx);
if (!argVector.initCapacity(aArgs.Length())) {
JS_ReportErrorUTF8(aCx, "Couldn't initialize argument vector");
return nullptr;
}
for (auto& arg : aArgs) {
if (!argVector.append(arg.get())) {
JS_ReportErrorUTF8(aCx, "Couldn't add argument to arg vector");
return nullptr;
}
}
// Create the protocol instance, add the IPCInterface to the
// IPDLProtocolInstance...
JS::RootedObject topLevelProtocol(aCx, JS_New(aCx, constructor, argVector));
auto* instance =
static_cast<ipdl::IPDLProtocolInstance*>(JS_GetPrivate(topLevelProtocol.get()));
if (!instance) {
JS_ReportErrorUTF8(aCx, "Couldn't get protocol instance object from private date field");
return nullptr;
}
instance->SetIPCInterface(parentInterface);
mTopLevelParentInstances.Put(aCp->ChildID(), instance);
return topLevelProtocol;
}
JSObject*
IPDL::NewTopLevelProtocolChild(JSContext* aCx,
const Sequence<JS::Handle<JS::Value>>& aArgs)
{
JS::RootedObject constructor(aCx, mTopLevelClassConstructor.get());
// Prepare the arguments into a vector.
JS::AutoValueVector argVector(aCx);
if (!argVector.initCapacity(aArgs.Length())) {
JS_ReportErrorUTF8(aCx, "Couldn't initialize argument vector");
return nullptr;
}
for (auto& arg : aArgs) {
if (!argVector.append(arg.get())) {
JS_ReportErrorUTF8(aCx, "Couldn't add argument to arg vector");
return nullptr;
}
}
// Create the protocol instance, add the IPCInterface to the
// IPDLProtocolInstance...
JS::RootedObject topLevelProtocol(aCx, JS_New(aCx, constructor, argVector));
auto* instance =
static_cast<ipdl::IPDLProtocolInstance*>(JS_GetPrivate(topLevelProtocol.get()));
if (!instance) {
JS_ReportErrorUTF8(aCx, "Couldn't get protocol instance object from private date field");
return nullptr;
}
instance->SetIPCInterface(GetOrInitChildInterface());
mTopLevelChildInstance = instance;
return topLevelProtocol;
}
NS_IMETHODIMP
IPDL::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
{
nsDependentCString topic(aTopic);
if (topic.EqualsLiteral("ipc:content-created")) {
nsCOMPtr<nsIContentParent> cp = do_QueryInterface(aSubject);
AutoEntryScript aes(mParentObject, "New Content Parent");
NewTopLevelProtocolParent(
aes.cx(), Sequence<JS::HandleValue>(), cp->AsContentParent());
}
return NS_OK;
}
constexpr nsLiteralString IPDL::sPropertyNames[];
constexpr size_t IPDL::sPropertyNamesLength;
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -1,154 +0,0 @@
/* -*- 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 https://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_IPDL__
#define mozilla_dom_IPDL__
#include "nsClassHashtable.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIObserver.h"
#include "nsRefPtrHashtable.h"
#include "nsDataHashtable.h"
#include "nsWrapperCache.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/HoldDropJSObjects.h"
class nsIGlobalObject;
namespace mozilla {
namespace ipdl {
class IPDLProtocol;
class IPDLProtocolInstance;
enum class IPDLSide : bool;
namespace ipc {
class PContentParentIPCInterface;
class PContentChildIPCInterface;
} // ipc
} // ipdl
namespace dom {
class ContentParent;
class IPDL
: public nsIObserver
, public nsWrapperCache
{
protected:
virtual ~IPDL();
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IPDL)
NS_DECL_NSIOBSERVER
explicit IPDL(nsIGlobalObject* aParentObject);
static already_AddRefed<IPDL> Constructor(const GlobalObject& aGlobal,
ErrorResult& aRv);
void SetupContentParent();
void RegisterProtocol(JSContext* aCx, const nsAString& aProtocolName, const nsAString& aProtocolURI, bool aEagerLoad);
void RegisterTopLevelClass(JSContext* aCx,
JS::Handle<JSObject*> aClassConstructor);
void CreateTopLevelInstance(JSContext* aCx,
const Sequence<JS::Handle<JS::Value>>& aArgs);
void GetTopLevelInstance(JSContext* aCx,
const Optional<uint32_t>& aId,
JS::MutableHandle<JSObject*> aRetval);
void GetTopLevelInstances(JSContext* aCx,
nsTArray<JSObject*>& aRetval);
bool DoResolve(JSContext* aCx,
JS::Handle<JSObject*> aObj,
JS::Handle<jsid> aId,
JS::MutableHandle<JS::PropertyDescriptor> aRv);
void GetOwnPropertyNames(JSContext* aCx,
JS::AutoIdVector& aNames,
bool aEnumerableOnly,
ErrorResult& aRv);
nsISupports* GetParentObject();
nsIGlobalObject* GetGlobalObject() { return mParentObject; }
static bool MayResolve(jsid aId);
virtual JSObject* WrapObject(JSContext* aCx,
JS::HandleObject aGivenProto) override;
ipdl::ipc::PContentParentIPCInterface* GetParentInterface(uint32_t aId)
{
return mParentInterfaces.Get(aId);
}
ipdl::ipc::PContentChildIPCInterface* GetChildInterface()
{
return mChildInterface.get();
}
JSObject* NewTopLevelProtocolParent(
JSContext* aCx,
const Sequence<JS::Handle<JS::Value>>& aArgs,
ContentParent* aCp);
JSObject* NewTopLevelProtocolChild(
JSContext* aCx,
const Sequence<JS::Handle<JS::Value>>& aArgs);
protected:
bool IsRealProperty(const nsAString& aPropertyName);
bool ResolveProtocolProperty(const nsString& aProtocolPropertyName,
JS::Handle<JSObject*> aObj,
JSContext* aCx,
JS::MutableHandle<JS::PropertyDescriptor> aRv);
Maybe<ipdl::IPDLSide> GetProtocolSide(const nsAString& aProtocolName);
void StripParentSuffix(const nsAString& aProtocolName, nsAString& aRetVal);
void StripChildSuffix(const nsAString& aProtocolName, nsAString& aRetVal);
ipdl::ipc::PContentChildIPCInterface* GetOrInitChildInterface();
already_AddRefed<ipdl::IPDLProtocol> NewIPDLProtocol(
const nsAString& aProtocolName,
JS::Handle<JSObject*> aObj,
JSContext* aCx);
typedef nsRefPtrHashtable<nsStringHashKey, ipdl::IPDLProtocol>
ProtocolClassTable;
ProtocolClassTable mParsedProtocolClassTable;
nsTArray<nsString> mParsedProtocolIDs;
nsIGlobalObject* MOZ_NON_OWNING_REF mParentObject;
nsClassHashtable<nsUint32HashKey, ipdl::ipc::PContentParentIPCInterface>
mParentInterfaces;
UniquePtr<ipdl::ipc::PContentChildIPCInterface> mChildInterface;
nsRefPtrHashtable<nsUint32HashKey, ipdl::IPDLProtocolInstance>
mTopLevelParentInstances;
RefPtr<ipdl::IPDLProtocolInstance> mTopLevelChildInstance;
JS::Heap<JSObject*> mTopLevelClassConstructor;
nsDataHashtable<nsStringHashKey, nsString> mProtocolURIs;
static constexpr const nsLiteralString sPropertyNames[] = {NS_LITERAL_STRING("registerTopLevelClass"), NS_LITERAL_STRING("getTopLevelInstance"), NS_LITERAL_STRING("getTopLevelInstances"), NS_LITERAL_STRING("registerProtocol")};
static constexpr size_t sPropertyNamesLength = ArrayLength(sPropertyNames);
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_IPDL__

Просмотреть файл

@ -826,14 +826,6 @@ parent:
CpowEntry[] aCpows, Principal aPrincipal)
returns (StructuredCloneData[] retval);
/**
* Send an IPDL sync message with args packed as a JS array in the input
* and the output ClonedMessageData.
*/
sync SyncMessageIPDL(nsCString aProtocolName, uint32_t aChannelId,
nsCString aMessage, ClonedMessageData aData)
returns (StructuredCloneData[] retval);
nested(inside_sync) sync RpcMessage(nsString aMessage, ClonedMessageData aData,
CpowEntry[] aCpows, Principal aPrincipal)
returns (StructuredCloneData[] retval);
@ -1206,17 +1198,9 @@ parent:
async DetachBrowsingContext(BrowsingContextId aContextId,
bool aMoveToBFCache);
both:
async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
Principal aPrincipal, ClonedMessageData aData);
/**
* Send an IPDL async message with args packed as a JS array in the input
* and the output ClonedMessageData.
*/
async AsyncMessageIPDL(nsCString aProtocol, uint32_t aChannelId,
nsCString aMessage, ClonedMessageData aData)
returns (StructuredCloneData[] retval);
/**
* Notify `push-subscription-modified` observers in the parent and child.
*/

Просмотреть файл

@ -40,7 +40,6 @@ EXPORTS.mozilla.dom += [
'ContentProcessManager.h',
'CPOWManagerGetter.h',
'FilePickerParent.h',
'IPDL.h',
'MemoryReportRequest.h',
'nsIContentChild.h',
'nsIContentParent.h',
@ -91,7 +90,6 @@ UNIFIED_SOURCES += [
# ContentChild.cpp cannot be compiled in unified mode on linux due to Time conflict
SOURCES += [
'ContentChild.cpp',
'IPDL.cpp',
'ProcessHangMonitor.cpp',
]

Просмотреть файл

@ -440,9 +440,6 @@ partial interface Window {
[Func="nsGlobalWindowInner::IsPrivilegedChromeWindow"]
readonly attribute ChromeMessageBroadcaster messageManager;
[Func="nsGlobalWindowInner::IsPrivilegedChromeWindow"]
readonly attribute IPDL IPDL;
/**
* Returns the message manager identified by the given group name that
* manages all frame loaders belonging to that group.

Просмотреть файл

@ -848,8 +848,6 @@ description = test only
description = test only
[PContent::SyncMessage]
description =
[PContent::SyncMessageIPDL]
description =
[PContent::CreateChildProcess]
description =
[PContent::BridgeToChildProcess]

Просмотреть файл

@ -1,12 +0,0 @@
[package]
name = "ipdl"
version = "0.1.0"
authors = ["Tristan Bourvon <tristanbourvon@gmail.com>", "Andrew McCreight <continuation@gmail.com>"]
license = "MPL-2.0"
[dependencies]
pipdl = { path = "../pipdl" }
[lib]
name = "ipdl"
path = "src/lib.rs"

Просмотреть файл

@ -1,5 +0,0 @@
# ipdl-rs
Code taken from https://github.com/mystor/pipdl-rs has been written by Nika Layzell
Code taken from https://github.com/amccreight/ipdl_parser has been written by Andrew McCreight

Просмотреть файл

@ -1,58 +0,0 @@
#!/usr/bin/python3
# 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/.
# Test command generator for the IPDL parser.
# 1. Add the following code to ipc/ipdl/ipdl.py, do a build, and copy
# the output from the build, from INCLUDES to DONE, somewhere:
#
# print "INCLUDES"
# for i in includedirs:
# print i
# print "FILES"
# for f in files:
# print f
# print "DONE"
# 2. Adjust leading_text_example as necessary, if the log timestamp
# stuff has changed.
# 3. Run this script on the output from step 1. This should produce a
# command to run cargo with all of the files from step 1. You can run
# it with bash or whatever.
import sys
# Used to decide how many characters to chop off the start.
leading_text_example = " 0:02.39 "
in_include = False
in_files = False
start_trim = len(leading_text_example)
print("cargo run --"),
for line in sys.stdin:
line = line [start_trim:-1]
if line.endswith("INCLUDES"):
in_include = True
continue
if line.endswith("FILES"):
assert in_include
in_include = False
in_files = True
continue
if line.endswith("DONE"):
assert in_files
exit(0)
if in_include:
print("-I", line),
elif in_files:
print(line),
else:
assert False

Просмотреть файл

@ -1,285 +0,0 @@
/* 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/. */
use std::fmt;
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct QualifiedId {
pub base_id: Identifier,
pub quals: Vec<String>,
}
impl QualifiedId {
pub fn new(base: Identifier) -> QualifiedId {
QualifiedId { base_id: base, quals: Vec::new() }
}
pub fn qualify(mut self, id: Identifier) -> QualifiedId {
self.quals.push(self.base_id.id);
self.base_id = id;
self
}
pub fn new_from_iter<'a, I> (mut ids: I) -> QualifiedId
where I: Iterator<Item=&'a str>
{
let loc = Location { file_name: String::from("<builtin>"), lineno: 0, colno: 0 };
let mut qual_id = QualifiedId::new(Identifier::new(String::from(ids.next().expect("Empty iterator when creating QID")), loc.clone()));
for i in ids {
qual_id = qual_id.qualify(Identifier::new(String::from(i), loc.clone()));
}
qual_id
}
pub fn short_name(&self) -> String {
self.base_id.to_string()
}
pub fn full_name(&self) -> Option<String> {
if self.quals.is_empty() {
None
} else {
Some(self.to_string())
}
}
pub fn loc(&self) -> &Location {
&self.base_id.loc
}
}
impl fmt::Display for QualifiedId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for q in &self.quals {
try!(write!(f, "{}::", q));
}
write!(f, "{}", self.base_id)
}
}
#[derive(Debug)]
pub struct TypeSpec {
pub spec: QualifiedId,
pub array: bool,
pub nullable: bool,
}
impl TypeSpec {
pub fn new(spec: QualifiedId) -> TypeSpec {
TypeSpec { spec: spec, array: false, nullable: false }
}
pub fn loc(&self) -> &Location {
self.spec.loc()
}
}
#[derive(Debug)]
pub struct Param {
pub name: Identifier,
pub type_spec: TypeSpec,
}
#[derive(Debug)]
pub struct StructField {
pub type_spec: TypeSpec,
pub name: Identifier,
}
#[derive(Clone, Debug)]
pub struct Namespace {
pub name: Identifier,
pub namespaces: Vec<String>,
}
impl Namespace {
pub fn qname(&self) -> QualifiedId {
QualifiedId { base_id: self.name.clone(), quals: self.namespaces.clone() }
}
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Compress {
None,
Enabled,
All,
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum SendSemantics {
Async,
Sync,
Intr,
}
impl SendSemantics {
pub fn is_async(&self) -> bool {
self == &SendSemantics::Async
}
pub fn is_sync(&self) -> bool {
self == &SendSemantics::Sync
}
pub fn is_intr(&self) -> bool {
self == &SendSemantics::Intr
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub enum Nesting {
None,
InsideSync,
InsideCpow,
}
impl Nesting {
pub fn is_none(&self) -> bool {
self == &Nesting::None
}
pub fn inside_sync(&self) -> bool {
self == &Nesting::InsideSync
}
pub fn inside_cpow(&self) -> bool {
self == &Nesting::InsideCpow
}
}
#[derive(Debug, Clone, Copy)]
pub enum Priority {
Normal,
High,
Input,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Direction {
ToParent,
ToChild,
ToParentOrChild,
}
impl Direction {
pub fn is_to_child(&self) -> bool {
self == &Direction::ToChild
}
pub fn is_both(&self) -> bool {
self == &Direction::ToParentOrChild
}
}
#[derive(Debug, Clone)]
pub struct Location {
pub file_name: String,
pub lineno: usize,
pub colno: usize,
}
impl fmt::Display for Location {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}:{}:{}", self.file_name, self.lineno, self.colno)
}
}
#[derive(Debug, Clone)]
pub struct Identifier {
pub id: String,
pub loc: Location,
}
impl Identifier {
pub fn new(name: String, loc: Location) -> Identifier {
Identifier {
id: name,
loc: loc,
}
}
}
impl fmt::Display for Identifier {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.id)
}
}
#[derive(Debug)]
pub struct MessageDecl {
pub name: Identifier,
pub send_semantics: SendSemantics,
pub nested: Nesting,
pub prio: Priority,
pub direction: Direction,
pub in_params: Vec<Param>,
pub out_params: Vec<Param>,
pub compress: Compress,
pub verify: bool,
}
#[derive(Debug)]
pub struct Protocol {
pub send_semantics: SendSemantics,
pub nested: Nesting,
pub managers: Vec<Identifier>,
pub manages: Vec<Identifier>,
pub messages: Vec<MessageDecl>,
}
#[derive(Debug)]
pub enum CxxTypeKind {
Struct,
Class,
}
#[derive(Debug)]
pub struct UsingStmt {
pub cxx_type: TypeSpec,
pub header: String,
pub kind: Option<CxxTypeKind>,
pub refcounted: bool,
}
#[derive(Clone, Debug, PartialEq)]
pub enum FileType {
Protocol,
Header,
}
impl FileType {
pub fn from_file_path(file_path: &str) -> Option<FileType> {
if let Some(e) = file_path.rsplit('.').next() {
if e == "ipdlh" {
Some(FileType::Header)
} else {
Some(FileType::Protocol)
}
} else {
None
}
}
}
// Translation unit identifier.
pub type TUId = i32;
#[derive(Debug)]
pub struct TranslationUnit {
pub namespace: Namespace,
pub file_type: FileType,
pub file_name: String,
pub cxx_includes: Vec<String>,
pub includes: Vec<TUId>,
pub using: Vec<UsingStmt>,
pub structs: Vec<(Namespace, Vec<StructField>)>,
pub unions: Vec<(Namespace, Vec<TypeSpec>)>,
pub protocol: Option<(Namespace, Protocol)>,
}
pub struct AST {
pub main_tuid: TUId,
pub translation_units: HashMap<TUId, TranslationUnit>,
}

Просмотреть файл

@ -1,68 +0,0 @@
/* 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/. */
use ast::Location;
use pipdl;
use std::error::Error;
use std::fmt;
fn error_msg(loc: &Location, err: &str) -> String {
format!("{}: error: {}", loc, err)
}
#[must_use]
pub struct Errors {
errors: Vec<String>,
}
impl From<pipdl::Error> for Errors {
fn from(error: pipdl::Error) -> Self {
Errors::one(
&Location {
file_name: error.span().start.file,
lineno: error.span().start.line,
colno: error.span().start.col,
},
error.description(),
)
}
}
impl fmt::Display for Errors {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.errors.join("\n"))
}
}
impl Errors {
pub fn none() -> Errors {
Errors { errors: Vec::new() }
}
pub fn one(loc: &Location, err: &str) -> Errors {
Errors {
errors: vec![error_msg(&loc, &err)],
}
}
pub fn append(&mut self, mut other: Errors) {
self.errors.append(&mut other.errors);
}
pub fn append_one(&mut self, loc: &Location, other: &str) {
self.errors.push(error_msg(&loc, &other));
}
pub fn to_result(&self) -> Result<(), String> {
if self.errors.is_empty() {
Ok(())
} else {
Err(self.errors.join("\n"))
}
}
pub fn is_empty(&self) -> bool {
self.errors.is_empty()
}
}

Просмотреть файл

@ -1,12 +0,0 @@
/* 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/. */
#![allow(unknown_lints)]
extern crate pipdl;
pub mod ast;
mod errors;
pub mod parser;
mod passes;

Просмотреть файл

@ -1,114 +0,0 @@
/* 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/. */
use pipdl;
use passes::include_resolution::IncludeResolver;
use passes::parsetree_to_tu::ParseTreeToTU;
use passes::type_check;
use errors;
use std::collections::HashMap;
use std::hash::Hash;
use std::str;
use std::path::PathBuf;
use ast::{Location, AST};
pub trait OwnedSourceBuffer: Drop + AsRef<[u8]> {
fn to_utf8(&self) -> &str;
}
impl<T> OwnedSourceBuffer for T
where
T: Drop + AsRef<[u8]>,
{
fn to_utf8(&self) -> &str {
str::from_utf8(self.as_ref()).unwrap()
}
}
pub trait FileURI: Clone + Eq + Hash {
fn resolve_relative_path(&self, relative_path: &str) -> Result<Self, ()>;
fn to_utf8(&self) -> &str;
}
impl FileURI for PathBuf {
fn resolve_relative_path(&self, relative_path: &str) -> Result<Self, ()> {
let mut new_path = self.clone();
new_path.push(relative_path);
new_path.canonicalize().map_err(|_| ())
}
fn to_utf8(&self) -> &str {
self.to_str().unwrap()
}
}
#[derive(Clone)]
pub struct ParseTree<T>
where
T: FileURI,
{
pub translation_unit: pipdl::Spanned<pipdl::TranslationUnit>,
pub file_path: T,
}
pub fn parse_file<F: Fn(&str) -> Result<Box<OwnedSourceBuffer>, ()>, T: FileURI>(
file_path: &T,
source_string_loader: &mut F,
) -> Result<ParseTree<T>, errors::Errors> {
let file_path_str = file_path.to_utf8();
let file_text = source_string_loader(file_path_str).map_err(|()| {
errors::Errors::one(
&Location {
file_name: file_path_str.to_owned(),
lineno: 0,
colno: 0,
},
"Error loading source string",
)
})?;
let parse_tree = ParseTree {
translation_unit: pipdl::parse(file_text.to_utf8(), file_path_str)?,
file_path: file_path.clone(),
};
Ok(parse_tree)
}
pub fn parse<F: Fn(&str) -> Result<Box<OwnedSourceBuffer>, ()>, T: FileURI>(
file_path: &T,
include_dirs: &[T],
mut source_string_loader: F,
) -> Result<AST, errors::Errors> {
let parse_tree = parse_file(file_path, &mut source_string_loader)?;
let mut include_resolver = IncludeResolver::new(include_dirs);
let (main_tuid, result) = include_resolver.resolve_includes(parse_tree, source_string_loader)?;
let parsetree_to_translation_unit = ParseTreeToTU::new(&include_resolver);
let ast = AST {
main_tuid,
translation_units: {
result
.into_iter()
.map(|(tuid, parse_tree)| {
Ok((
tuid,
parsetree_to_translation_unit.parsetree_to_translation_unit(parse_tree)?,
))
})
.collect::<Result<HashMap<_, _>, errors::Errors>>()?
},
};
type_check::check(&ast.translation_units)?;
Ok(ast)
}

Просмотреть файл

@ -1,205 +0,0 @@
/* 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/. */
use ast::{Location, TUId};
use errors::Errors;
use parser::{parse_file, FileURI, OwnedSourceBuffer, ParseTree};
use std::collections::{HashMap, HashSet};
pub struct IncludeResolver<'a, T: 'a>
where
T: FileURI,
{
include_dirs: &'a [T],
include_files: HashMap<String, T>,
id_file_map: TUIdFileMap<T>,
}
impl<'a, T> IncludeResolver<'a, T>
where
T: FileURI,
{
pub fn new(include_dirs: &'a [T]) -> IncludeResolver<'a, T> {
IncludeResolver {
include_dirs,
include_files: HashMap::new(),
id_file_map: TUIdFileMap::new(),
}
}
pub fn get_include(&self, include_name: &str) -> Option<TUId> {
match self.include_files.get(include_name) {
Some(ref path) => self.id_file_map.get_tuid(path),
None => None,
}
}
pub fn resolve_include<'b>(&'b mut self, include_name: &str) -> Option<TUId> {
if let Some(ref include_file_path) = self.include_files.get(include_name) {
return Some(self.id_file_map.resolve_file_name(include_file_path));
}
// XXX The Python parser also checks '' for some reason.
for include_dir in self.include_dirs {
let mut new_include_path = include_dir.clone();
new_include_path = match new_include_path.resolve_relative_path(include_name) {
Ok(inc_path) => inc_path,
Err(_) => continue,
};
let new_id = self.id_file_map.resolve_file_name(&new_include_path);
self.include_files
.insert(String::from(include_name), new_include_path);
return Some(new_id);
}
None
}
fn print_include_context(include_context: &[T]) {
for path in include_context {
println!(" in file included from `{}':", path.to_utf8());
}
}
#[allow(needless_pass_by_value)]
pub fn resolve_includes<F: Fn(&str) -> Result<Box<OwnedSourceBuffer>, ()>>(
&mut self,
parse_tree: ParseTree<T>,
mut source_string_loader: F,
) -> Result<(TUId, HashMap<TUId, ParseTree<T>>), Errors> {
let mut work_list: Vec<(T, Vec<T>)> = Vec::new();
let mut parsed_files = HashMap::new();
let mut visited_files = HashSet::new();
let resolved_path = parse_tree
.file_path
.resolve_relative_path("")
.map_err(|()| {
Errors::one(
&Location {
file_name: parse_tree.file_path.to_utf8().to_owned(),
lineno: 0,
colno: 0,
},
"Could not resolve file path",
)
})?;
let file_id = self.id_file_map.resolve_file_name(&resolved_path);
visited_files.insert(file_id);
work_list.push((resolved_path.clone(), Vec::new()));
while !work_list.is_empty() {
let mut new_work_list = Vec::new();
for (curr_file, include_context) in work_list {
let curr_parse_tree = if curr_file == resolved_path {
parse_tree.clone()
} else {
match parse_file(&curr_file, &mut source_string_loader) {
Ok(tu) => tu,
Err(err) => {
Self::print_include_context(&include_context);
return Err(Errors::from(err));
}
}
};
let mut include_errors = Errors::none();
for include in &curr_parse_tree.translation_unit.data.includes {
let include_filename = format!(
"{}{}{}",
include.data.id.data,
".ipdl",
if include.data.protocol.is_some() {
""
} else {
"h"
}
);
let include_id = match self.resolve_include(&include_filename) {
Some(tuid) => tuid,
None => {
include_errors.append_one(
&Location {
file_name: include_filename.clone(),
lineno: 0,
colno: 0,
},
&format!("Cannot resolve include {}", include_filename),
);
continue;
}
};
if visited_files.contains(&include_id) {
continue;
}
let mut new_include_context = include_context.clone();
new_include_context.push(curr_file.clone());
visited_files.insert(include_id);
new_work_list.push((
self.include_files
.get(&include_filename)
.expect("Resolve include is broken")
.clone(),
new_include_context,
));
}
if !include_errors.is_empty() {
return Err(include_errors);
}
let curr_id = self.id_file_map.resolve_file_name(&curr_file);
parsed_files.insert(curr_id, curr_parse_tree);
}
work_list = new_work_list;
}
Ok((file_id, parsed_files))
}
}
pub struct TUIdFileMap<T>
where
T: FileURI,
{
next_id: TUId,
file_ids: HashMap<T, TUId>,
id_files: HashMap<TUId, T>,
}
impl<T> TUIdFileMap<T>
where
T: FileURI,
{
fn new() -> TUIdFileMap<T> {
TUIdFileMap {
next_id: 0,
file_ids: HashMap::new(),
id_files: HashMap::new(),
}
}
fn get_tuid(&self, path: &T) -> Option<TUId> {
self.file_ids.get(path).cloned()
}
fn resolve_file_name(&mut self, path: &T) -> TUId {
if let Some(&id) = self.file_ids.get(path) {
return id;
}
let id = self.next_id;
self.next_id += 1;
self.id_files.insert(id, path.clone());
self.file_ids.insert(path.clone(), id);
id
}
}

Просмотреть файл

@ -1,7 +0,0 @@
/* 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/. */
pub mod include_resolution;
pub mod parsetree_to_tu;
pub mod type_check;

Просмотреть файл

@ -1,387 +0,0 @@
/* 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/. */
use ast;
use errors::Errors;
use parser;
use passes::include_resolution::IncludeResolver;
use pipdl;
pub struct ParseTreeToTU<'includedirs, T: 'includedirs> where T: parser::FileURI {
include_resolver: &'includedirs IncludeResolver<'includedirs, T>,
}
impl<'includedirs, T> ParseTreeToTU<'includedirs, T> where T: parser::FileURI {
pub fn new(include_resolver: &'includedirs IncludeResolver<'includedirs, T>) -> Self {
ParseTreeToTU { include_resolver }
}
pub fn parsetree_to_translation_unit(
&self,
parse_tree: parser::ParseTree<T>,
) -> Result<ast::TranslationUnit, Errors> {
self.convert_translation_unit(parse_tree.translation_unit.data, parse_tree.file_path.to_utf8().to_owned())
}
fn convert_translation_unit(
&self,
pt_translation_unit: pipdl::TranslationUnit,
pt_filename: String,
) -> Result<ast::TranslationUnit, Errors> {
let mut structs = Vec::new();
let mut unions = Vec::new();
let mut protocol = None;
let mut last_is_struct = false;
for item in pt_translation_unit.items {
match item {
pipdl::Item::Struct(struct_item) => {
structs.push(self.convert_struct_item(struct_item.data));
last_is_struct = true;
}
pipdl::Item::Union(union_item) => {
unions.push(self.convert_union_item(union_item.data));
last_is_struct = false;
}
pipdl::Item::Protocol(protocol_item) => match protocol {
Some(_) => {
return Err(Errors::one(
&ast::Location {
file_name: pt_filename,
lineno: protocol_item.span.start.line,
colno: protocol_item.span.start.col,
},
"only one protocol definition per file",
))
}
None => protocol = Some(self.convert_protocol_item(protocol_item.data)),
},
}
}
Ok(ast::TranslationUnit {
cxx_includes: pt_translation_unit
.cxx_includes
.into_iter()
.map(|x| x.data.file.data)
.collect(),
includes: pt_translation_unit
.includes
.into_iter()
.map(|x| {
let filename = format!(
"{}{}{}",
x.data.id.data,
".ipdl",
if x.data.protocol.is_some() { "" } else { "h" }
);
self.include_resolver
.get_include(&filename)
.expect("Cannot find include TUId when converting ParseTree to AST")
})
.collect(),
using: pt_translation_unit
.usings
.into_iter()
.map(|x| self.convert_using_stmt(x.data))
.collect(),
namespace: match &protocol {
Some(p) => p.0.clone(),
None => {
// There's not really a canonical "thing" in headers. So
// somewhat arbitrarily use the namespace of the last
// interesting thing that was declared.
if last_is_struct {
structs.last().expect("last_is_struct is broken").0.clone()
} else {
match unions.last() {
Some(u) => u.0.clone(),
None => {
return Err(Errors::one(
&ast::Location {
file_name: pt_filename,
lineno: 0,
colno: 0,
},
"file is empty",
))
}
}
}
}
},
structs,
unions,
protocol,
file_type: ast::FileType::from_file_path(&pt_filename)
.expect("Cannot determine file type when converting parse tree to AST"),
file_name: pt_filename,
})
}
fn convert_using_stmt(&self, pt_using_stmt: pipdl::Using) -> ast::UsingStmt {
ast::UsingStmt {
cxx_type: self.convert_cxx_type(pt_using_stmt.ty.data),
header: pt_using_stmt.file.data,
kind: self.convert_cxx_type_kind(&pt_using_stmt.kind.data),
refcounted: pt_using_stmt.refcounted.is_some(),
}
}
fn convert_cxx_type_kind(&self, pt_type_kind: &pipdl::CxxTypeKind) -> Option<ast::CxxTypeKind> {
match pt_type_kind {
pipdl::CxxTypeKind::Class => Some(ast::CxxTypeKind::Class),
pipdl::CxxTypeKind::Struct => Some(ast::CxxTypeKind::Struct),
pipdl::CxxTypeKind::None => None,
}
}
fn convert_cxx_type(&self, pt_cxx_type: pipdl::CxxPath) -> ast::TypeSpec {
ast::TypeSpec {
spec: self.convert_cxx_path(pt_cxx_type),
array: false,
nullable: false,
}
}
fn convert_cxx_path(&self, mut pt_cxx_path: pipdl::CxxPath) -> ast::QualifiedId {
ast::QualifiedId {
base_id: self.convert_cxx_path_seg(
pt_cxx_path
.segs
.pop()
.expect("Empty path when converting into QualifiedId")
.data,
),
quals: pt_cxx_path
.segs
.into_iter()
.map(|x| self.convert_cxx_path_seg(x.data).id)
.collect(),
}
}
fn convert_cxx_path_seg(&self, pt_cxx_path_seg: pipdl::CxxPathSeg) -> ast::Identifier {
ast::Identifier {
id: match pt_cxx_path_seg.args {
Some(args) => format!(
"{}<{}>",
pt_cxx_path_seg.id.data,
args.data
.into_iter()
.map(|x| x.data)
.collect::<Vec<String>>()
.concat()
),
None => pt_cxx_path_seg.id.data,
},
loc: self.convert_location(pt_cxx_path_seg.id.span.start),
}
}
fn convert_location(&self, pt_location: pipdl::Location) -> ast::Location {
ast::Location {
file_name: pt_location.file,
lineno: pt_location.line,
colno: pt_location.col,
}
}
fn convert_struct_item(
&self,
pt_struct_item: pipdl::StructItem,
) -> (ast::Namespace, Vec<ast::StructField>) {
(
self.convert_path(pt_struct_item.path),
pt_struct_item
.fields
.into_iter()
.map(|x| self.convert_struct_field(x.data))
.collect(),
)
}
fn convert_path(&self, mut pt_path: Vec<pipdl::Spanned<String>>) -> ast::Namespace {
ast::Namespace {
name: self.convert_name(
pt_path
.pop()
.expect("Empty path when converting into Namespace"),
),
namespaces: pt_path.into_iter().map(|x| x.data).collect(),
}
}
fn convert_struct_field(&self, pt_struct_field: pipdl::Field) -> ast::StructField {
ast::StructField {
type_spec: self.convert_type(pt_struct_field.ty.data),
name: self.convert_name(pt_struct_field.name),
}
}
fn convert_name(&self, pt_name: pipdl::Spanned<String>) -> ast::Identifier {
ast::Identifier {
id: pt_name.data,
loc: self.convert_location(pt_name.span.start),
}
}
fn convert_type(&self, pt_type: pipdl::Type) -> ast::TypeSpec {
ast::TypeSpec {
spec: ast::QualifiedId::new(self.convert_cxx_path_seg(pt_type.name.data)),
array: pt_type.is_array.is_some(),
nullable: pt_type.is_nullable.is_some(),
}
}
fn convert_union_item(
&self,
pt_union_item: pipdl::UnionItem,
) -> (ast::Namespace, Vec<ast::TypeSpec>) {
(
self.convert_path(pt_union_item.path),
pt_union_item
.components
.into_iter()
.map(|x| self.convert_type(x.data))
.collect(),
)
}
fn convert_protocol_item(
&self,
pt_protocol_item: pipdl::ProtocolItem,
) -> (ast::Namespace, ast::Protocol) {
(
self.convert_path(pt_protocol_item.path),
ast::Protocol {
send_semantics: self.convert_send_semantics(&pt_protocol_item.send_semantics.data),
nested: self.convert_nesting(pt_protocol_item.nested),
managers: match pt_protocol_item.managers {
Some(managers) => managers
.data
.into_iter()
.map(|x| self.convert_name(x))
.collect(),
None => Vec::new(),
},
manages: pt_protocol_item
.manages
.into_iter()
.map(|x| self.convert_name(x.data))
.collect(),
messages: pt_protocol_item
.groups
.into_iter()
.flat_map(|group| {
let (decls, direction) = (group.data.decls, group.data.direction.data);
decls
.into_iter()
.map(move |x| (x.data, direction.clone()))
.map(|(message_decl, direction)| {
self.convert_message_decl(message_decl, &direction)
})
})
.collect(),
},
)
}
fn convert_message_decl(
&self,
pt_message_decl: pipdl::MessageDecl,
pt_direction: &pipdl::Direction,
) -> ast::MessageDecl {
let mut compress = ast::Compress::None;
let mut verify = false;
for modifier in pt_message_decl.modifiers {
match modifier.data {
pipdl::MessageModifier::Compress => compress = ast::Compress::Enabled,
pipdl::MessageModifier::CompressAll => compress = ast::Compress::All,
pipdl::MessageModifier::Verify => verify = true,
}
}
ast::MessageDecl {
name: self.convert_name(pt_message_decl.name),
send_semantics: self.convert_send_semantics(&pt_message_decl.send_semantics.data),
nested: self.convert_nesting(pt_message_decl.nested),
prio: self.convert_priority(pt_message_decl.priority),
direction: self.convert_direction(&pt_direction),
in_params: pt_message_decl
.params
.into_iter()
.map(|x| self.convert_param(x.data))
.collect(),
out_params: match pt_message_decl.returns {
Some(returns) => returns
.data
.into_iter()
.map(|x| self.convert_param(x.data))
.collect(),
None => Vec::new(),
},
compress,
verify,
}
}
fn convert_param(&self, pt_param: pipdl::Param) -> ast::Param {
ast::Param {
name: self.convert_name(pt_param.name),
type_spec: self.convert_type(pt_param.ty.data),
}
}
fn convert_send_semantics(
&self,
pt_send_semantics: &pipdl::SendSemantics,
) -> ast::SendSemantics {
match pt_send_semantics {
pipdl::SendSemantics::Async => ast::SendSemantics::Async,
pipdl::SendSemantics::Sync => ast::SendSemantics::Sync,
pipdl::SendSemantics::Intr => ast::SendSemantics::Intr,
}
}
fn convert_nesting(
&self,
pt_nesting: Option<pipdl::Spanned<pipdl::Spanned<pipdl::Nesting>>>,
) -> ast::Nesting {
match pt_nesting {
Some(x) => match x.data.data {
pipdl::Nesting::None => ast::Nesting::None,
pipdl::Nesting::InsideCpow => ast::Nesting::InsideCpow,
pipdl::Nesting::InsideSync => ast::Nesting::InsideSync,
},
None => ast::Nesting::None,
}
}
fn convert_priority(
&self,
pt_priority: Option<pipdl::Spanned<pipdl::Spanned<pipdl::Priority>>>,
) -> ast::Priority {
match pt_priority {
Some(x) => match x.data.data {
pipdl::Priority::Normal => ast::Priority::Normal,
pipdl::Priority::High => ast::Priority::High,
pipdl::Priority::Input => ast::Priority::Input,
},
None => ast::Priority::Normal,
}
}
fn convert_direction(&self, pt_direction: &pipdl::Direction) -> ast::Direction {
match pt_direction {
pipdl::Direction::ToChild => ast::Direction::ToChild,
pipdl::Direction::ToParent => ast::Direction::ToParent,
pipdl::Direction::Both => ast::Direction::ToParentOrChild,
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,74 +0,0 @@
extern crate ipdl;
use std::collections::HashSet;
use std::ffi::OsStr;
use std::fs;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
const BASE_PATH: [&str; 5] = ["..", "..", "ipdl", "test", "ipdl"];
const OK_PATH: &str = "ok";
const ERROR_PATH: &str = "error";
// Tests in error/ are disabled because the given checking is not
// enabled yet.
const DISABLED_TESTS: &[&str] = &["unknownSyncMessage.ipdl", "unknownIntrMessage.ipdl", "asyncMessageListed.ipdl"];
// XXX This does not run efficiently. If A includes B, then we end up
// testing A and B two times each. At least for the non-error case we
// should be able to do them all together.
fn test_files(test_file_path: &str, should_pass: bool) {
let mut path: PathBuf = BASE_PATH.iter().collect();
path.push(test_file_path);
let include_dirs = vec![path.clone()];
let mut disabled_tests = HashSet::new();
for f in DISABLED_TESTS {
disabled_tests.insert(OsStr::new(f));
}
let entries = fs::read_dir(&path).expect("Should have the test file directory");
for entry in entries {
if let Ok(entry) = entry {
let expected_result = if !should_pass
&& disabled_tests.contains(
entry
.path()
.file_name()
.expect("No filename for path in test directory"),
) {
println!(
"Expecting test to pass when it should fail {:?}",
entry.file_name()
);
true
} else {
println!("Testing {:?}", entry.file_name());
should_pass
};
let file_name = entry.path();
let ok = ipdl::parser::parse(&file_name, &include_dirs, |src| {
let mut buffer = Vec::new();
let mut file = File::open(src).map_err(|_| ())?;
file.read_to_end(&mut buffer).map_err(|_| ())?;
Ok(Box::new(buffer))
}).is_ok();
assert!(expected_result == ok);
}
}
}
#[test]
fn ok_tests() {
test_files(OK_PATH, true);
}
#[test]
fn error_tests() {
test_files(ERROR_PATH, false);
}

Просмотреть файл

@ -1,15 +0,0 @@
[package]
name = "ipdl_bindings"
version = "0.1.0"
authors = ["Tristan Bourvon <tristanbourvon@gmail.com>"]
license = "MPL-2.0"
[dependencies]
ipdl = { path = "../ipdl" }
thin-vec = { version = "*", features = ["gecko-ffi"] }
nsstring = { path = "../../../servo/support/gecko/nsstring" }
mfbt-maybe = { path = "../../../xpcom/rust/mfbt-maybe" }
[lib]
name = "ipdl_bindings"
path = "src/lib.rs"

Просмотреть файл

@ -1,121 +0,0 @@
#include "IPCInterface.h"
#include "mozilla/ipdl/IPDLProtocolInstance.h"
#include "mozilla/dom/IPDL.h"
#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/MozPromise.h"
#include "mozilla/ipdl/IPDLProtocol.h"
namespace mozilla {
namespace ipdl {
namespace ipc {
/* virtual */ mozilla::ipc::IPCResult
IPCInterface::RecvMessageCommon(
mozilla::ipc::IProtocol* aActor,
IPDLSide aSide,
const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessage,
const dom::ClonedMessageData& aData,
nsTArray<dom::ipc::StructuredCloneData>* aReturnData)
{
// Borrow from the CloneMessageData to the StructuredCloneData.
dom::ipc::StructuredCloneData data;
switch (aSide) {
case IPDLSide::Child:
data.BorrowFromClonedMessageDataForChild(aData);
break;
case IPDLSide::Parent:
data.BorrowFromClonedMessageDataForParent(aData);
break;
}
// Get the destination instance object to initiate a new context.
JS::RootingContext* rcx = CycleCollectedJSContext::Get()->RootingCx();
JS::RootedObject object(rcx);
auto sidedProtocolName = IPDLProtocol::GetSidedProtocolName(
aProtocolName, aSide);
object = GetDestinationObject(sidedProtocolName, aChannelId);
dom::AutoEntryScript aes(object, "RecvSyncMessageIPDL");
JSContext* cx = aes.cx();
// Read the arguments from the StructuredCloneData.
JS::RootedValue argsVal(cx);
ErrorResult errRes;
data.Read(cx, &argsVal, errRes);
if (NS_WARN_IF(errRes.Failed())) {
return IPC_FAIL(aActor,
"Could not read arguments from StructuredCloneData");
}
JS::RootedObject argsObj(cx, &argsVal.toObject());
uint32_t arrayLength = 0;
if (!JS_GetArrayLength(cx, argsObj, &arrayLength)) {
return IPC_FAIL(aActor, "Could not get argument array length");
}
// Extract all the arguments.
JS::AutoValueVector args(cx);
for (uint32_t i = 0; i < arrayLength; i++) {
JS::RootedValue val(cx);
if (!JS_GetElement(cx, argsObj, i, &val)) {
return IPC_FAIL(aActor,
"Could not get argument value from argument array");
}
if (!args.append(val)) {
return IPC_FAIL(aActor,
"Could not append argument value to argument vector");
}
}
JS::HandleValueArray argsHandle(args);
JS::RootedValue retValue(cx);
// Call the receive handler in the protocol instance.
if (!mProtocolInstances.GetOrInsert(sidedProtocolName)
.Get(aChannelId)
->RecvMessage(
cx, aMessage, argsHandle, &retValue)) {
NS_WARNING("Error in the RecvMessage handler");
aReturnData->Clear();
return IPC_OK();
}
// Write back the return value.
dom::ipc::StructuredCloneData retData;
retData.Write(cx, retValue, errRes);
if (NS_WARN_IF(errRes.Failed())) {
return IPC_FAIL(aActor,
"Could not write return value to StructuredCloneData");
}
aReturnData->AppendElement(std::move(retData));
return IPC_OK();
}
/* virtual */ JSObject*
IPCInterface::GetDestinationObject(const nsCString& aProtocolName,
const uint32_t& aChannelId)
{
// Return the instance object corresponding to the protocol name and channel
// ID.
return mProtocolInstances.GetOrInsert(aProtocolName)
.Get(aChannelId)
->GetInstanceObject();
}
} // ipc
} // ipdl
} // mozilla

Просмотреть файл

@ -1,117 +0,0 @@
/* -*- 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 https://mozilla.org/MPL/2.0/. */
#ifndef dom_base_ipdl_bindings_ipcinterface_h
#define dom_base_ipdl_bindings_ipcinterface_h
#include <functional>
#include "jsapi.h"
#include "mozilla/ipc/ProtocolUtils.h"
namespace mozilla {
namespace dom {
class IPDL;
}
namespace ipdl {
class IPDLProtocolInstance;
enum class IPDLSide : bool;
namespace ipc {
class IPCInterface
{
public:
// Message call return type.
typedef JS::MutableHandleValue OutObject;
// Message call argument list type.
typedef JS::HandleValueArray InArgs;
// Async message call promise type.
typedef MozPromise<JS::Value, nsCString, true> AsyncMessagePromise;
explicit IPCInterface(dom::IPDL* aIPDL)
: mIPDL(aIPDL)
{
}
virtual ~IPCInterface() = default;
// Send an async message through IPC.
virtual RefPtr<AsyncMessagePromise> SendAsyncMessage(
JSContext* aCx,
const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessageName,
const InArgs& aArgs) = 0;
// Send a sync message through IPC.
virtual bool SendSyncMessage(JSContext* aCx,
const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessageName,
const InArgs& aArgs,
OutObject aRet) = 0;
// Send an intr message through IPC.
virtual bool SendIntrMessage(JSContext* aCx,
const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessageName,
const InArgs& aArgs,
OutObject aRet) = 0;
// Set the recv handler to call when we receive a message.
virtual void SetIPDLInstance(const uint32_t& aChannelId,
const nsCString& aProtocolName,
IPDLProtocolInstance* aInstance)
{
mProtocolInstances.GetOrInsert(aProtocolName).GetOrInsert(aChannelId) =
aInstance;
}
virtual void RemoveIPDLInstance(const uint32_t& aChannelId,
const nsCString& aProtocolName)
{
mProtocolInstances.GetOrInsert(aProtocolName).Remove(aChannelId);
}
// Receive a message from IPC. Empty return array means error.
virtual mozilla::ipc::IPCResult RecvMessage(
const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessage,
const dom::ClonedMessageData& aData,
nsTArray<dom::ipc::StructuredCloneData>* aReturnData) = 0;
protected:
// Inner common function for receiving a message from either the parent or the
// child. Empty return array means error.
virtual mozilla::ipc::IPCResult RecvMessageCommon(
mozilla::ipc::IProtocol* aActor,
IPDLSide aSide,
const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessage,
const dom::ClonedMessageData& aData,
nsTArray<dom::ipc::StructuredCloneData>* aReturnData);
// Retrieves the destination instance object for a protocol/channel pair.
virtual JSObject* GetDestinationObject(const nsCString& aProtocolName,
const uint32_t& aChannelId);
dom::IPDL* MOZ_NON_OWNING_REF mIPDL;
nsDataHashtable<nsCStringHashKey,
nsDataHashtable<nsUint32HashKey, IPDLProtocolInstance*>>
mProtocolInstances;
};
} // ipc
} // ipdl
} // mozilla
#endif // dom_base_ipdl_bindings_ipcinterface_h

Просмотреть файл

@ -1,778 +0,0 @@
/* -*- 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 https://mozilla.org/MPL/2.0/. */
#include "IPDLProtocol.h"
#include <cfloat>
#include "ipdl_ffi_generated.h"
#include "mozilla/dom/DOMMozPromiseRequestHolder.h"
#include "mozilla/dom/Promise.h"
#include "nsJSUtils.h"
#include "wrapper.h"
#include "mozilla/dom/IPDL.h"
#include "IPCInterface.h"
#include "IPDLProtocolInstance.h"
namespace mozilla {
namespace ipdl {
NS_IMPL_CYCLE_COLLECTION_CLASS(IPDLProtocol)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IPDLProtocol)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mInstances)
tmp->mProtoObj = nullptr;
tmp->mConstructorObj = nullptr;
mozilla::DropJSObjects(tmp);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IPDLProtocol)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInstances)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IPDLProtocol)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mProtoObj)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mConstructorObj)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(IPDLProtocol)
NS_IMPL_CYCLE_COLLECTING_RELEASE(IPDLProtocol)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IPDLProtocol)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
void
IPDLProtocol::ASTDeletePolicy::operator()(const mozilla::ipdl::ffi::AST* aASTPtr)
{
if (!aASTPtr) {
return;
}
wrapper::FreeAST(aASTPtr);
}
IPDLProtocol::IPDLProtocol(dom::IPDL* aIPDL,
IPDLSide aSide,
const nsACString& aIPDLFile,
nsIGlobalObject* aGlobal,
JS::HandleObject aParent,
JSContext* aCx)
: mSide(aSide)
, mGlobal(aGlobal)
, mIPDL(aIPDL)
, mNextProtocolInstanceChannelId(0)
{
mozilla::HoldJSObjects(this);
nsCString errorString;
mAST.reset(wrapper::Parse(aIPDLFile, errorString));
if (!mAST) {
JS_ReportErrorUTF8(aCx, "IPDL: %s", errorString.get());
return;
}
// Get the main translation unit.
auto mainTU = GetMainTU();
MOZ_ASSERT(mainTU->protocol, "should have a protocol in protocol file");
mProtocolName = JoinNamespace(mainTU->protocol->ns);
auto& manages = mainTU->protocol->protocol.manages;
auto& messages = mainTU->protocol->protocol.messages;
NS_NAMED_LITERAL_CSTRING(sendPrefix, "send");
NS_NAMED_LITERAL_CSTRING(recvPrefix, "recv");
NS_NAMED_LITERAL_CSTRING(allocPrefix, "alloc");
NS_NAMED_LITERAL_CSTRING(constructorSuffix, "Constructor");
// Store the managed protocols in a set for fast retrieval and access.
nsTHashtable<nsCStringHashKey> managedProtocols;
for (auto& managedProtocol : manages) {
managedProtocols.PutEntry(managedProtocol.id);
}
nsTArray<JSFunctionSpec> funcs;
nsTArray<nsCString> functionNames;
// We loop through every message of the protocol and add them to our message
// table, taking into account our protocol side and the message direction.
for (auto& message : messages) {
// The message is gonna be sendXXX.
if ((message.direction == ffi::Direction::ToChild &&
mSide == IPDLSide::Parent) ||
(message.direction == ffi::Direction::ToParent &&
mSide == IPDLSide::Child) ||
message.direction == ffi::Direction::ToParentOrChild) {
// If this is a managed protocol name...
if (managedProtocols.Contains(message.name.id)) {
// Append the sendXXXConstructor message.
const nsAutoCString& constructorName =
sendPrefix + message.name.id + constructorSuffix;
functionNames.AppendElement(constructorName);
funcs.AppendElement<JSFunctionSpec>(JS_FN(
functionNames.LastElement().get(),
SendConstructorDispatch,
static_cast<uint16_t>(message.in_params.Length()),
0));
mMessageTable.Put(constructorName, &message);
// And the allocXXX message.
const nsAutoCString& allocName = allocPrefix + message.name.id;
functionNames.AppendElement(allocName);
funcs.AppendElement<JSFunctionSpec>(JS_FN(
functionNames.LastElement().get(),
AbstractAlloc,
static_cast<uint16_t>(message.in_params.Length()),
0));
mMessageTable.Put(allocName, &message);
} else {
// Otherwise for the regular sendXXX messages, we define the associated JS function.
const nsAutoCString& funcName = sendPrefix + message.name.id;
functionNames.AppendElement(funcName);
funcs.AppendElement<JSFunctionSpec>(JS_FN(
functionNames.LastElement().get(),
message.name.id.Equals("__delete__") ? SendDeleteDispatch
: SendMessageDispatch,
static_cast<uint16_t>(message.in_params.Length()),
0));
mMessageTable.Put(funcName, &message);
}
}
// The message is gonna be recvXXX;
if ((message.direction == ffi::Direction::ToChild &&
mSide == IPDLSide::Child) ||
(message.direction == ffi::Direction::ToParent &&
mSide == IPDLSide::Parent) ||
message.direction == ffi::Direction::ToParentOrChild) {
// If this is a managed protocol...
if (managedProtocols.Contains(message.name.id)) {
// Append the recvXXXConstructor message.
const nsAutoCString& constructorName =
recvPrefix + message.name.id + constructorSuffix;
functionNames.AppendElement(constructorName);
funcs.AppendElement<JSFunctionSpec>(JS_FN(
functionNames.LastElement().get(),
RecvConstructor,
static_cast<uint16_t>(message.in_params.Length()),
0));
mMessageTable.Put(constructorName, &message);
// And the allocXXX message.
const nsAutoCString& allocName = allocPrefix + message.name.id;
functionNames.AppendElement(allocName);
funcs.AppendElement<JSFunctionSpec>(JS_FN(
functionNames.LastElement().get(),
AbstractAlloc,
static_cast<uint16_t>(message.in_params.Length()),
0));
mMessageTable.Put(allocName, &message);
} else {
// For the regular recvXXX callbacks, we define the associated "abstract"
// functions or the delete default function.
const nsAutoCString& funcName = recvPrefix + message.name.id;
functionNames.AppendElement(funcName);
funcs.AppendElement<JSFunctionSpec>(JS_FN(
functionNames.LastElement().get(),
message.name.id.Equals("__delete__") ? RecvDelete
: AbstractRecvMessage,
static_cast<uint16_t>(message.in_params.Length()),
0));
mMessageTable.Put(funcName, &message);
}
}
}
funcs.AppendElement<JSFunctionSpec>(JS_FS_END);
// Create our new protocol JSClass.
mSidedProtocolName = GetSidedProtocolName(mProtocolName, mSide);
mProtocolClass =
{ mSidedProtocolName.get(),
JSCLASS_HAS_PRIVATE,
&sIPDLJSClassOps };
JS::RootedObject parentProto(aCx);
JS_GetClassPrototype(aCx, JSProto_Object, &parentProto);
// Initialize it with the constructor and the functions.
mProtoObj = JS_InitClass(aCx,
aParent,
parentProto,
&mProtocolClass,
Constructor,
0,
nullptr,
funcs.Elements(),
nullptr,
nullptr);
JS::RootedObject protoObj(aCx, mProtoObj);
// Add this object to the private field.
JS_SetPrivate(protoObj, this);
mConstructorObj = JS_GetConstructor(aCx, protoObj);
// We build the name->AST lookup tables for later typechecking.
BuildNameLookupTables();
}
nsCString
IPDLProtocol::GetProtocolName()
{
return mProtocolName;
}
JSObject*
IPDLProtocol::GetProtocolClassConstructor()
{
return mConstructorObj.get();
}
uint32_t
IPDLProtocol::RegisterExternalInstance()
{
auto childID = mNextProtocolInstanceChannelId++;
return childID;
}
JSClass&
IPDLProtocol::GetProtocolClass()
{
return mProtocolClass;
}
const ffi::TranslationUnit*
IPDLProtocol::GetMainTU()
{
return wrapper::GetTU(mAST.get(), wrapper::GetMainTUId(mAST.get()));
}
void
IPDLProtocol::BuildNameLookupTables()
{
// We don't have an Int32 hashkey, but it's ok since we can just perform
// conversions in and out.
nsTHashtable<nsUint32HashKey> visitedTUId;
nsTArray<ffi::TUId> workList;
// Our current loop element.
const ffi::TranslationUnit* currentTU = nullptr;
// Our current loop index.
ffi::TUId currentTUId = -1;
// We start with only the main tu in the worklist, and then unroll all the
// includes.
ffi::TUId mainTUId = wrapper::GetMainTUId(mAST.get());
workList.AppendElement(mainTUId);
while (!workList.IsEmpty()) {
// Get an index and anelement from the work list.
currentTUId = workList.PopLastElement();
currentTU = wrapper::GetTU(mAST.get(), currentTUId);
// If we are in a protocol file, just add the protocol and stop here (we)
// shouldn't keep going through the includes recursively, and we should
// ignore the local structs and unions.
if (currentTU->file_type == ffi::FileType::Protocol) {
// If there is a protocol, add it.
if (currentTU->protocol) {
mProtocolTable.Put(JoinNamespace(currentTU->protocol->ns),
currentTU->protocol.ptr());
}
}
// If we are in a header file, add the structs and the unions it contains,
// and then recurse through all of its includes.
if (currentTU->file_type == ffi::FileType::Header ||
currentTUId == mainTUId) {
for (size_t i = 0; i < currentTU->structs.Length(); i++) {
// Dirty, but this is the only way to have a pointer to an element
const auto* s = currentTU->structs.Elements() + i;
mStructTable.Put(JoinNamespace(s->ns), s);
}
for (size_t i = 0; i < currentTU->unions.Length(); i++) {
// Dirty, but this is the only way to have a pointer to an element
const auto* u = currentTU->unions.Elements() + i;
mUnionTable.Put(JoinNamespace(u->ns), u);
}
workList.AppendElements(currentTU->includes);
}
}
}
/* static */ bool
IPDLProtocol::SendMessageDispatch(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
{
// Unwrap the JS args.
auto args = JS::CallArgsFromVp(aArgc, aVp);
// Get the IPDLProtocol object from the private field of the method `this`.
JS::RootedObject thisObj(aCx);
args.computeThis(aCx, &thisObj);
auto* instance = static_cast<IPDLProtocolInstance*>(JS_GetPrivate(thisObj));
if (!instance) {
JS_ReportErrorUTF8(aCx, "Cannot use deleted protocol");
return false;
}
// Get the method name that we are calling.
auto function = JS_GetObjectFunction(&args.callee());
nsAutoJSString functionName;
if (!functionName.init(aCx, JS_GetFunctionId(function))) {
return false;
}
// Call our internal SendMessage function.
return instance->SendMessage(aCx, NS_ConvertUTF16toUTF8(functionName), args);
}
/* static */ bool
IPDLProtocol::SendConstructorDispatch(JSContext* aCx,
unsigned aArgc,
JS::Value* aVp)
{
// Unwrap the JS args.
auto args = JS::CallArgsFromVp(aArgc, aVp);
// Get the IPDLProtocol object from the private field of the method `this`.
JS::RootedObject thisObj(aCx);
args.computeThis(aCx, &thisObj);
auto* instance = static_cast<IPDLProtocolInstance*>(JS_GetPrivate(thisObj));
if (!instance) {
JS_ReportErrorUTF8(aCx, "Cannot use deleted protocol");
return false;
}
// Get the method name that we are calling.
auto function = JS_GetObjectFunction(&args.callee());
nsAutoJSString functionName;
if (!functionName.init(aCx, JS_GetFunctionId(function))) {
return false;
}
// Call our internal SendConstructor function.
return instance->SendConstructor(aCx, thisObj, NS_ConvertUTF16toUTF8(functionName), args);
}
/* static */ bool
IPDLProtocol::SendDeleteDispatch(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
{
// Unwrap the JS args.
auto args = JS::CallArgsFromVp(aArgc, aVp);
// Get the IPDLProtocol object from the private field of the method `this`.
JS::RootedObject thisObj(aCx);
args.computeThis(aCx, &thisObj);
auto* instance = static_cast<IPDLProtocolInstance*>(JS_GetPrivate(thisObj));
if (!instance) {
JS_ReportErrorUTF8(aCx, "Cannot use deleted protocol");
return false;
}
// Get the method name that we are calling.
auto function = JS_GetObjectFunction(&args.callee());
nsAutoJSString functionName;
if (!functionName.init(aCx, JS_GetFunctionId(function))) {
return false;
}
// Call our internal SendConstructor function.
return instance->SendDelete(aCx, NS_ConvertUTF16toUTF8(functionName), args);
}
void
IPDLProtocol::RemoveInstance(IPDLProtocolInstance *instance)
{
mInstances.RemoveEntry(instance);
}
bool
IPDLProtocol::CheckParamTypeSpec(JSContext* aCx,
JS::HandleValue aJSVal,
ffi::Param aParam)
{
// Just unwrap the type spec.
return CheckTypeSpec(aCx, aJSVal, aParam.type_spec);
}
bool
IPDLProtocol::CheckTypeSpec(JSContext* aCx,
JS::HandleValue aJSVal,
ffi::TypeSpec aTypeSpec)
{
// If the type is nullable and we get a null, we return now
if (aTypeSpec.nullable && aJSVal.isNull()) {
return true;
}
// If the type is an array, we check the type for all the array elements
if (aTypeSpec.array) {
// Check if jsVal is an array.
bool isArray = false;
JS_IsArrayObject(aCx, aJSVal, &isArray);
if (!isArray) {
return false;
}
// Get the JS array.
JS::RootedObject jsArray(aCx, &aJSVal.toObject());
uint32_t arrayLength = 0;
JS_GetArrayLength(aCx, jsArray, &arrayLength);
// For each element of the array, we check its type.
for (size_t i = 0; i < arrayLength; i++) {
JS::RootedValue arrayVal(aCx);
JS_GetElement(aCx, jsArray, i, &arrayVal);
if (!CheckType(aCx, arrayVal, aTypeSpec.spec)) {
return false;
}
}
return true;
}
// We check the actual type if not an array.
return CheckType(aCx, aJSVal, aTypeSpec.spec);
}
bool
IPDLProtocol::CheckType(JSContext* aCx,
JS::HandleValue aJSVal,
ffi::QualifiedId aType)
{
// First check the builtin types
if (CheckBuiltinType(aCx, aJSVal, aType)) {
return true;
}
// Then the protocol types
if (CheckProtocolType(aCx, aJSVal, aType)) {
return true;
}
// Then the struct types
if (CheckStructType(aCx, aJSVal, aType)) {
return true;
}
// Then the union types.
if (CheckUnionType(aCx, aJSVal, aType)) {
return true;
}
// Otherwise we have a type mismatch.
return false;
}
bool
IPDLProtocol::CheckProtocolType(JSContext* aCx,
JS::HandleValue aJSVal,
ffi::QualifiedId aType)
{
// If we don't know that protocol name, return false.
auto typeString = JoinQualifiedId(aType);
if (!mProtocolTable.Contains(typeString)) {
return false;
}
// If we don't have an object, return false.
if (!aJSVal.isObject()) {
return false;
}
// Get our JS object.
JS::RootedObject jsObj(aCx, &aJSVal.toObject());
// If the object is not an IPDL protocol class instance, return false.
if (typeString.Equals(JS_GetClass(jsObj)->name) != 0) { // not equal
return false;
}
auto* protocolObj = static_cast<IPDLProtocol*>(JS_GetPrivate(jsObj));
if (!protocolObj) {
JS_ReportErrorUTF8(aCx, "Couldn't get protocol object from private date field");
return false;
}
// Check the protocol name against the one we require.
return protocolObj->GetProtocolName().Equals(typeString);
}
bool
IPDLProtocol::CheckStructType(JSContext* aCx,
JS::HandleValue aJSVal,
ffi::QualifiedId aType)
{
// If we don't know that struct name, return false.
auto* ipdlStruct = mStructTable.Get(JoinQualifiedId(aType));
if (!ipdlStruct) {
return false;
}
// If we don't have an object, return false.
if (!aJSVal.isObject()) {
return false;
}
// Get our JS object.
JS::RootedObject jsObj(aCx, &aJSVal.toObject());
// Go through every field of the struct.
for (auto& field : ipdlStruct->fields) {
JS::RootedValue propertyValue(aCx);
// Check that the field exists in the object we got.
if (!JS_GetProperty(aCx, jsObj, field.name.id.get(), &propertyValue)) {
return false;
}
if (propertyValue.isUndefined()) {
return false;
}
// Check that the field type matches the element we got.
if (!CheckTypeSpec(aCx, propertyValue, field.type_spec)) {
return false;
}
}
return true;
}
bool
IPDLProtocol::CheckUnionType(JSContext* aCx,
JS::HandleValue aJSVal,
ffi::QualifiedId aType)
{
auto* ipdlUnion = mUnionTable.Get(JoinQualifiedId(aType));
if (!ipdlUnion) {
return false;
}
// Go through every type of the union
for (auto& type : ipdlUnion->types) {
// If our input value matches any of these types, return true.
if (CheckTypeSpec(aCx, aJSVal, type)) {
return true;
}
}
// Otherwise return false.
return false;
}
/* static */ bool
IPDLProtocol::CheckBuiltinType(JSContext* aCx, JS::HandleValue aJSVal, ffi::QualifiedId type)
{
// Check all the builtin types using their type name, and custom constraints
// such as bounds checking and length.
auto typeString = JoinQualifiedId(type);
if (typeString.Equals("bool")) {
return aJSVal.isBoolean();
}
if (typeString.Equals("char")) {
JS::AutoCheckCannotGC nogc;
size_t length;
if (!aJSVal.isString()) {
return false;
}
JS_GetLatin1StringCharsAndLength(aCx, nogc, aJSVal.toString(), &length);
return length == 1;
}
if (typeString.Equals("nsString") || typeString.Equals("nsCString")) {
return aJSVal.isString();
}
if (typeString.Equals("short")) {
return aJSVal.isNumber() && (trunc(aJSVal.toNumber()) == aJSVal.toNumber()) &&
(aJSVal.toNumber() <= SHRT_MAX) && (aJSVal.toNumber() >= SHRT_MIN);
}
if (typeString.Equals("int")) {
return aJSVal.isNumber() && (trunc(aJSVal.toNumber()) == aJSVal.toNumber()) &&
(aJSVal.toNumber() <= INT_MAX) && (aJSVal.toNumber() >= INT_MIN);
}
if (typeString.Equals("long")) {
return aJSVal.isNumber() && (trunc(aJSVal.toNumber()) == aJSVal.toNumber()) &&
(aJSVal.toNumber() <= LONG_MAX) && (aJSVal.toNumber() >= LONG_MIN);
}
if (typeString.Equals("float")) {
return aJSVal.isNumber() && (aJSVal.toNumber() <= FLT_MAX) &&
(aJSVal.toNumber() >= FLT_MIN);
}
if (typeString.Equals("double")) {
return aJSVal.isNumber();
}
if (typeString.Equals("int8_t")) {
return aJSVal.isNumber() && (trunc(aJSVal.toNumber()) == aJSVal.toNumber()) &&
(aJSVal.toNumber() <= INT8_MAX) && (aJSVal.toNumber() >= INT8_MIN);
}
if (typeString.Equals("uint8_t")) {
return aJSVal.isNumber() && (trunc(aJSVal.toNumber()) == aJSVal.toNumber()) &&
(aJSVal.toNumber() <= UINT8_MAX) && (aJSVal.toNumber() >= 0);
}
if (typeString.Equals("int16_t")) {
return aJSVal.isNumber() && (trunc(aJSVal.toNumber()) == aJSVal.toNumber()) &&
(aJSVal.toNumber() <= INT16_MAX) && (aJSVal.toNumber() >= INT16_MIN);
}
if (typeString.Equals("uint16_t")) {
return aJSVal.isNumber() && (trunc(aJSVal.toNumber()) == aJSVal.toNumber()) &&
(aJSVal.toNumber() <= UINT16_MAX) && (aJSVal.toNumber() >= 0);
}
if (typeString.Equals("int32_t")) {
return aJSVal.isNumber() && (trunc(aJSVal.toNumber()) == aJSVal.toNumber()) &&
(aJSVal.toNumber() <= INT32_MAX) && (aJSVal.toNumber() >= INT32_MIN);
}
if (typeString.Equals("uint32_t")) {
return aJSVal.isNumber() && (trunc(aJSVal.toNumber()) == aJSVal.toNumber()) &&
(aJSVal.toNumber() <= UINT32_MAX) && (aJSVal.toNumber() >= 0);
}
// These IPDL builtin types are not allowed from the JS API because they are
// not easily representable.
if (typeString.Equals("int64_t") || typeString.Equals("uint64_t") ||
typeString.Equals("size_t") || typeString.Equals("ssize_t") ||
typeString.Equals("nsresult") ||
typeString.Equals("mozilla::ipc::Shmem") ||
typeString.Equals("mozilla::ipc::ByteBuf") ||
typeString.Equals("mozilla::ipc::FileDescriptor")) {
JS_ReportErrorUTF8(
aCx, "IPDL: cannot use type `%s` from JS", typeString.get());
return false;
}
return false;
}
IPDLProtocol::~IPDLProtocol()
{
mProtoObj = nullptr;
mConstructorObj = nullptr;
mozilla::DropJSObjects(this);
}
/* static */ bool
IPDLProtocol::Constructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
{
JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
// This function is a bit tricky. Basically we need to construct an object with
// the protocol's C++ JSClass, but with the prototype of the inherited JS class.
// First we get the prototype of the inherited class.
JS::RootedValue newTargetObjProtov(aCx);
JS::RootedObject newTargetObj(aCx, &args.newTarget().toObject());
if (!JS_GetProperty(aCx, newTargetObj, "prototype", &newTargetObjProtov)) {
return false;
}
JS::RootedObject newTargetObjProto(aCx, &newTargetObjProtov.toObject());
// Now we get the prototype of abstract protocol class, and get the IPDLProtocol
// object from it.
JS::RootedObject callee(aCx, &args.callee());
JS::RootedValue prototypev(aCx);
if (!JS_GetProperty(aCx, callee, "prototype", &prototypev)) {
return false;
}
JS::RootedObject prototype(aCx, &prototypev.toObject());
auto protocol = static_cast<IPDLProtocol*>(JS_GetPrivate(prototype));
if (!protocol) {
JS_ReportErrorUTF8(aCx, "Couldn't get protocol object from private date field");
return false;
}
// Now we construct our new object.
JS::RootedObject newClassObject(
aCx,
JS_NewObjectWithGivenProto(
aCx, &protocol->GetProtocolClass(), newTargetObjProto));
// We add it to our list of protocol instances and set its private field.
auto newInstance = MakeRefPtr<IPDLProtocolInstance>(
nullptr, protocol->RegisterExternalInstance(), protocol, newClassObject);
protocol->mInstances.PutEntry(newInstance);
JS_SetPrivate(newClassObject, newInstance);
args.rval().setObject(*newClassObject);
return true;
}
/* static */ bool
IPDLProtocol::RecvDelete(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
{
return true;
}
/* static */ bool
IPDLProtocol::RecvConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
{
return true;
}
/* static */ bool
IPDLProtocol::AbstractRecvMessage(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
{
JS_ReportErrorUTF8(
aCx, "Received message but recv method not overriden!");
return false;
}
/* static */ bool
IPDLProtocol::AbstractAlloc(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
{
JS_ReportErrorUTF8(
aCx, "Cannot alloc from abstract IPDL protocol class!");
return false;
}
/* static */ nsCString
IPDLProtocol::JoinQualifiedId(const ffi::QualifiedId aQid)
{
nsAutoCString ret;
for (auto& qual : aQid.quals) {
ret.Append(qual);
ret.Append("::");
}
ret.Append(aQid.base_id.id);
return std::move(ret);
}
/* static */ nsCString
IPDLProtocol::JoinNamespace(const ffi::Namespace aNs)
{
nsAutoCString ret;
for (auto& name : aNs.namespaces) {
ret.Append(name);
ret.Append("::");
}
ret.Append(aNs.name.id);
return std::move(ret);
}
constexpr JSClassOps IPDLProtocol::sIPDLJSClassOps;
} // ipdl
} // mozilla

Просмотреть файл

@ -1,269 +0,0 @@
/* -*- 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 https://mozilla.org/MPL/2.0/. */
#ifndef dom_base_ipdl_bindings_IPDLProtocol_h
#define dom_base_ipdl_bindings_IPDLProtocol_h
#include "jsapi.h"
#include "nsDataHashtable.h"
#include "nsStringFwd.h"
#include "nsCycleCollectionParticipant.h"
class nsIGlobalObject;
namespace mozilla {
namespace dom {
class IPDL;
} // dom
namespace ipdl {
class IPDLProtocolInstance;
namespace ipc {
class IPCInterface;
} // ipc
namespace ffi {
struct AST;
struct Union;
struct Struct;
struct NamedProtocol;
struct MessageDecl;
struct TranslationUnit;
struct Param;
struct TypeSpec;
struct QualifiedId;
struct Namespace;
} // ffi
// Represents the side of the protocol.
// This is un-nested to be forward-declarable.
enum class IPDLSide : bool
{
Parent,
Child
};
/**
* Represents an IPDLProtocol to be used under the cover from JS.
* This is owned by the IPDL class, and represents an abstract IPDL protocol
* class which can be extended from JS.
*
* Example usage from JS:
*
* IPDL.registerTopLevelClass(TestParent);
*
* class TestParent extends IPDL.PTestParent {
* // We add a listener for the message `SomeMessageFromChild` defined in
* // the IPDL protocol
* recvSomeMessageFromChild(arg1, arg2) {
* // In IPDL, out params are named. This is how we return them.
* return {out1: "test", out2: "test2" };
* };
*
* // We define the allocation function
* allocPSubTest() {
* return new SubTestParent();
* }
*
* // We need to pass the content parent ID to the super constructor
* constructor(id) {
* super(id);
* // We send the sync message `SomeSyncMessageToChild` to the child
* var syncResult = this.sendSomeSyncMessageToChild(123, [4, 5, 6]);
* console.log(syncResult);
*
* // We send the async message `SomeAsyncMessageToChild` to the child
* // Async calls return a promise
* protocol.sendSomeAsyncMessageToChild("hi").then(function(asyncResult)
* { console.log(asyncResult);
* });
* }
* }
*/
class IPDLProtocol : public nsISupports
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IPDLProtocol)
// Custom deleter for our AST smart pointer.
struct ASTDeletePolicy
{
void operator()(const mozilla::ipdl::ffi::AST* aASTPtr);
};
IPDLProtocol(dom::IPDL* aIPDL,
IPDLSide aSide,
const nsACString& aIPDLFile,
nsIGlobalObject* aGlobal,
JS::HandleObject aParent,
JSContext* aCx);
// Get the JSObject corresponding to the constructor of the JS class
// of our protocol.
JSObject* GetProtocolClassConstructor();
// Returns a new channel ID and updates the internal channel ID counter.
uint32_t RegisterExternalInstance();
// Returns the protocol name.
nsCString GetProtocolName();
// Returns the protocol side.
IPDLSide GetSide() { return mSide; }
// Returns a message decl for a given name.
const ffi::MessageDecl* GetMessageDecl(const nsACString& aName)
{
return mMessageTable.Get(aName);
}
// Type checks a parameter against a JS Value argument.
// This is just a slim wrapper around CheckTypeSpec.
bool CheckParamTypeSpec(JSContext* aCx,
JS::HandleValue aJSVal,
ffi::Param aParam);
// Returns the global object associated to that protocol.
nsIGlobalObject* GetGlobal() { return mGlobal; }
void RemoveInstance(IPDLProtocolInstance* instance);
// Returns the protocol name suffixed with the protocol side.
static nsCString GetSidedProtocolName(const nsCString& aProtocolName,
IPDLSide aSide)
{
return aProtocolName + (aSide == IPDLSide::Parent
? NS_LITERAL_CSTRING("Parent")
: NS_LITERAL_CSTRING("Child"));
}
// Small helper function to join a qualified id into a string.
static nsCString JoinQualifiedId(const ffi::QualifiedId qid);
// Small helper function to join a namespace into a string.
static nsCString JoinNamespace(const ffi::Namespace ns);
protected:
// The IPC interface object that we use for the actual IPC stuff.
// Which side of the protocol we're on.
IPDLSide mSide;
// Our Rust-owned AST.
UniquePtr<const ffi::AST, ASTDeletePolicy> mAST;
// The global JS object interface needed for promises.
nsCOMPtr<nsIGlobalObject> mGlobal;
// The JS constructor we expose to the API user.
JS::Heap<JSObject*> mConstructorObj;
// The JS prototype we expose to the API user.
JS::Heap<JSObject*> mProtoObj;
// The C++ JSClass corresponding to the protocol.
JSClass mProtocolClass;
// The unsided protocol name.
nsCString mProtocolName;
// The sided protocol name.
nsCString mSidedProtocolName;
// The IPDL global object managing this protocol.
dom::IPDL* MOZ_NON_OWNING_REF mIPDL;
// Typedefs for the member variables defined below.
typedef nsDataHashtable<nsCStringHashKey, const ffi::MessageDecl*>
MessageTable;
typedef nsDataHashtable<nsCStringHashKey, const ffi::Struct*> StructTable;
typedef nsDataHashtable<nsCStringHashKey, const ffi::Union*> UnionTable;
typedef nsDataHashtable<nsCStringHashKey, const ffi::NamedProtocol*>
ProtocolTable;
typedef nsTHashtable<nsRefPtrHashKey<IPDLProtocolInstance>> InstanceList;
// List of current IPDL protocol instances living in JS.
InstanceList mInstances;
uint32_t mNextProtocolInstanceChannelId;
// Maps message names to the AST struct describing them.
MessageTable mMessageTable;
// Maps struct names to the AST struct describing them.
StructTable mStructTable;
// Maps union names to the AST struct describing them.
UnionTable mUnionTable;
// Maps protocol names to the AST struct describing them.
ProtocolTable mProtocolTable;
virtual ~IPDLProtocol();
// Builds the struct, union and protocol name->AST lookup tables so that we
// can easily access name from the TypeSpecs given by message parameters.
void BuildNameLookupTables();
// Used internally to get the protocol JSClass.
JSClass& GetProtocolClass();
// Returns the main translation unit.
const ffi::TranslationUnit* GetMainTU();
// Type checks a TypeSpec against a JS Value.
// This takes care of checking the nullable and array extras, and then calls
// CheckType, possibly on all elements if dealing with an array.
bool CheckTypeSpec(JSContext* cx,
JS::HandleValue jsVal,
ffi::TypeSpec typeSpec);
// Type checks a type name against a JS Value.
bool CheckType(JSContext* cx, JS::HandleValue jsVal, ffi::QualifiedId type);
// Type checks a protocol type name against a JS Value.
bool CheckProtocolType(JSContext* cx,
JS::HandleValue jsVal,
ffi::QualifiedId type);
// Type checks a struct type name against a JS Value.
bool CheckStructType(JSContext* cx,
JS::HandleValue jsVal,
ffi::QualifiedId type);
// Type checks a union type name against a JS Value.
bool CheckUnionType(JSContext* cx,
JS::HandleValue jsVal,
ffi::QualifiedId type);
// Type checks a builtin type name against a JS Value.
// Note that some usual IPDL C++-inspired types are not available to use
// with this JS API (for instance, int64_t).
static bool CheckBuiltinType(JSContext* cx,
JS::HandleValue jsVal,
ffi::QualifiedId type);
// These are wrappers unpacking the IPDLProtocolInstance stored in the private
// data field of the callee, then dispatching the call to that instance.
static bool SendMessageDispatch(JSContext* cx, unsigned argc, JS::Value* vp);
static bool SendConstructorDispatch(JSContext* cx,
unsigned argc,
JS::Value* vp);
static bool SendDeleteDispatch(JSContext* cx, unsigned argc, JS::Value* vp);
// Constructor for the protocol class, which is called from the inherited
// classes.
static bool Constructor(JSContext* cx, unsigned argc, JS::Value* vp);
// Default implementations for various IPDL stuff. Abstract methods throw on
// call because they MUST be reimplemented.
static bool RecvDelete(JSContext* cx, unsigned argc, JS::Value* vp);
static bool RecvConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
static bool AbstractRecvMessage(JSContext* cx, unsigned argc, JS::Value* vp);
static bool AbstractAlloc(JSContext* cx, unsigned argc, JS::Value* vp);
// Our IPDLProtocol JS class custom operations.
static constexpr JSClassOps sIPDLJSClassOps = {};
};
} // ipdl
} // mozilla
#endif // dom_base_ipdl_bindings_IPDLProtocol_h

Просмотреть файл

@ -1,460 +0,0 @@
/* -*- 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 https://mozilla.org/MPL/2.0/. */
#include "IPDLProtocolInstance.h"
#include <cfloat>
#include "IPCInterface.h"
#include "ipdl_ffi_generated.h"
#include "mozilla/dom/DOMMozPromiseRequestHolder.h"
#include "mozilla/dom/Promise.h"
#include "nsJSUtils.h"
#include "wrapper.h"
#include "mozilla/dom/IPDL.h"
namespace mozilla {
namespace ipdl {
NS_IMPL_CYCLE_COLLECTION_CLASS(IPDLProtocolInstance)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IPDLProtocolInstance)
tmp->mInstanceObject = nullptr;
tmp->mAsyncReturnOverride = nullptr;
mozilla::DropJSObjects(tmp);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IPDLProtocolInstance)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IPDLProtocolInstance)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mInstanceObject)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mAsyncReturnOverride)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(IPDLProtocolInstance)
NS_IMPL_CYCLE_COLLECTING_RELEASE(IPDLProtocolInstance)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IPDLProtocolInstance)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
IPDLProtocolInstance::IPDLProtocolInstance(ipc::IPCInterface* aIPCInterface,
uint32_t aChannelId,
IPDLProtocol* aIPDLProtocol,
JS::HandleObject aInstanceObject)
: mChannelId(aChannelId)
, mIPDLProtocol(aIPDLProtocol)
, mInstanceObject(aInstanceObject)
, mAsyncReturnOverride(nullptr)
, mConstructing(true)
{
mozilla::HoldJSObjects(this);
SetIPCInterface(aIPCInterface);
}
IPDLProtocolInstance::~IPDLProtocolInstance()
{
mInstanceObject = nullptr;
mAsyncReturnOverride = nullptr;
mozilla::DropJSObjects(this);
}
void
IPDLProtocolInstance::SetIPCInterface(ipc::IPCInterface* aIPCInterface)
{
mIPCInterface = aIPCInterface;
if (mIPCInterface) {
// If we're setting the interface, it means that we're done with the
// constructor.
mConstructing = false;
NS_NAMED_LITERAL_CSTRING(parentSuffix, "Parent");
NS_NAMED_LITERAL_CSTRING(childSuffix, "Child");
// Hook up this instance to the IPC interface for receiving messages.
mIPCInterface->SetIPDLInstance(
mChannelId,
mIPDLProtocol->GetProtocolName() +
(mIPDLProtocol->GetSide() == IPDLSide::Child ? childSuffix
: parentSuffix),
this);
}
}
bool
IPDLProtocolInstance::SendConstructor(JSContext* aCx,
JS::HandleObject aThisObj,
const nsCString& aFuncName,
JS::CallArgs aArgs)
{
// Make sure the instance can send stuff.
if (!CheckIsAvailable(aCx)) {
return false;
}
NS_NAMED_LITERAL_CSTRING(sendPrefix, "send");
NS_NAMED_LITERAL_CSTRING(constructorSuffix, "Constructor");
nsAutoCString allocName(NS_LITERAL_CSTRING("alloc"));
allocName.Append(Substring(aFuncName,
sendPrefix.Length(),
aFuncName.Length() - sendPrefix.Length() -
constructorSuffix.Length()));
JS::HandleValueArray argsArray(aArgs);
// Construct the sub protocol by calling our alloc function.
JS::RootedValue constructedValue(aCx);
if (!JS_CallFunctionName(
aCx, aThisObj, allocName.get(), argsArray, &constructedValue)) {
aArgs.rval().setUndefined();
return false;
}
JS::RootedObject constructedObject(aCx, &constructedValue.toObject());
// Add the IPC interface to the newly constructed object.
auto instance = static_cast<IPDLProtocolInstance*>(JS_GetPrivate(constructedObject.get()));
if (!instance) {
JS_ReportErrorUTF8(aCx, "Couldn't get protocol instance object from private date field");
return false;
}
instance->SetIPCInterface(mIPCInterface);
// Create new call arguments from the current call arguments to be passed to
// SendMessage.
JS::AutoValueVector newArgsVec(aCx);
if (!newArgsVec.initCapacity(aArgs.length() +
3)) { // this + callee + channelID
JS_ReportErrorUTF8(
aCx, "Could not initialize new argument vector for constructor");
aArgs.rval().setUndefined();
return false;
}
JS::CallArgs newArgs =
JS::CallArgsFromVp(aArgs.length() + 1, newArgsVec.begin());
newArgs.setThis(aArgs.thisv().get());
newArgs.setCallee(aArgs.calleev().get());
// We add the channel ID as the first argument.
JS::RootedValue channelID(aCx, JS::NumberValue(instance->ChannelId()));
newArgs[0].set(channelID);
// We copy all the other arguments.
for (unsigned int i = 0; i < aArgs.length(); i++) {
newArgs[i + 1].set(aArgs[i]);
}
// We send the construction message, overriding the return result
// with the constructed object.
bool res = SendMessage(aCx, aFuncName, newArgs, constructedObject);
aArgs.rval().set(newArgs.rval());
return res;
}
bool
IPDLProtocolInstance::SendDelete(JSContext* aCx,
const nsCString& aFuncName,
JS::CallArgs aArgs)
{
// Make sure the instance can send stuff.
if (!CheckIsAvailable(aCx)) {
return false;
}
bool res = SendMessage(aCx, aFuncName, aArgs);
return res;
}
bool
IPDLProtocolInstance::SendMessage(JSContext* aCx,
const nsCString& aFuncName,
JS::CallArgs aArgs,
JS::HandleObject aReturnOverride)
{
// Make sure the instance can send stuff.
if (!CheckIsAvailable(aCx)) {
return false;
}
// Get the corresponding message AST struct from our lookup table.
auto message = mIPDLProtocol->GetMessageDecl(aFuncName);
// Sanity check. Usually the JS engine will trigger a type error saying it
// doesn't find the function before we reach this stage. If this assertion
// is triggered, it means there is a flaw in the way we add messages.
MOZ_ASSERT(message);
auto& inParams = message->in_params;
auto expectedArgCount = inParams.Length();
// Since our arg count reflects a well defined protocol, should we
// require strict arg count?
if (!aArgs.requireAtLeast(aCx, aFuncName.get(), expectedArgCount)) {
return false;
}
// Check that every param and args have matching types.
for (size_t i = 0; i < inParams.Length(); i++) {
if (!mIPDLProtocol->CheckParamTypeSpec(
aCx, aArgs.get(i), inParams.ElementAt(i))) {
JS_ReportErrorUTF8(
aCx,
"Type mismatch on %zuth argument of `%s`: expected %s, got %s",
i,
aFuncName.get(),
IPDLProtocol::JoinQualifiedId(inParams.ElementAt(i).type_spec.spec)
.get(),
InformalValueTypeName(aArgs.get(i)));
aArgs.rval().setUndefined();
return false;
}
}
NS_NAMED_LITERAL_CSTRING(sendPrefix, "send");
nsAutoCString messageName(
Substring(aFuncName,
sendPrefix.Length(),
aFuncName.Length() - sendPrefix.Length())); // trim leading `send`
// Prepare the argument array for sending to the IPC interface.
auto argArray = JS::HandleValueArray(aArgs);
// Send the message to the underlying IPC interface depending on the send
// semantics.
JS::RootedValue retVal(aCx);
bool ret;
switch (message->send_semantics) {
case ffi::SendSemantics::Async:
retVal = SendAsyncMessage(aCx, messageName, argArray, aReturnOverride);
ret = true;
break;
case ffi::SendSemantics::Sync:
ret = SendSyncMessage(aCx, messageName, argArray, &retVal);
if (aReturnOverride.get()) {
retVal.setObject(*aReturnOverride);
}
break;
case ffi::SendSemantics::Intr:
ret = SendIntrMessage(aCx, messageName, argArray, &retVal);
if (aReturnOverride.get()) {
retVal.setObject(*aReturnOverride);
}
break;
}
aArgs.rval().set(retVal);
return ret;
}
JS::Value
IPDLProtocolInstance::SendAsyncMessage(JSContext* aCx,
const nsCString& aFuncName,
const JS::HandleValueArray& aArgArray,
JS::HandleObject aReturnOverride)
{
// Create a JS/DOM promise to return.
// It will resolve to the result of the message call.
ErrorResult aRv;
RefPtr<dom::Promise> outer =
dom::Promise::Create(mIPDLProtocol->GetGlobal(), aRv);
if (aRv.Failed()) {
return JS::UndefinedValue();
}
// This wraps the AsyncMessagePromise that we use for the actual IPC/C++
// message so that if the global object gets disconnected, that promise also
// gets disconnected and is not left dangling.
auto promiseHolder = MakeRefPtr<
dom::DOMMozPromiseRequestHolder<ipc::IPCInterface::AsyncMessagePromise>>(
mIPDLProtocol->GetGlobal());
bool hasReturnOverride = (aReturnOverride.get());
mAsyncReturnOverride = aReturnOverride;
// Actually send the message to the IPC interface.
// If the C++ promise succeeds, then we resolve the JS promise.
// If it fails, we reject the JS promise.
// We also make sure that the promise holder tracks our promise.
mIPCInterface
->SendAsyncMessage(
aCx, mIPDLProtocol->GetProtocolName(), mChannelId, aFuncName, aArgArray)
->Then(mIPDLProtocol->GetGlobal()->EventTargetFor(TaskCategory::Other),
__func__,
[&asyncReturnOverride = mAsyncReturnOverride, promiseHolder, outer, hasReturnOverride](
const JS::Value& aResult) {
// Tell the promise holder that our promise is resolved.
promiseHolder->Complete();
// Note, you can access the holder's bound global in
// your reaction handler. Its mostly likely set if
// the handler fires, but you still must check for
// its existence since something could disconnect
// the global between when the MozPromise reaction
// runnable is queued and when it actually runs.
nsIGlobalObject* global = promiseHolder->GetParentObject();
NS_ENSURE_TRUE_VOID(global);
// Resolve the JS promise with our result.
// If we have an override return value, return it instead.
if (hasReturnOverride) {
outer->MaybeResolve(JS::ObjectValue(*asyncReturnOverride));
asyncReturnOverride = nullptr;
} else {
outer->MaybeResolve(aResult);
}
},
[promiseHolder, outer, aCx](nsCString aRv) {
// Tell the promise holder that our promise is resolved.
promiseHolder->Complete();
// Reject the JS promise with our error message.
JS::RootedValue retVal(
aCx, JS::StringValue(JS_NewStringCopyZ(aCx, aRv.get())));
outer->MaybeReject(aCx, retVal);
})
->Track(*promiseHolder);
// Get the JSObject corresponding to the JS promise.
JS::RootedObject retObj(aCx, outer->PromiseObj());
return JS::ObjectValue(*retObj);
}
bool
IPDLProtocolInstance::SendSyncMessage(JSContext* aCx,
const nsCString& aFuncName,
const JS::HandleValueArray& aArgArray,
JS::MutableHandleValue aRet)
{
// Simply call the underlying IPC interface directly.
return mIPCInterface->SendSyncMessage(aCx,
mIPDLProtocol->GetProtocolName(),
mChannelId,
aFuncName,
aArgArray,
aRet);
}
bool
IPDLProtocolInstance::SendIntrMessage(JSContext* aCx,
const nsCString& aFuncName,
const JS::HandleValueArray& aArgArray,
JS::MutableHandleValue aRet)
{
// Simply call the underlying IPC interface directly.
return mIPCInterface->SendIntrMessage(aCx,
mIPDLProtocol->GetProtocolName(),
mChannelId,
aFuncName,
aArgArray,
aRet);
}
bool
IPDLProtocolInstance::RecvMessage(JSContext* aCx,
const nsCString& aMessageName,
const JS::HandleValueArray& aArgArray,
JS::MutableHandleValue aRet)
{
// Make sure the instance can receive stuff.
if (!CheckIsAvailable(aCx)) {
return false;
}
const nsAutoCString& funcName = NS_LITERAL_CSTRING("recv") + aMessageName;
JS::RootedValue prop(aCx);
NS_NAMED_LITERAL_CSTRING(constructorSuffix, "Constructor");
// Check if the message name ends with the constructor suffix.
if (aMessageName.RFind(
constructorSuffix.get(), false, -1, constructorSuffix.Length()) != kNotFound) {
nsAutoCString protocolName(Substring(
aMessageName, 0, aMessageName.Length() - constructorSuffix.Length()));
nsAutoCString allocName(protocolName);
allocName.InsertLiteral("alloc", 0);
// Allocate the new sub protocol instance by calling the alloc method.
JS::RootedValue allocatedProtocolValue(aCx);
JS::RootedObject objectInstance(aCx, mInstanceObject);
JS_CallFunctionName(
aCx,
objectInstance,
allocName.get(),
// Ignore the leading channel ID.
JS::HandleValueArray::subarray(aArgArray, 1, aArgArray.length() - 1),
&allocatedProtocolValue);
JS::RootedObject allocatedProtocol(aCx, &allocatedProtocolValue.toObject());
auto instance = static_cast<IPDLProtocolInstance*>(JS_GetPrivate(allocatedProtocol.get()));
if (!instance) {
JS_ReportErrorUTF8(aCx, "Couldn't get protocol instance object from private date field");
return false;
}
// Set the IPC interface of the constructed protocol object.
instance->SetIPCInterface(mIPCInterface);
nsAutoCString constructorName(protocolName);
constructorName.InsertLiteral("recv", 0);
constructorName.AppendLiteral("Constructor");
// Call the recvConstructor function
JS::RootedValue unusedResult(aCx);
JS_CallFunctionName(aCx,
objectInstance,
constructorName.get(),
JS::HandleValueArray(allocatedProtocolValue),
&unusedResult);
return true;
}
// Otherwise if we have a regular message, just call it.
JS::RootedObject objInstance(aCx, mInstanceObject);
if (!JS_GetProperty(aCx, objInstance, funcName.get(), &prop)) {
aRet.setUndefined();
return false;
}
if (!JS_CallFunctionValue(aCx, objInstance, prop, aArgArray, aRet)) {
aRet.setUndefined();
return false;
}
// If we receive a delete, mark our protocol instance as deleted.
if (aMessageName.Equals("__delete__")) {
aRet.setUndefined();
JS_SetPrivate(mInstanceObject, nullptr);
mIPCInterface->RemoveIPDLInstance(mChannelId,
mIPDLProtocol->GetProtocolName());
// ALWAYS PUT THIS LAST, DO NOT ACCESS `this` AFTERWARDS
mIPDLProtocol->RemoveInstance(this);
}
return true;
}
JSObject*
IPDLProtocolInstance::GetInstanceObject()
{
return mInstanceObject;
}
} // ipdl
} // mozilla

Просмотреть файл

@ -1,134 +0,0 @@
/* -*- 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 https://mozilla.org/MPL/2.0/. */
#ifndef dom_base_ipdl_bindings_IPDLProtocolInstance_h
#define dom_base_ipdl_bindings_IPDLProtocolInstance_h
#include "jsapi.h"
#include "nsStringFwd.h"
#include "nsCycleCollectionParticipant.h"
namespace mozilla {
namespace dom {
class IPDL;
} // dom
namespace ipdl {
class IPDLProtocol;
namespace ipc {
class IPCInterface;
} // ipc
namespace ffi {
struct AST;
struct Union;
struct Struct;
struct NamedProtocol;
struct MessageDecl;
struct TranslationUnit;
struct Param;
struct TypeSpec;
struct QualifiedId;
struct Namespace;
} // ffi
/**
* Represents an IPDL protocol object instance, either created automatically if the protocol is top level,
* or allocated from the parent protocol.
*/
class IPDLProtocolInstance : public nsISupports
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IPDLProtocolInstance)
IPDLProtocolInstance(ipc::IPCInterface* aIPCInterface,
uint32_t aChannelId,
IPDLProtocol* aIPDLProtocol,
JS::HandleObject aInstanceObject);
// Returns the JSObject corresponding to this instance.
JSObject* GetInstanceObject();
// Returns the channel ID of this instance.
uint32_t ChannelId() { return mChannelId; };
// Represents the IPDL sendSubProtocolConstructor functions.
bool SendConstructor(JSContext* aCx,
JS::HandleObject aThisObj,
const nsCString& aFuncName,
JS::CallArgs aArgs);
// Represents the IPDL send__delete__ function.
bool SendDelete(JSContext* aCx, const nsCString& aFuncName, JS::CallArgs aArgs);
// Performs param/arg type checking and calls a sub-function depending on
// the message send semantics.
bool SendMessage(JSContext* aCx,
const nsCString& aFuncName,
JS::CallArgs aArgs,
JS::HandleObject aReturnOverride = nullptr);
// Sends an async message by calling the underlying IPC interface, returning
// a promise to the return value object.
JS::Value SendAsyncMessage(JSContext* aCx,
const nsCString& aFuncName,
const JS::HandleValueArray& aArgArray,
JS::HandleObject aReturnOverride = nullptr);
// Sends a sync message by calling the underlying IPC interface, returning
// the return value object.
bool SendSyncMessage(JSContext* aCx,
const nsCString& aFuncName,
const JS::HandleValueArray& aArgArray,
JS::MutableHandleValue aRet);
// Sends an intr message by calling the underlying IPC interface, returning
// the return value object.
bool SendIntrMessage(JSContext* aCx,
const nsCString& aFuncName,
const JS::HandleValueArray& aArgArray,
JS::MutableHandleValue aRet);
// Receives a message from the underlying IPC interface, returning the result
// if any.
bool RecvMessage(JSContext* aCx,
const nsCString& aMessageName,
const JS::HandleValueArray& aArgArray,
JS::MutableHandleValue aRet);
// Sets the IPC interface of the IPDL instance.
void SetIPCInterface(ipc::IPCInterface* aIPCInterface);
protected:
virtual ~IPDLProtocolInstance();
// Whether this protocol is being constructed (we're in the constructor of the instance).
bool IsConstructing() { return mConstructing; }
bool CheckIsAvailable(JSContext* aCx)
{
if (IsConstructing()) {
JS_ReportErrorUTF8(aCx,
"Protocol is constructing, cannot be used yet.");
return false;
}
return true;
}
ipc::IPCInterface* MOZ_NON_OWNING_REF mIPCInterface;
uint32_t mChannelId;
IPDLProtocol* MOZ_NON_OWNING_REF mIPDLProtocol;
JS::Heap<JSObject*> mInstanceObject;
JS::Heap<JSObject*> mAsyncReturnOverride;
bool mConstructing;
};
} // ipdl
} // mozilla
#endif // dom_base_ipdl_bindings_IPDLProtocolInstance_h

Просмотреть файл

@ -1,198 +0,0 @@
#include "PContentChildIPCInterface.h"
#include "mozilla/dom/ContentChild.h"
namespace mozilla {
namespace ipdl {
namespace ipc {
PContentChildIPCInterface::PContentChildIPCInterface(dom::IPDL* aIPDL,
dom::ContentChild* aCc)
: IPCInterface(aIPDL)
, mCc(aCc)
{
mCc->RegisterIPDLIPCInterface(this);
}
/* virtual */ mozilla::ipc::IPCResult
PContentChildIPCInterface::RecvMessage(
const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessage,
const dom::ClonedMessageData& aData,
nsTArray<dom::ipc::StructuredCloneData>* aReturnData)
{
return RecvMessageCommon(mCc,
IPDLSide::Child,
aProtocolName,
aChannelId,
aMessage,
aData,
aReturnData);
}
/* virtual */ RefPtr<IPCInterface::AsyncMessagePromise>
PContentChildIPCInterface::SendAsyncMessage(JSContext* aCx,
const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessageName,
const InArgs& aArgs)
{
// Create a new Promise to resolve the async call.
auto promise = MakeRefPtr<AsyncMessagePromise::Private>(__func__);
auto promiseHolder = MakeRefPtr<
dom::DOMMozPromiseRequestHolder<dom::ContentChild::AsyncMessageIPDLPromise>>(
xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx)));
// Write arguments to the StructuredCloneData.
dom::ipc::StructuredCloneData data;
ErrorResult errRes;
auto* argsObjPtr = JS_NewArrayObject(aCx, aArgs);
if (!argsObjPtr) {
promise->Reject(
NS_LITERAL_CSTRING("Failed to allocate new array object"),
__func__);
return promise;
}
JS::RootedObject argsObj(aCx, argsObjPtr);
JS::RootedValue argsVal(aCx, JS::ObjectValue(*argsObj));
data.Write(aCx, argsVal, errRes);
if (NS_WARN_IF(errRes.Failed())) {
promise->Reject(
NS_LITERAL_CSTRING("Failed to write arguments to StructuredCloneData"),
__func__);
return promise;
}
// Wrap the StructuredCloneData in a ClonedMessageData.
dom::ClonedMessageData cmd;
if (!data.BuildClonedMessageDataForChild((dom::nsIContentChild*)mCc, cmd)) {
promise->Reject(
NS_LITERAL_CSTRING("Failed to write arguments to StructuredCloneData"),
__func__);
return promise;
}
// Send the actual message through the ContentChild
mCc->SendAsyncMessageIPDL(aProtocolName, aChannelId, aMessageName, cmd)
->Then(promiseHolder->GetParentObject()->EventTargetFor(TaskCategory::Other),
__func__,
[promiseHolder, promise](nsTArray<dom::ipc::StructuredCloneData> aRes) {
promiseHolder->Complete();
// If the array is empty, it means we got an error.
if (aRes.IsEmpty()) {
promise->Reject(NS_LITERAL_CSTRING(
"Error in RecvAsyncMessage in parent process"),
__func__);
return;
}
nsIGlobalObject* global = promiseHolder->GetParentObject();
NS_ENSURE_TRUE_VOID(global);
dom::AutoEntryScript aes(global, "SendAsyncMessageIPDL");
JSContext* cx = aes.cx();
JS::RootedValue ret(cx);
ErrorResult rv;
aRes.ElementAt(0).Read(cx, &ret, rv);
if (NS_WARN_IF(rv.Failed())) {
promise->Reject(
NS_LITERAL_CSTRING(
"Failed to read return value from StructuredCloneData"),
__func__);
} else {
promise->Resolve(ret, __func__);
}
},
[promiseHolder, promise](::mozilla::ipc::ResponseRejectReason aReason) {
promiseHolder->Complete();
promise->Reject(nsPrintfCString(
"IPC error when calling SendAsyncMessageIPDL, "
"see error message above. Reason: %d",
(unsigned int)aReason),
__func__);
})->Track(*promiseHolder);
return promise;
}
/* virtual */ bool
PContentChildIPCInterface::SendSyncMessage(JSContext* aCx,
const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessageName,
const InArgs& aArgs,
OutObject aRet)
{
// Write arguments to the StructuredCloneData.
dom::ipc::StructuredCloneData data;
ErrorResult errRes;
auto* argsObjPtr = JS_NewArrayObject(aCx, aArgs);
if (!argsObjPtr) {
aRet.setUndefined();
return false;
}
JS::RootedObject argsObj(aCx, argsObjPtr);
JS::RootedValue argsVal(aCx, JS::ObjectValue(*argsObj));
data.Write(aCx, argsVal, errRes);
if (NS_WARN_IF(errRes.Failed())) {
JS_ReportErrorUTF8(aCx, "Failed to write arguments to StructuredCloneData");
aRet.setUndefined();
return false;
}
// Wrap the StructuredCloneData in a ClonedMessageData.
dom::ClonedMessageData cmd;
if (!data.BuildClonedMessageDataForChild((dom::nsIContentChild*)mCc, cmd)) {
JS_ReportErrorUTF8(aCx, "Failed to build cloned message data for arguments");
aRet.setUndefined();
return false;
}
nsTArray<dom::ipc::StructuredCloneData> retData;
// Send the actual message through the ContentChild
if (!mCc->SendSyncMessageIPDL(
aProtocolName, aChannelId, aMessageName, cmd, &retData)) {
JS_ReportErrorUTF8(aCx, "IPC error when calling SendSyncMessageIPDL");
aRet.setUndefined();
return false;
}
// If the array is empty, it means we got an error.
if (retData.IsEmpty()) {
JS_ReportErrorUTF8(aCx, "Error in RecvSyncMessageIPDL in parent process");
aRet.setUndefined();
return false;
}
retData.ElementAt(0).Read(aCx, aRet, errRes);
if (NS_WARN_IF(errRes.Failed())) {
JS_ReportErrorUTF8(aCx,
"Failed to read return value from StructuredCloneData");
aRet.setUndefined();
return false;
}
return true;
}
} // ipc
} // ipdl
} // mozilla

Просмотреть файл

@ -1,77 +0,0 @@
/* -*- 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 https://mozilla.org/MPL/2.0/. */
#ifndef dom_base_ipdl_bindings_pcontentchildipcinterface_h
#define dom_base_ipdl_bindings_pcontentchildipcinterface_h
#include "IPCInterface.h"
namespace mozilla {
namespace dom {
class IPDL;
class ContentChild;
namespace ipc {
class StructuredCloneData;
}
}
namespace ipdl {
namespace ipc {
class PContentChildIPCInterface : public IPCInterface
{
public:
PContentChildIPCInterface(dom::IPDL* aIPDL, dom::ContentChild* aCc);
virtual ~PContentChildIPCInterface() = default;
// Receive a message from IPC.
virtual mozilla::ipc::IPCResult RecvMessage(
const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessage,
const dom::ClonedMessageData& aData,
nsTArray<dom::ipc::StructuredCloneData>* aReturnData) override;
// Send an async message through IPC.
virtual RefPtr<AsyncMessagePromise> SendAsyncMessage(
JSContext* aCx,
const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessageName,
const InArgs& aArgs) override;
// Send a sync message through IPC.
virtual bool SendSyncMessage(JSContext* aCx,
const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessageName,
const InArgs& aArgs,
OutObject aRet) override;
// Send an intr message through IPC.
virtual bool SendIntrMessage(JSContext* aCx,
const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessageName,
const InArgs& aArgs,
OutObject aRet) override
{
MOZ_CRASH("Unimplemented");
aRet.setUndefined();
return false;
}
protected:
dom::ContentChild* mCc;
};
} // ipc
} // ipdl
} // mozilla
#endif // dom_base_ipdl_bindings_pcontentchildipcinterface_h

Просмотреть файл

@ -1,131 +0,0 @@
#include "PContentParentIPCInterface.h"
#include "mozilla/dom/ContentParent.h"
namespace mozilla {
namespace ipdl {
namespace ipc {
PContentParentIPCInterface::PContentParentIPCInterface(dom::IPDL* aIPDL,
dom::ContentParent* aCp)
: IPCInterface(aIPDL)
, mCp(aCp)
{
mCp->RegisterIPDLIPCInterface(this);
}
/* virtual */ mozilla::ipc::IPCResult
PContentParentIPCInterface::RecvMessage(
const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessage,
const dom::ClonedMessageData& aData,
nsTArray<dom::ipc::StructuredCloneData>* aReturnData)
{
return RecvMessageCommon(mCp,
IPDLSide::Parent,
aProtocolName,
aChannelId,
aMessage,
aData,
aReturnData);
}
/* virtual */ RefPtr<IPCInterface::AsyncMessagePromise>
PContentParentIPCInterface::SendAsyncMessage(JSContext* aCx,
const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessageName,
const InArgs& aArgs)
{
auto promise = MakeRefPtr<AsyncMessagePromise::Private>(__func__);
auto promiseHolder = MakeRefPtr<
dom::DOMMozPromiseRequestHolder<dom::ContentParent::AsyncMessageIPDLPromise>>(
xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx)));
// Write arguments to the StructuredCloneData.
dom::ipc::StructuredCloneData data;
ErrorResult errRes;
auto* argsObjPtr = JS_NewArrayObject(aCx, aArgs);
if (!argsObjPtr) {
promise->Reject(
NS_LITERAL_CSTRING("Failed to allocate new array object"),
__func__);
return promise;
}
JS::RootedObject argsObj(aCx, argsObjPtr);
JS::RootedValue argsVal(aCx, JS::ObjectValue(*argsObj));
data.Write(aCx, argsVal, errRes);
if (NS_WARN_IF(errRes.Failed())) {
promise->Reject(
NS_LITERAL_CSTRING("Failed to write arguments to StructuredCloneData"),
__func__);
return promise;
}
// Wrap the StructuredCloneData in a ClonedMessageData.
dom::ClonedMessageData cmd;
if (!data.BuildClonedMessageDataForParent((dom::nsIContentParent*)mCp, cmd)) {
promise->Reject(
NS_LITERAL_CSTRING("Failed to write arguments to StructuredCloneData"),
__func__);
return promise;
}
// Send the actual message through the ContentParent
mCp->SendAsyncMessageIPDL(aProtocolName, aChannelId, aMessageName, cmd)
->Then(promiseHolder->GetParentObject()->EventTargetFor(TaskCategory::Other),
__func__,
[promiseHolder, promise](nsTArray<dom::ipc::StructuredCloneData> aRes) {
promiseHolder->Complete();
// If the array is empty, it means we got an error.
if (aRes.IsEmpty()) {
promise->Reject(NS_LITERAL_CSTRING(
"Error in RecvAsyncMessage in parent process"),
__func__);
return;
}
nsIGlobalObject* global = promiseHolder->GetParentObject();
NS_ENSURE_TRUE_VOID(global);
dom::AutoEntryScript aes(global, "SendAsyncMessageIPDL");
JSContext* cx = aes.cx();
JS::RootedValue ret(cx);
ErrorResult rv;
aRes.ElementAt(0).Read(cx, &ret, rv);
if (NS_WARN_IF(rv.Failed())) {
promise->Reject(
NS_LITERAL_CSTRING(
"Failed to read return value from StructuredCloneData"),
__func__);
} else {
promise->Resolve(ret, __func__);
}
},
[promiseHolder, promise](::mozilla::ipc::ResponseRejectReason aReason) {
promiseHolder->Complete();
promise->Reject(nsPrintfCString(
"IPC error when calling SendAsyncMessageIPDL, "
"see error message above. Reason: %d",
(unsigned int)aReason),
__func__);
})->Track(*promiseHolder);
return promise;
}
} // ipc
} // ipdl
} // mozilla

Просмотреть файл

@ -1,81 +0,0 @@
/* -*- 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 https://mozilla.org/MPL/2.0/. */
#ifndef dom_base_ipdl_bindings_pcontentparentipcinterface_h
#define dom_base_ipdl_bindings_pcontentparentipcinterface_h
#include "IPCInterface.h"
namespace mozilla {
namespace dom {
class IPDL;
class ContentParent;
namespace ipc {
class StructuredCloneData;
}
}
namespace ipdl {
namespace ipc {
class PContentParentIPCInterface : public IPCInterface
{
public:
explicit PContentParentIPCInterface(dom::IPDL* aIPDL, dom::ContentParent* aCp);
virtual ~PContentParentIPCInterface() = default;
// Receive a message from IPC.
virtual mozilla::ipc::IPCResult RecvMessage(
const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessage,
const dom::ClonedMessageData& aData,
nsTArray<dom::ipc::StructuredCloneData>* aReturnData) override;
// Send an async message through IPC.
virtual RefPtr<AsyncMessagePromise> SendAsyncMessage(
JSContext* aCx,
const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessageName,
const InArgs& aArgs) override;
// Send a sync message through IPC.
virtual bool SendSyncMessage(JSContext* aCx,
const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessageName,
const InArgs& aArgs,
OutObject aRet) override
{
MOZ_CRASH("Unimplemented");
aRet.setUndefined();
return false;
}
// Send an intr message through IPC.
virtual bool SendIntrMessage(JSContext* aCx,
const nsCString& aProtocolName,
const uint32_t& aChannelId,
const nsCString& aMessageName,
const InArgs& aArgs,
OutObject aRet) override
{
MOZ_CRASH("Unimplemented");
aRet.setUndefined();
return false;
}
protected:
dom::ContentParent* mCp;
};
} // ipc
} // ipdl
} // mozilla
#endif // dom_base_ipdl_bindings_pcontentparentipcinterface_h

Просмотреть файл

@ -1,24 +0,0 @@
# rustup run nightly cbindgen toolkit/library/rust/ --crate ipdl --lockfile Cargo.lock -o dom/base/ipdl_bindings/ipdl_ffi_generated.h
header="""
/* -*- 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 https://mozilla.org/MPL/2.0/. */
#ifndef ipdl_ffi_generated_h
#define ipdl_ffi_generated_h
#include <nsTArray.h>
#include <nsString.h>"""
trailer="""
#endif // ipdl_ffi_generated_h"""
autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
namespaces = ["mozilla", "ipdl", "ffi"]
language="C++"
[export.rename]
"ThinVec" = "nsTArray"

Просмотреть файл

@ -1,181 +0,0 @@
/* -*- 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 https://mozilla.org/MPL/2.0/. */
#ifndef ipdl_ffi_generated_h
#define ipdl_ffi_generated_h
#include <nsTArray.h>
#include <nsString.h>
/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
#include <cstdint>
#include <cstdlib>
namespace mozilla {
namespace ipdl {
namespace ffi {
enum class Compress {
None,
Enabled,
All,
};
enum class CxxTypeKind {
Struct,
Class,
};
enum class Direction {
ToParent,
ToChild,
ToParentOrChild,
};
enum class FileType {
Protocol,
Header,
};
enum class Nesting {
None,
InsideSync,
InsideCpow,
};
enum class Priority {
Normal,
High,
Input,
};
enum class SendSemantics {
Async,
Sync,
Intr,
};
struct AST;
struct Location {
nsCString file_name;
uintptr_t lineno;
uintptr_t colno;
};
struct Identifier {
nsCString id;
Location loc;
};
struct Namespace {
Identifier name;
nsTArray<nsCString> namespaces;
};
using TUId = int32_t;
struct QualifiedId {
Identifier base_id;
nsTArray<nsCString> quals;
};
struct TypeSpec {
QualifiedId spec;
bool array;
bool nullable;
};
struct UsingStmt {
TypeSpec cxx_type;
nsCString header;
Maybe<CxxTypeKind> kind;
bool refcounted;
};
struct StructField {
TypeSpec type_spec;
Identifier name;
};
struct Struct {
Namespace ns;
nsTArray<StructField> fields;
};
struct Union {
Namespace ns;
nsTArray<TypeSpec> types;
};
struct Param {
Identifier name;
TypeSpec type_spec;
};
struct MessageDecl {
Identifier name;
SendSemantics send_semantics;
Nesting nested;
Priority prio;
Direction direction;
nsTArray<Param> in_params;
nsTArray<Param> out_params;
Compress compress;
bool verify;
};
struct Protocol {
SendSemantics send_semantics;
Nesting nested;
nsTArray<Identifier> managers;
nsTArray<Identifier> manages;
nsTArray<MessageDecl> messages;
};
struct NamedProtocol {
Namespace ns;
Protocol protocol;
};
struct TranslationUnit {
Namespace ns;
FileType file_type;
nsCString file_name;
nsTArray<nsCString> cxx_includes;
nsTArray<TUId> includes;
nsTArray<UsingStmt> using_stmt;
nsTArray<Struct> structs;
nsTArray<Union> unions;
Maybe<NamedProtocol> protocol;
};
extern "C" {
/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
const TranslationUnit *ipdl_ast_get_tu(const AST *ast, TUId tuid);
TUId ipdl_ast_main_tuid(const AST *ast);
void ipdl_free_ast(const AST *ast);
const AST *ipdl_parse_file(const nsACString *ipdl_file,
nsACString *error_string,
uint8_t (*source_string_loader)(const nsACString*, nsACString*),
uint8_t (*resolve_relative_path)(const nsACString*, const nsACString*, nsACString*),
uint8_t (*equals)(const nsACString*, const nsACString*));
} // extern "C"
} // namespace ffi
} // namespace ipdl
} // namespace mozilla
/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
#endif // ipdl_ffi_generated_h

Просмотреть файл

@ -1,29 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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('/ipc/chromium/chromium-config.mozbuild')
EXPORTS.mozilla.ipdl = [
'IPDLProtocol.h',
'IPDLProtocolInstance.h'
]
EXPORTS.mozilla.ipdl.ipc = [
'IPCInterface.h',
'PContentChildIPCInterface.h',
'PContentParentIPCInterface.h'
]
UNIFIED_SOURCES += [
'IPCInterface.cpp',
'IPDLProtocol.cpp',
'IPDLProtocolInstance.cpp',
'PContentChildIPCInterface.cpp',
'PContentParentIPCInterface.cpp',
'wrapper.cpp',
]
FINAL_LIBRARY = 'xul'

Просмотреть файл

@ -1,529 +0,0 @@
/* 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/. */
extern crate ipdl;
extern crate nsstring;
extern crate thin_vec;
#[macro_use]
extern crate mfbt_maybe;
use ipdl::ast;
use ipdl::parser;
use ipdl::parser::FileURI;
use mfbt_maybe::{Maybe, MaybeTrait};
use nsstring::{nsACString, nsCStr, nsCString};
use std::collections::HashMap;
use std::iter::FromIterator;
use std::str;
use thin_vec::ThinVec;
use std::hash::Hash;
use std::hash::Hasher;
maybe!(CxxTypeKind);
maybe!(NamedProtocol);
fn vec_to_thinvec<T, F: Into<T>>(vec: Vec<F>) -> ThinVec<T> {
ThinVec::from_iter(vec.into_iter().map(|x| x.into()))
}
#[repr(C)]
pub struct QualifiedId {
pub base_id: Identifier,
pub quals: ThinVec<nsCString>,
}
impl From<ast::QualifiedId> for QualifiedId {
fn from(qi: ast::QualifiedId) -> Self {
QualifiedId {
base_id: qi.base_id.into(),
quals: ThinVec::from_iter(qi.quals.into_iter().map(|x| x.into())),
}
}
}
#[repr(C)]
pub struct TypeSpec {
pub spec: QualifiedId,
pub array: bool,
pub nullable: bool,
}
impl From<ast::TypeSpec> for TypeSpec {
fn from(ts: ast::TypeSpec) -> Self {
TypeSpec {
spec: ts.spec.into(),
array: ts.array,
nullable: ts.nullable,
}
}
}
#[repr(C)]
pub struct Param {
pub name: Identifier,
pub type_spec: TypeSpec,
}
impl From<ast::Param> for Param {
fn from(p: ast::Param) -> Self {
Param {
name: p.name.into(),
type_spec: p.type_spec.into(),
}
}
}
#[repr(C)]
pub struct StructField {
pub type_spec: TypeSpec,
pub name: Identifier,
}
impl From<ast::StructField> for StructField {
fn from(sf: ast::StructField) -> Self {
StructField {
type_spec: sf.type_spec.into(),
name: sf.name.into(),
}
}
}
#[repr(C)]
pub struct Namespace {
pub name: Identifier,
pub namespaces: ThinVec<nsCString>,
}
impl From<ast::Namespace> for Namespace {
fn from(ns: ast::Namespace) -> Self {
Namespace {
name: ns.name.into(),
namespaces: vec_to_thinvec(ns.namespaces),
}
}
}
#[repr(C)]
pub enum Compress {
None,
Enabled,
All,
}
impl From<ast::Compress> for Compress {
fn from(c: ast::Compress) -> Self {
match c {
ast::Compress::None => Compress::None,
ast::Compress::Enabled => Compress::Enabled,
ast::Compress::All => Compress::All,
}
}
}
#[repr(C)]
pub enum SendSemantics {
Async,
Sync,
Intr,
}
impl From<ast::SendSemantics> for SendSemantics {
fn from(ss: ast::SendSemantics) -> Self {
match ss {
ast::SendSemantics::Async => SendSemantics::Async,
ast::SendSemantics::Sync => SendSemantics::Sync,
ast::SendSemantics::Intr => SendSemantics::Intr,
}
}
}
#[repr(C)]
pub enum Nesting {
None,
InsideSync,
InsideCpow,
}
impl From<ast::Nesting> for Nesting {
fn from(n: ast::Nesting) -> Self {
match n {
ast::Nesting::InsideCpow => Nesting::InsideCpow,
ast::Nesting::InsideSync => Nesting::InsideSync,
ast::Nesting::None => Nesting::None,
}
}
}
#[repr(C)]
pub enum Priority {
Normal,
High,
Input,
}
impl From<ast::Priority> for Priority {
fn from(p: ast::Priority) -> Self {
match p {
ast::Priority::High => Priority::High,
ast::Priority::Input => Priority::Input,
ast::Priority::Normal => Priority::Normal,
}
}
}
#[repr(C)]
pub enum Direction {
ToParent,
ToChild,
ToParentOrChild,
}
impl From<ast::Direction> for Direction {
fn from(d: ast::Direction) -> Self {
match d {
ast::Direction::ToChild => Direction::ToChild,
ast::Direction::ToParent => Direction::ToParent,
ast::Direction::ToParentOrChild => Direction::ToParentOrChild,
}
}
}
#[repr(C)]
pub struct Location {
pub file_name: nsCString,
pub lineno: usize,
pub colno: usize,
}
impl From<ast::Location> for Location {
fn from(l: ast::Location) -> Self {
Location {
file_name: l.file_name.into(),
lineno: l.lineno,
colno: l.colno,
}
}
}
#[repr(C)]
pub struct Identifier {
pub id: nsCString,
pub loc: Location,
}
impl From<ast::Identifier> for Identifier {
fn from(id: ast::Identifier) -> Self {
Identifier {
id: id.id.into(),
loc: id.loc.into(),
}
}
}
#[repr(C)]
pub struct MessageDecl {
pub name: Identifier,
pub send_semantics: SendSemantics,
pub nested: Nesting,
pub prio: Priority,
pub direction: Direction,
pub in_params: ThinVec<Param>,
pub out_params: ThinVec<Param>,
pub compress: Compress,
pub verify: bool,
}
impl From<ast::MessageDecl> for MessageDecl {
fn from(md: ast::MessageDecl) -> Self {
MessageDecl {
name: md.name.into(),
send_semantics: md.send_semantics.into(),
nested: md.nested.into(),
prio: md.prio.into(),
direction: md.direction.into(),
in_params: vec_to_thinvec(md.in_params),
out_params: vec_to_thinvec(md.out_params),
compress: md.compress.into(),
verify: md.verify,
}
}
}
#[repr(C)]
pub struct Protocol {
pub send_semantics: SendSemantics,
pub nested: Nesting,
pub managers: ThinVec<Identifier>,
pub manages: ThinVec<Identifier>,
pub messages: ThinVec<MessageDecl>,
}
impl From<ast::Protocol> for Protocol {
fn from(p: ast::Protocol) -> Self {
Protocol {
send_semantics: p.send_semantics.into(),
nested: p.nested.into(),
managers: vec_to_thinvec(p.managers),
manages: vec_to_thinvec(p.manages),
messages: vec_to_thinvec(p.messages),
}
}
}
#[repr(C)]
pub enum CxxTypeKind {
Struct,
Class,
}
impl From<ast::CxxTypeKind> for CxxTypeKind {
fn from(cxxtk: ast::CxxTypeKind) -> Self {
match cxxtk {
ast::CxxTypeKind::Class => CxxTypeKind::Class,
ast::CxxTypeKind::Struct => CxxTypeKind::Struct,
}
}
}
#[repr(C)]
pub struct UsingStmt {
pub cxx_type: TypeSpec,
pub header: nsCString,
pub kind: Maybe<CxxTypeKind>,
pub refcounted: bool,
}
impl From<ast::UsingStmt> for UsingStmt {
fn from(using: ast::UsingStmt) -> Self {
UsingStmt {
cxx_type: using.cxx_type.into(),
header: using.header.into(),
kind: using.kind.into(),
refcounted: using.refcounted,
}
}
}
#[repr(C)]
pub enum FileType {
Protocol,
Header,
}
impl From<ast::FileType> for FileType {
fn from(ft: ast::FileType) -> Self {
match ft {
ast::FileType::Protocol => FileType::Protocol,
ast::FileType::Header => FileType::Header,
}
}
}
// Translation unit identifier.
pub type TUId = i32;
#[repr(C)]
pub struct Struct {
pub ns: Namespace,
pub fields: ThinVec<StructField>,
}
impl From<(ast::Namespace, Vec<ast::StructField>)> for Struct {
fn from(s: (ast::Namespace, Vec<ast::StructField>)) -> Self {
Struct {
ns: s.0.into(),
fields: vec_to_thinvec(s.1),
}
}
}
#[repr(C)]
pub struct Union {
pub ns: Namespace,
pub types: ThinVec<TypeSpec>,
}
impl From<(ast::Namespace, Vec<ast::TypeSpec>)> for Union {
fn from(u: (ast::Namespace, Vec<ast::TypeSpec>)) -> Self {
Union {
ns: u.0.into(),
types: vec_to_thinvec(u.1),
}
}
}
#[repr(C)]
pub struct NamedProtocol {
pub ns: Namespace,
pub protocol: Protocol,
}
impl From<(ast::Namespace, ast::Protocol)> for NamedProtocol {
fn from(p: (ast::Namespace, ast::Protocol)) -> Self {
NamedProtocol {
ns: p.0.into(),
protocol: p.1.into(),
}
}
}
#[repr(C)]
pub struct TranslationUnit {
pub ns: Namespace,
pub file_type: FileType,
pub file_name: nsCString,
pub cxx_includes: ThinVec<nsCString>,
pub includes: ThinVec<TUId>,
pub using_stmt: ThinVec<UsingStmt>,
pub structs: ThinVec<Struct>,
pub unions: ThinVec<Union>,
pub protocol: Maybe<NamedProtocol>,
}
impl From<ast::TranslationUnit> for TranslationUnit {
fn from(tu: ast::TranslationUnit) -> Self {
TranslationUnit {
ns: tu.namespace.into(),
file_type: tu.file_type.into(),
file_name: tu.file_name.into(),
cxx_includes: vec_to_thinvec(tu.cxx_includes),
includes: vec_to_thinvec(tu.includes),
using_stmt: vec_to_thinvec(tu.using),
structs: vec_to_thinvec(tu.structs),
unions: vec_to_thinvec(tu.unions),
protocol: tu.protocol.into(),
}
}
}
pub struct AST {
pub main_tuid: TUId,
pub translation_units: HashMap<TUId, TranslationUnit>,
}
impl From<ast::AST> for AST {
fn from(ast: ast::AST) -> Self {
AST {
main_tuid: ast.main_tuid,
translation_units: ast
.translation_units
.into_iter()
.map(|(k, v)| (k, v.into()))
.collect(),
}
}
}
#[no_mangle]
pub extern "C" fn ipdl_ast_get_tu(ast: &AST, tuid: TUId) -> *const TranslationUnit {
ast.translation_units
.get(&tuid)
.map(|x| x as *const TranslationUnit)
.unwrap_or(::std::ptr::null())
}
#[no_mangle]
pub extern "C" fn ipdl_ast_main_tuid(ast: &AST) -> TUId {
ast.main_tuid
}
struct FFIURI {
data: nsCString,
resolve_relative_path_fn: fn(&nsACString, &nsACString, &mut nsACString) -> u8,
equals_fn: fn(&nsACString, &nsACString) -> u8,
}
impl parser::FileURI for FFIURI {
fn resolve_relative_path(&self, relative_path: &str) -> Result<Self, ()> {
let mut result = nsCString::new();
let ok = (self.resolve_relative_path_fn)(&self.data, &nsCStr::from(relative_path), &mut result);
if ok != 0 {
Ok(FFIURI {
data: result,
resolve_relative_path_fn: self.resolve_relative_path_fn,
equals_fn: self.equals_fn,
})
} else {
Err(())
}
}
fn to_utf8(&self) -> &str {
str::from_utf8(&self.data).unwrap()
}
}
impl PartialEq for FFIURI {
fn eq(&self, other: &FFIURI) -> bool {
(self.equals_fn)(&self.data, &other.data) != 0
}
}
impl Eq for FFIURI {}
impl Hash for FFIURI {
fn hash<H: Hasher>(&self, state: &mut H) {
self.data.hash(state);
}
}
impl Clone for FFIURI {
fn clone(&self) -> FFIURI {
let new_data = nsCString::from(self.data.as_ref());
FFIURI {
data: new_data,
resolve_relative_path_fn: self.resolve_relative_path_fn,
equals_fn: self.equals_fn,
}
}
}
#[no_mangle]
pub unsafe extern "C" fn ipdl_parse_file(
ipdl_file: &nsACString,
error_string: &mut nsACString,
source_string_loader: fn(&nsACString, &mut nsACString) -> u8,
resolve_relative_path: fn(&nsACString, &nsACString, &mut nsACString) -> u8,
equals: fn(&nsACString, &nsACString) -> u8,
) -> *const AST {
let uri = FFIURI {
data: nsCString::from(ipdl_file),
resolve_relative_path_fn: resolve_relative_path,
equals_fn: equals,
};
let parent_uri = match uri.resolve_relative_path("./") {
Ok(pu) => pu,
Err(()) => {
error_string.assign("Could not get IPDL file parent directory");
return ::std::ptr::null()
},
};
Box::into_raw(Box::new(match parser::parse(
&uri,
&[parent_uri],
|uri: &str| -> Result<Box<parser::OwnedSourceBuffer>, ()> {
let ns_uri = nsCStr::from(uri);
let mut result = nsCString::new();
let ok = source_string_loader(&ns_uri, &mut result);
if ok != 0 {
Ok(Box::new(result))
} else {
Err(())
}
},
) {
Ok(ast) => ast.into(),
Err(error) => {
error_string.assign(&format!("{}", error));
return ::std::ptr::null()
},
}))
}
#[no_mangle]
pub unsafe extern "C" fn ipdl_free_ast(ast: *const AST) {
drop(Box::from_raw(ast as *mut AST))
}

Просмотреть файл

@ -1,155 +0,0 @@
/* -*- 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 https://mozilla.org/MPL/2.0/. */
#include "wrapper.h"
#include "nsAString.h"
#include "nsString.h"
#include "nsNetUtil.h"
namespace mozilla {
namespace ipdl {
namespace wrapper {
static uint8_t
source_string_loader(const nsACString* aFileName, nsACString* aRet)
{
nsCOMPtr<nsIChannel> chan;
nsCOMPtr<nsIInputStream> instream;
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIIOService> serv = do_GetService(NS_IOSERVICE_CONTRACTID);
nsresult rv;
rv = NS_NewURI(getter_AddRefs(uri), *aFileName);
if (NS_FAILED(rv)) {
NS_WARNING("FAILED TO GET URI");
return 0;
}
rv = NS_NewChannel(getter_AddRefs(chan),
uri,
nsContentUtils::GetSystemPrincipal(),
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
nsIContentPolicy::TYPE_OTHER,
nullptr, // PerformanceStorage
nullptr, // aLoadGroup
nullptr, // aCallbacks
nsIRequest::LOAD_NORMAL,
serv);
if (NS_SUCCEEDED(rv)) {
chan->SetContentType(NS_LITERAL_CSTRING("application/x-ipdl"));
rv = chan->Open2(getter_AddRefs(instream));
}
if (NS_FAILED(rv)) {
NS_WARNING("LOAD_ERROR_NOSTREAM");
return 0;
}
int64_t len = -1;
rv = chan->GetContentLength(&len);
if (NS_FAILED(rv) || len == -1) {
NS_WARNING("LOAD_ERROR_NOCONTENT");
return 0;
}
if (len > INT32_MAX) {
NS_WARNING("LOAD_ERROR_CONTENTTOOBIG");
return 0;
}
rv = NS_ReadInputStreamToString(instream, *aRet, len);
if (NS_FAILED(rv)) {
NS_WARNING("FAILED TO READ");
return 0;
}
return 1;
}
static uint8_t
resolve_relative_path(const nsACString* aFileName, const nsACString* aRelativePath, nsACString* aRet)
{
nsCOMPtr<nsIURI> uri;
nsresult rv;
rv = NS_NewURI(getter_AddRefs(uri), *aFileName);
if (NS_FAILED(rv)) {
NS_WARNING("FAILED TO GET URI");
return 0;
}
rv = uri->Resolve(*aRelativePath, *aRet);
if (NS_FAILED(rv)) {
NS_WARNING("FAILED TO RESOLVE URI");
return 0;
}
return 1;
}
static uint8_t
uri_equals(const nsACString* aFileName1, const nsACString* aFileName2)
{
nsCOMPtr<nsIURI> uri1;
nsCOMPtr<nsIURI> uri2;
nsresult rv;
rv = NS_NewURI(getter_AddRefs(uri1), *aFileName1);
if (NS_FAILED(rv)) {
NS_WARNING("FAILED TO GET URI 1");
}
rv = NS_NewURI(getter_AddRefs(uri2), *aFileName2);
if (NS_FAILED(rv)) {
NS_WARNING("FAILED TO GET URI 2");
}
bool retval;
rv = uri1->Equals(uri2, &retval);
if (NS_FAILED(rv)) {
NS_WARNING("FAILED TO COMPARE URIs");
}
return retval ? 1 : 0;
}
const ffi::AST*
Parse(const nsACString& aIPDLFile, nsACString& errorString)
{
return ffi::ipdl_parse_file(&aIPDLFile, &errorString, source_string_loader, resolve_relative_path, uri_equals);
}
void
FreeAST(const ffi::AST* aAST)
{
ffi::ipdl_free_ast(aAST);
}
const ffi::TranslationUnit*
GetTU(const ffi::AST* aAST, ffi::TUId aTUID)
{
return ffi::ipdl_ast_get_tu(aAST, aTUID);
}
ffi::TUId
GetMainTUId(const ffi::AST* aAST)
{
return ffi::ipdl_ast_main_tuid(aAST);
}
} // wrapper
} // ipdl
} // mozilla

Просмотреть файл

@ -1,37 +0,0 @@
/* -*- 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 https://mozilla.org/MPL/2.0/. */
#ifndef dom_base_ipdl_bindings_wrapper_h
#define dom_base_ipdl_bindings_wrapper_h
#include "ipdl_ffi_generated.h"
#include "nsStringFwd.h"
namespace mozilla {
namespace ipdl {
namespace wrapper {
// Parse the given ipdl file and return a Rust-owned AST.
const ffi::AST*
Parse(const nsACString& aIPDLFile, nsACString& errorString);
// Free the AST from Rust code.
void
FreeAST(const ffi::AST* aAST);
// Get the translation unit with the given tuid from the given AST.
const ffi::TranslationUnit*
GetTU(const ffi::AST* aAST, ffi::TUId aTUID);
// Get the tuid of the main translation unit of the AST.
ffi::TUId
GetMainTUId(const ffi::AST* aAST);
} // wrapper
} // ipdl
} // mozilla
#endif // dom_base_ipdl_bindings_wrapper_h

Просмотреть файл

@ -1,9 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
DIRS += [
'ipdl_bindings',
]

2
ipc/ipdl_new/pipdl/.gitignore поставляемый
Просмотреть файл

@ -1,2 +0,0 @@
/target/
**/*.rs.bk

Просмотреть файл

@ -1,7 +0,0 @@
[package]
name = "pipdl"
version = "0.1.0"
authors = ["Nika Layzell <nika@thelayzells.com>"]
license = "MPL-2.0"
[dependencies]

Просмотреть файл

@ -1,5 +0,0 @@
#!/bin/bash
# Run the parser on every error ipdl file in the passed-in directory.
find $1 -name "*.ipdl" -print0 | sort -z | xargs -0 -n 1 cargo run --release --example try_parse --
echo status $? >&2

Просмотреть файл

@ -1,30 +0,0 @@
/* 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/. */
extern crate pipdl;
use std::env::args;
use std::fs::File;
use std::io::Read;
fn run() -> Result<(), Box<std::error::Error>> {
let filename = args().nth(1).ok_or("Filename expected")?;
let mut f = File::open(&filename)?;
let mut s = String::new();
f.read_to_string(&mut s)?;
if let Err(e) = pipdl::parse(&s, &filename) {
return Err(Box::new(e));
}
Ok(())
}
fn main() {
::std::process::exit(match run() {
Ok(_) => 0,
Err(e) => {
eprintln!("{}", e);
1
}
})
}

Просмотреть файл

@ -1,720 +0,0 @@
/* 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/. */
//! This is a basic recursive-descent parser for ipdl. It intentionally doesn't
//! have some featres which most languages would have, such as unicode support
//! in identifiers, as it is unnecessary for our usecase.
// Our code is Clippy aware, so we disable warnings for unknown lints
// which are triggered when we silence a clippy lint
#![allow(unknown_lints)]
use std::error;
use std::fmt;
#[macro_use]
pub mod util;
pub use util::*;
/// Public error type for messages with resolved type information.
pub struct Error(Box<ParserError>);
impl Error {
pub fn span(&self) -> Span {
self.0.span()
}
}
impl error::Error for Error {
fn description(&self) -> &str {
&self.0.message()
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&format!(
"{}:{}:{}: error: {}",
self.0.span().start.file,
self.0.span().start.line,
self.0.span().start.col,
self.0.message()
))
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
#[derive(Debug, Clone)]
pub struct CxxInclude {
pub file: Spanned<String>,
}
fn cxx_include(i: In) -> PResult<Spanned<CxxInclude>> {
let start = i.loc();
let (i, _) = kw(i, "include")?;
let (i, file) = string(i)?;
commit! {
let (i, _) = punct(i, ";")?;
let end = i.loc();
Ok((i.clone(), Spanned::new(Span { start, end }, CxxInclude { file })))
}
}
#[derive(Debug, Clone)]
pub struct Include {
pub protocol: Option<Spanned<()>>,
pub id: Spanned<String>,
}
fn include(i: In) -> PResult<Spanned<Include>> {
let start = i.loc();
let (i, _) = kw(i, "include")?;
let (i, pcol) = maybe(i.clone(), kw(i, "protocol"))?;
let pcol_is_some = pcol.is_some();
let common_end_code = |i, id| {
let (i, _) = punct(i, ";")?;
let end = i.loc();
Ok((
i,
Spanned::new(Span { start, end }, Include { protocol: pcol, id }),
))
};
if pcol_is_some {
// If we have the protocol keyword, then it can't be a C++ include anymore, and we start committing
commit! {
let (i, id) = ident(i)?;
common_end_code(i, id)
}
} else {
// Otherwise we first parse the ident
let (i, id) = ident(i)?;
commit! {
common_end_code(i, id)
}
}
}
#[derive(Debug, Clone)]
pub enum CxxTypeKind {
Class,
Struct,
None,
}
#[derive(Debug, Clone)]
pub struct CxxPathSeg {
pub id: Spanned<String>,
pub args: Option<Spanned<Vec<Spanned<String>>>>,
}
fn template_args(i: In) -> PResult<Spanned<Vec<Spanned<String>>>> {
let start = i.loc();
let (i, _) = punct(i, "<")?;
commit! {
let (i, args) = sep(i, ident, ",")?;
let (i, _) = punct(i, ">")?;
let end = i.loc();
Ok((i, Spanned::new(Span { start, end }, args)))
}
}
fn cxx_path_seg(i: In) -> PResult<Spanned<CxxPathSeg>> {
let start = i.loc();
let (i, id) = ident(i)?;
let (i, args) = maybe(i.clone(), template_args(i))?;
let end = i.loc();
Ok((
i,
Spanned::new(Span { start, end }, CxxPathSeg { id, args }),
))
}
#[derive(Debug, Clone)]
pub struct CxxPath {
pub segs: Vec<Spanned<CxxPathSeg>>,
}
fn cxx_path(i: In) -> PResult<Spanned<CxxPath>> {
let start = i.loc();
let (i, segs) = sep(i, cxx_path_seg, "::")?;
let end = i.loc();
Ok((i, Spanned::new(Span { start, end }, CxxPath { segs })))
}
#[derive(Debug, Clone)]
pub struct Using {
pub refcounted: Option<Spanned<()>>,
pub kind: Spanned<CxxTypeKind>,
pub ty: Spanned<CxxPath>,
pub file: Spanned<String>,
}
fn using(i: In) -> PResult<Spanned<Using>> {
let start = i.loc();
let (i, _) = kw(i, "using")?;
commit! {
let (i, refcounted) = maybe(i.clone(), kw(i, "refcounted"))?;
let kw_start = i.loc();
let (i, kind) = any!(
i, "struct or class keyword",
kw(i.clone(), "struct") => CxxTypeKind::Struct,
kw(i.clone(), "class") => CxxTypeKind::Class,
Ok((i.clone(), ())) => CxxTypeKind::None,
)?;
let kw_end = i.loc();
let (i, ty) = cxx_path(i)?;
let (i, _) = kw(i, "from")?;
let (i, file) = string(i)?;
let (i, _) = punct(i, ";")?;
let end = i.loc();
Ok((i, Spanned::new(Span { start, end }, Using { refcounted, kind: Spanned::new(Span { start: kw_start, end: kw_end }, kind), ty, file })))
}
}
#[derive(Debug, Clone)]
pub struct Type {
pub is_nullable: Option<Spanned<()>>,
pub name: Spanned<CxxPathSeg>,
pub is_array: Option<Spanned<()>>,
}
fn ty(i: In) -> PResult<Spanned<Type>> {
fn array_brackets(i: In) -> PResult<Spanned<()>> {
let (i, _) = punct(i, "[")?;
commit! { punct(i, "]") }
}
let start = i.loc();
let (i, nullable) = maybe(i.clone(), kw(i, "nullable"))?;
let (i, name) = cxx_path_seg(i)?;
let (i, array) = maybe(i.clone(), array_brackets(i))?;
let end = i.loc();
Ok((
i,
Spanned::new(
Span { start, end },
Type {
is_nullable: nullable,
name,
is_array: array,
},
),
))
}
fn component(i: In) -> PResult<Spanned<Type>> {
let (i, ty) = ty(i)?;
commit! {
let (i, _) = punct(i, ";")?;
Ok((i, ty))
}
}
#[derive(Debug, Clone)]
pub struct UnionItem {
pub path: Vec<Spanned<String>>,
pub components: Vec<Spanned<Type>>,
}
fn union_item(i: In) -> PResult<Spanned<UnionItem>> {
let start = i.loc();
let (i, _) = kw(i, "union")?;
commit! {
let (i, name) = ident(i)?;
let (i, _) = punct(i, "{")?;
let (i, components) = many(i, component)?;
let (i, _) = punct(i, "}")?;
let (i, _) = punct(i, ";")?;
let end = i.loc();
Ok((i, Spanned::new(Span { start, end }, UnionItem {
path: vec![name],
components,
})))
}
}
#[derive(Debug, Clone)]
pub struct Field {
pub ty: Spanned<Type>,
pub name: Spanned<String>,
}
fn field(i: In) -> PResult<Spanned<Field>> {
let start = i.loc();
let (i, ty) = ty(i)?;
commit! {
let (i, name) = ident(i)?;
let (i, _) = punct(i, ";")?;
let end = i.loc();
Ok((i, Spanned::new(Span {start, end}, Field { ty, name })))
}
}
#[derive(Debug, Clone)]
pub struct StructItem {
pub path: Vec<Spanned<String>>,
pub fields: Vec<Spanned<Field>>,
}
fn struct_item(i: In) -> PResult<Spanned<StructItem>> {
let start = i.loc();
let (i, _) = kw(i, "struct")?;
commit! {
let (i, name) = ident(i)?;
let (i, _) = punct(i, "{")?;
let (i, fields) = many(i, field)?;
let (i, _) = punct(i, "}")?;
let (i, _) = punct(i, ";")?;
let end = i.loc();
Ok((i, Spanned::new(Span { start, end }, StructItem {
path: vec![name],
fields,
})))
}
}
#[derive(Debug, Clone)]
pub enum Nesting {
None,
InsideSync,
InsideCpow,
}
#[allow(needless_pass_by_value)]
fn nesting(i: In) -> PResult<Spanned<Nesting>> {
let start = i.loc();
let (i, nesting) = any!(
i, "nesting specifier (not, inside_sync, or inside_cpow)",
kw(i.clone(), "not") => Nesting::None,
kw(i.clone(), "inside_sync") => Nesting::InsideSync,
kw(i.clone(), "inside_cpow") => Nesting::InsideCpow,
)?;
let end = i.loc();
Ok((i, Spanned::new(Span { start, end }, nesting)))
}
#[derive(Debug, Clone)]
pub enum Priority {
Normal,
High,
Input,
}
#[allow(needless_pass_by_value)]
fn priority(i: In) -> PResult<Spanned<Priority>> {
let start = i.loc();
let (i, priority) = any!(
i, "priority specifier (normal, high, or input)",
kw(i.clone(), "normal") => Priority::Normal,
kw(i.clone(), "high") => Priority::High,
kw(i.clone(), "input") => Priority::Input,
)?;
let end = i.loc();
Ok((i, Spanned::new(Span { start, end }, priority)))
}
#[derive(Debug, Clone)]
pub enum SendSemantics {
Async,
Sync,
Intr,
}
#[derive(Debug, Clone)]
pub enum MessageModifier {
Verify,
Compress,
CompressAll,
}
#[allow(needless_pass_by_value)]
fn message_modifier(i: In) -> PResult<Spanned<MessageModifier>> {
let start = i.loc();
let (i, message_modifier) = any!(
i, "message modifier (verify, compress, or compressall)",
kw(i.clone(), "verify") => MessageModifier::Verify,
kw(i.clone(), "compress") => MessageModifier::Compress,
kw(i.clone(), "compressall") => MessageModifier::CompressAll,
)?;
let end = i.loc();
Ok((i, Spanned::new(Span { start, end }, message_modifier)))
}
#[derive(Debug, Clone)]
pub struct Param {
pub ty: Spanned<Type>,
pub name: Spanned<String>,
}
fn param(i: In) -> PResult<Spanned<Param>> {
let start = i.loc();
let (i, ty) = ty(i)?;
commit! {
let (i, name) = ident(i)?;
let end = i.loc();
Ok((i, Spanned::new(Span { start, end }, Param { ty, name })))
}
}
#[derive(Debug, Clone)]
pub struct MessageDecl {
pub nested: Option<Spanned<Spanned<Nesting>>>,
pub priority: Option<Spanned<Spanned<Priority>>>,
pub send_semantics: Spanned<SendSemantics>,
pub name: Spanned<String>,
pub params: Vec<Spanned<Param>>,
pub returns: Option<Spanned<Vec<Spanned<Param>>>>,
pub modifiers: Vec<Spanned<MessageModifier>>,
}
fn returns(i: In) -> PResult<Spanned<Vec<Spanned<Param>>>> {
let start = i.loc();
let (i, _) = kw(i, "returns")?;
commit! {
let (i, _) = punct(i, "(")?;
let (i, p) = sep(i, param, ",")?;
let (i, _) = punct(i, ")")?;
let end = i.loc();
Ok((i, Spanned::new(Span { start, end }, p)))
}
}
fn message_nested(i: In) -> PResult<Spanned<Spanned<Nesting>>> {
let start = i.loc();
let (i, _) = kw(i, "nested")?;
commit! {
let (i, _) = punct(i, "(")?;
let (i, nested) = nesting(i)?;
let (i, _) = punct(i, ")")?;
let end = i.loc();
Ok((i, Spanned::new(Span { start, end }, nested)))
}
}
fn message_prio(i: In) -> PResult<Spanned<Spanned<Priority>>> {
let start = i.loc();
let (i, _) = kw(i, "prio")?;
commit! {
let (i, _) = punct(i, "(")?;
let (i, prio) = priority(i)?;
let (i, _) = punct(i, ")")?;
let end = i.loc();
Ok((i, Spanned::new(Span { start, end }, prio)))
}
}
fn message_decl(i: In) -> PResult<Spanned<MessageDecl>> {
let start = i.loc();
// XXX(nika): This is really gross, maybe clean it up?
let mut nested = None;
let mut priority = None;
drive!(
i,
any!(
i, "message prefix",
message_prio(i.clone()) => |p| priority = Some(p),
message_nested(i.clone()) => |n| nested = Some(n),
)
);
let send_semantics_start = i.loc();
let (i, send_semantics) = any!(
i, "send semantics (async, sync, or intr)",
kw(i.clone(), "async") => SendSemantics::Async,
kw(i.clone(), "sync") => SendSemantics::Sync,
kw(i.clone(), "intr") => SendSemantics::Intr,
)?;
let send_semantics_end = i.loc();
commit! {
let (i, name) = ident(i)?;
let (i, _) = punct(i, "(")?;
let (i, params) = sep(i, param, ",")?;
let (i, _) = punct(i, ")")?;
let (i, returns) = maybe(i.clone(), returns(i))?;
let (i, modifiers) = many(i, message_modifier)?;
let (i, _) = punct(i, ";")?;
let end = i.loc();
Ok((i, Spanned::new(Span { start, end }, MessageDecl {
nested,
priority,
send_semantics: Spanned::new(Span { start: send_semantics_start, end: send_semantics_end }, send_semantics),
name,
params,
returns,
modifiers,
})))
}
}
#[derive(Debug, Clone)]
pub enum Direction {
ToChild,
ToParent,
Both,
}
#[allow(needless_pass_by_value)]
fn direction(i: In) -> PResult<Spanned<Direction>> {
let start = i.loc();
let (i, direction) = any!(
i, "direction (child, parent, or both)",
kw(i.clone(), "child") => Direction::ToChild,
kw(i.clone(), "parent") => Direction::ToParent,
kw(i.clone(), "both") => Direction::Both,
)?;
let end = i.loc();
Ok((i, Spanned::new(Span { start, end }, direction)))
}
#[derive(Debug, Clone)]
pub struct MessageGroup {
pub direction: Spanned<Direction>,
pub decls: Vec<Spanned<MessageDecl>>,
}
fn message_group(i: In) -> PResult<Spanned<MessageGroup>> {
let start = i.loc();
let (i, direction) = direction(i)?;
commit! {
let (i, _) = punct(i, ":")?;
let (i, decls) = many(i, message_decl)?;
let end = i.loc();
Ok((i, Spanned::new(Span { start, end }, MessageGroup {
direction,
decls,
})))
}
}
#[derive(Debug, Clone)]
pub struct ProtocolItem {
pub path: Vec<Spanned<String>>,
pub nested: Option<Spanned<Spanned<Nesting>>>,
pub send_semantics: Spanned<SendSemantics>,
pub managers: Option<Spanned<Vec<Spanned<String>>>>,
pub manages: Vec<Spanned<Spanned<String>>>,
pub groups: Vec<Spanned<MessageGroup>>,
}
fn protocol_nested(i: In) -> PResult<(Spanned<Spanned<Nesting>>, Spanned<SendSemantics>)> {
let nested_start = i.loc();
let (i, _) = kw(i, "nested")?;
commit! {
let (i, _) = punct(i, "(")?;
let (i, _) = kw(i, "upto")?;
let (i, n) = nesting(i)?;
let (i, _) = punct(i, ")")?;
let nested_end = i.loc();
let ss_start = i.loc();
let (i, ss) = any!(
i, "send semantics (async or sync)",
kw(i.clone(), "async") => SendSemantics::Async,
kw(i.clone(), "sync") => SendSemantics::Sync,
)?;
let ss_end = i.loc();
Ok((i, (Spanned::new(Span { start: nested_start, end: nested_end }, n), Spanned::new(Span { start: ss_start, end: ss_end}, ss))))
}
}
fn managers(i: In) -> PResult<Spanned<Vec<Spanned<String>>>> {
let start = i.loc();
let (i, _) = kw(i, "manager")?;
commit! {
let (i, managers) = sep(i, ident, "or")?;
let (i, _) = punct(i, ";")?;
let end = i.loc();
Ok((i, Spanned::new(Span {start, end}, managers)))
}
}
fn manages(i: In) -> PResult<Spanned<Spanned<String>>> {
let start = i.loc();
let (i, _) = kw(i, "manages")?;
commit! {
let (i, name) = ident(i)?;
let (i, _) = punct(i, ";")?;
let end = i.loc();
Ok((i, Spanned::new(Span { start, end }, name)))
}
}
#[allow(needless_pass_by_value)]
fn protocol_item(i: In) -> PResult<Spanned<ProtocolItem>> {
let start = i.loc();
let mut ss_span = Span::new(i.loc().file);
let ss_start = i.loc();
let (i, (nested, send_semantics)) = any!(
i, "protocol item prefixes",
kw(i.clone(), "async") => |_x| (None, SendSemantics::Async),
kw(i.clone(), "sync") => |_x| (None, SendSemantics::Sync),
kw(i.clone(), "intr") => |_x| (None, SendSemantics::Intr),
protocol_nested(i.clone()) => |x| {ss_span = x.1.span; (Some(x.0), x.1.data)},
Ok((i.clone(), ())) => |_x| (None, SendSemantics::Async),
)?;
let ss_end = i.loc();
if ss_span.is_null() {
ss_span = Span {
start: ss_start,
end: ss_end,
};
}
let (i, _) = kw(i, "protocol")?;
commit! {
let (i, name) = ident(i)?;
let (i, _) = punct(i, "{")?;
let (i, managers) = maybe(i.clone(), managers(i))?;
let (i, manages) = many(i, manages)?;
let (i, groups) = many(i, message_group)?;
let (i, _) = punct(i, "}")?;
let (i, _) = punct(i, ";")?;
let end = i.loc();
Ok((i, Spanned::new(Span { start, end }, ProtocolItem {
send_semantics: Spanned::new(ss_span, send_semantics),
nested,
path: vec![name],
managers,
manages,
groups,
})))
}
}
#[derive(Debug, Clone)]
#[allow(large_enum_variant)]
pub enum Item {
Struct(Spanned<StructItem>),
Union(Spanned<UnionItem>),
Protocol(Spanned<ProtocolItem>),
}
fn namespace(i: In) -> PResult<Vec<Item>> {
let (i, _) = kw(i, "namespace")?;
commit! {
let (i, name) = ident(i)?;
let (i, _) = punct(i, "{")?;
let (i, mut items) = items(i)?;
let (i, _) = punct(i, "}")?;
for it in &mut items {
match *it {
Item::Struct(ref mut i) =>
i.data.path.insert(0, name.clone()),
Item::Union(ref mut i) =>
i.data.path.insert(0, name.clone()),
Item::Protocol(ref mut i) =>
i.data.path.insert(0, name.clone()),
}
}
Ok((i, items))
}
}
fn items(i: In) -> PResult<Vec<Item>> {
let mut v = Vec::new();
drive!(
i,
any!(
i, "item (struct, union, protocol, or namespace)",
struct_item(i.clone()) => |x| v.push(Item::Struct(x)),
union_item(i.clone()) => |x| v.push(Item::Union(x)),
protocol_item(i.clone()) => |x| v.push(Item::Protocol(x)),
namespace(i.clone()) => |x| v.extend(x),
)
);
Ok((i, v))
}
#[derive(Debug, Clone)]
pub struct TranslationUnit {
pub cxx_includes: Vec<Spanned<CxxInclude>>,
pub includes: Vec<Spanned<Include>>,
pub usings: Vec<Spanned<Using>>,
pub items: Vec<Item>,
}
fn translation_unit(i: In) -> PResult<Spanned<TranslationUnit>> {
// Prelude.
let mut usings = Vec::new();
let mut includes = Vec::new();
let mut cxx_includes = Vec::new();
let start = i.loc();
drive!(
i,
any!(
i, "include or using declaration",
using(i.clone()) => |u| usings.push(u),
include(i.clone()) => |u| includes.push(u),
cxx_include(i.clone()) => |u| cxx_includes.push(u),
)
);
// Body.
let (i, items) = items(i)?;
// Make sure we're at EOF
let i = skip_ws(i)?;
if !i.rest().is_empty() {
return i.expected("item (struct, union, protocol, or namespace)");
}
let end = i.loc();
Ok((
i,
Spanned::new(
Span { start, end },
TranslationUnit {
cxx_includes,
includes,
usings,
items,
},
),
))
}
/// Entry point - parses a whole translation unit.
pub fn parse<'filepath>(
src: &str,
file: &'filepath str,
) -> Result<Spanned<TranslationUnit>, Error> {
match translation_unit(In::new(src, file.to_owned())) {
Ok((_, v)) => Ok(v),
Err(err) => Err(Error(Box::new(err))),
}
}

Просмотреть файл

@ -1,450 +0,0 @@
/* 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/. */
//! Fairly minimal recursive-descent parser helper functions and types.
use std::fmt;
#[derive(Clone, Debug)]
pub struct Location {
pub line: usize,
pub col: usize,
pub file: String,
}
impl Location {
fn new(file: String) -> Self {
Location {
line: 0,
col: 0,
file,
}
}
pub fn is_null(&self) -> bool {
self.line == 0
}
}
#[derive(Clone, Debug)]
pub struct Span {
pub start: Location,
pub end: Location,
}
impl Span {
pub fn new(file: String) -> Self {
Span {
start: Location::new(file.clone()),
end: Location::new(file),
}
}
pub fn is_null(&self) -> bool {
self.start.is_null() && self.end.is_null()
}
}
#[derive(Clone, Debug)]
pub struct Spanned<T> {
pub data: T,
pub span: Span,
}
impl<T> Spanned<T> {
pub fn new(span: Span, data: T) -> Self {
Spanned { data, span }
}
}
/// Every bit set but the high bit in usize.
const OFF_MASK: usize = <usize>::max_value() / 2;
/// Only the high bit in usize.
const FATAL_MASK: usize = !OFF_MASK;
/// An error produced by pipdl
pub struct ParserError {
message: String,
fatal: bool,
span: Span,
}
impl ParserError {
pub(crate) fn is_fatal(&self) -> bool {
self.fatal
}
pub(crate) fn make_fatal(mut self) -> Self {
self.fatal = true;
self
}
pub(crate) fn span(&self) -> Span {
self.span.clone()
}
pub(crate) fn message(&self) -> &str {
&self.message
}
}
impl fmt::Debug for ParserError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Error")
.field("file", &self.span.start.file)
.field("start_line", &self.span.start.line)
.field("start_column", &self.span.start.col)
.field("end_line", &self.span.end.line)
.field("end_column", &self.span.end.col)
.finish()
}
}
/// Attempts to run each expression in order, recovering from any non-fatal
/// errors and attempting the next option.
macro_rules! any {
($i:ident, $expected:expr, $($e:expr => |$x:ident| $f:expr),+ $(,)*) => {
// NOTE: We have to do this sorcery for early returns. Using a loop with breaks makes clippy
// mad because the loop never loops and we can't desable the lint because we're not in a function.
// Also, we don't directly call the closure otherwise clippy would also complain about that. Yeah.
{
let mut my_closure = || {
$(match $e {
Ok((i, $x)) => return Ok((i, $f)),
Err(e) => {
// This assignment is used to help out with type inference.
let e: $crate::util::ParserError = e;
if e.is_fatal() {
return Err(e);
}
}
})+
return $i.expected($expected);
};
my_closure()
}
};
($i:ident, $expected:expr, $($e:expr => $f:expr),+ $(,)*) => {
any!($i, $expected, $($e => |_x| $f),+);
}
}
/// Attempts to repeatedly run the expression, stopping on a non-fatal error,
/// and directly returning any fatal error.
macro_rules! drive {
($i:ident, $e:expr) => {
let mut $i = $i;
loop {
match $e {
Ok((j, _)) => $i = j,
Err(e) => if e.is_fatal() {
return Err(e);
} else {
break;
},
}
}
};
}
/// The type of error used by internal parsers
pub(crate) type PResult<'src, T> = Result<(In<'src>, T), ParserError>;
/// Specify that after this point, errors produced while parsing which are not
/// handled should instead be treated as fatal parsing errors.
macro_rules! commit {
($($e:tt)*) => {
// Evaluate the inner expression, transforming errors into fatal errors.
let eval = || { $($e)* };
eval().map_err($crate::util::ParserError::make_fatal)
}
}
/// This datastructure is used as the cursor type into the input source data. It
/// holds the full source string, and the current offset.
#[derive(Clone, Debug)]
pub(crate) struct In<'src> {
src: &'src str,
byte_offset: usize,
loc: Location,
}
impl<'src> In<'src> {
pub(crate) fn new(s: &'src str, file: String) -> Self {
In {
src: s,
byte_offset: 0,
loc: Location {
line: 1,
col: 0,
file,
},
}
}
/// The remaining string in the source file.
pub(crate) fn rest(&self) -> &'src str {
&self.src[self.byte_offset..]
}
/// Move the cursor forward by `n` characters.
pub(crate) fn advance(&self, n_chars: usize) -> Self {
let mut loc = self.loc.clone();
let (n_bytes, last_c) = self
.rest()
.char_indices()
.take(n_chars)
.inspect(|&(_, character)| {
if character == '\n' {
loc.line += 1;
loc.col = 0;
} else {
loc.col += 1;
}
})
.last()
.expect("No characters remaining in advance");
let byte_offset = self
.byte_offset
.checked_add(n_bytes + last_c.len_utf8())
.expect("Failed checked add");
assert!(byte_offset <= self.src.len());
In {
src: self.src,
byte_offset,
loc,
}
}
/// Produce a new non-fatal error result with the given expected value.
pub(crate) fn expected<T>(&self, expected: &'static str) -> Result<T, ParserError> {
assert!((self.byte_offset & FATAL_MASK) == 0, "Offset is too large!");
// Get the line where the error occurred.
let text = self.src.lines().nth(self.loc.line - 1).unwrap_or(""); // Usually happens when the error occurs on the last, empty line
// Format the final error message.
let message = format!(
"{}\n\
| {}\n{:~>off$}^\n",
format!("Expected {}", expected),
text,
"",
off = self.loc.col + 2
);
Err(ParserError {
message,
fatal: false,
span: Span {
start: self.loc.clone(),
end: self.loc.clone(),
},
})
}
pub(crate) fn loc(&self) -> Location {
self.loc.clone()
}
}
/// Repeatedly run f, collecting results into a vec. Returns an error if a fatal
/// error is produced while parsing.
pub(crate) fn many<'src, F, R>(i: In<'src>, mut f: F) -> PResult<'src, Vec<R>>
where
F: FnMut(In<'src>) -> PResult<'src, R>,
{
let mut v = Vec::new();
drive!(
i,
match f(i.clone()) {
Ok((i, x)) => {
v.push(x);
Ok((i, ()))
}
Err(e) => Err(e),
}
);
Ok((i, v))
}
/// Repeatedly run f, followed by parsing the seperator sep. Returns an error if
/// a fatal error is produced while parsing.
pub(crate) fn sep<'src, Parser, Ret>(
i: In<'src>,
mut parser: Parser,
sep: &'static str,
) -> PResult<'src, Vec<Ret>>
where
Parser: FnMut(In<'src>) -> PResult<'src, Ret>,
{
let mut return_vector = Vec::new();
drive!(
i,
match parser(i.clone()) {
Ok((i, result)) => {
return_vector.push(result);
match punct(i.clone(), sep) {
Ok(o) => Ok(o),
Err(_) => return Ok((i, return_vector)),
}
}
Err(e) => Err(e),
}
);
Ok((i, return_vector))
}
/// Skip any leading whitespace, including comments
pub(crate) fn skip_ws(mut i: In) -> Result<In, ParserError> {
loop {
if i.rest().is_empty() {
break;
}
let c = i
.rest()
.chars()
.next()
.expect("No characters remaining when skipping ws");
if c.is_whitespace() {
i = i.advance(1);
continue;
}
// Line comments
if i.rest().starts_with("//") {
while !i.rest().starts_with('\n') {
i = i.advance(1);
if i.rest().is_empty() {
break;
}
}
continue;
}
// Block comments
if i.rest().starts_with("/*") {
while !i.rest().starts_with("*/") {
i = i.advance(1);
if i.rest().is_empty() {
return i.expected("end of block comment (`*/`)");
}
}
i = i.advance(2);
continue;
}
break;
}
Ok(i)
}
/// Read an identifier as a string.
pub(crate) fn ident(i: In) -> PResult<Spanned<String>> {
let i = skip_ws(i)?;
let start = i.loc();
let (end_char, end_byte) = i
.rest()
.char_indices()
.enumerate()
.skip_while(|&(_, (b_idx, c))| match c {
'_' | 'a'...'z' | 'A'...'Z' => true,
'0'...'9' if b_idx != 0 => true,
_ => false,
})
.next()
.map(|(c_idx, (b_idx, _))| (c_idx, b_idx))
.unwrap_or((i.rest().chars().count(), i.rest().len()));
if end_byte == 0 {
return i.expected("identifier");
}
let j = i.advance(end_char);
let end = j.loc();
Ok((
j,
Spanned::new(Span { start, end }, i.rest()[..end_byte].to_owned()),
))
}
/// Parse a specific keyword.
pub(crate) fn kw<'src>(i: In<'src>, kw: &'static str) -> PResult<'src, Spanned<()>> {
let error_message = i.expected(kw);
let (i, id) = ident(i)?;
if id.data == kw {
Ok((i, Spanned::new(id.span, ())))
} else {
error_message
}
}
/// Parse punctuation.
pub(crate) fn punct<'src>(i: In<'src>, p: &'static str) -> PResult<'src, Spanned<()>> {
let i = skip_ws(i)?;
let start = i.loc();
if i.rest().starts_with(p) {
let i = i.advance(p.chars().count());
let end = i.loc();
Ok((i, Spanned::new(Span { start, end }, ())))
} else {
i.expected(p)
}
}
/// Try to parse the inner value, and return Some() if it succeeded, None if it
/// failed non-fatally, and an error if it failed fatally.
pub(crate) fn maybe<'src, T>(i: In<'src>, r: PResult<'src, T>) -> PResult<'src, Option<T>> {
match r {
Ok((i, x)) => Ok((i, Some(x))),
Err(e) => if e.is_fatal() {
Err(e)
} else {
Ok((i, None))
},
}
}
/// Parse a string literal.
pub(crate) fn string(i: In) -> PResult<Spanned<String>> {
let mut s = String::new();
let start = i.loc();
let (i, _) = punct(i, "\"")?;
let mut chars = i.rest().chars().enumerate().peekable();
while let Some((char_offset, ch)) = chars.next() {
match ch {
'"' => {
let i = i.advance(char_offset + 1);
let end = i.loc();
return Ok((i, Spanned::new(Span { start, end }, s)));
}
'\\' => match chars.next() {
Some((_, 'n')) => s.push('\n'),
Some((_, 'r')) => s.push('\r'),
Some((_, 't')) => s.push('\t'),
Some((_, '\\')) => s.push('\\'),
Some((_, '\'')) => s.push('\''),
Some((_, '"')) => s.push('"'),
Some((_, '0')) => s.push('\0'),
_ => {
return i
.advance(char_offset)
.expected("valid escape (\\n, \\r, \\t, \\\\, \\', \\\", or \\0)")
}
},
x => s.push(x),
}
}
i.expected("end of string literal (\")")
}

Просмотреть файл

@ -8,7 +8,6 @@ DIRS += [
'chromium',
'glue',
'ipdl',
'ipdl_new',
'testshell',
]

Просмотреть файл

@ -1 +0,0 @@
{"files":{"Cargo.toml":"fb96cad605ae48215811808c1cc1b9a50248f2b14542058094b23983e2f8d8a0","README.md":"c26d7101e3031e7dd8890ce938e50cad7a1e6adf7fc2f2b0d3c36b03afe68c0b","src/heap.rs":"fe84a4ff433568d5713685456d87597ac5dcdb9d5190061a3da8074240ba1bc3","src/lib.rs":"ce36db8e3464dddade7c1ddbe3ee1f5e525af5be492ea51a0d8a0776c1adfc28","src/range.rs":"bac59bcb6230367a39c7e28ac15263e4526f966cd8c72015873017f17c115aaa"},"package":"73fdf4b84c65a85168477b7fb6c498e0716bc9487fba24623389ea7f51708044"}

28
third_party/rust/thin-vec/Cargo.toml поставляемый
Просмотреть файл

@ -1,28 +0,0 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g. crates.io) dependencies
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
[package]
name = "thin-vec"
version = "0.1.0"
authors = ["Alexis Beingessner <a.beingessner@gmail.com>"]
description = "a vec that takes up less space on the stack"
homepage = "https://github.com/gankro/thin-vec"
readme = "README.md"
license = "MIT/Apache-2.0"
repository = "https://github.com/gankro/thin-vec"
[dependencies.libc]
version = "0.2"
[features]
default = []
gecko-ffi = []
unstable = []

4
third_party/rust/thin-vec/README.md поставляемый
Просмотреть файл

@ -1,4 +0,0 @@
ThinVec is a Vec that stores its length and capacity inline, making it take up
less space. Currently this crate mostly exists to facilitate gecko ffi. The
crate isn't quite ready for use elsewhere, as it currently unconditionally
uses the libc allocator.

15
third_party/rust/thin-vec/src/heap.rs поставляемый
Просмотреть файл

@ -1,15 +0,0 @@
extern crate libc;
pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
assert!(align <= 16);
libc::malloc(size) as *mut _
}
pub unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
libc::free(ptr as *mut _);
}
pub unsafe fn reallocate(ptr: *mut u8, _old_size: usize, size: usize, align: usize) -> *mut u8 {
assert!(align <= 16);
libc::realloc(ptr as *mut _, size) as *mut _
}

2366
third_party/rust/thin-vec/src/lib.rs поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

102
third_party/rust/thin-vec/src/range.rs поставляемый
Просмотреть файл

@ -1,102 +0,0 @@
use std::ops::{RangeFull, Range, RangeTo, RangeFrom};
use std::collections::Bound::{self, Excluded, Included, Unbounded};
/// `RangeArgument` is implemented by Rust's built-in range types, produced
/// by range syntax like `..`, `a..`, `..b` or `c..d`.
pub trait RangeArgument<T: ?Sized> {
/// Start index bound.
///
/// Returns the start value as a `Bound`.
fn start(&self) -> Bound<&T>;
/// End index bound.
///
/// Returns the end value as a `Bound`.
fn end(&self) -> Bound<&T>;
}
// FIXME add inclusive ranges to RangeArgument
impl<T: ?Sized> RangeArgument<T> for RangeFull {
fn start(&self) -> Bound<&T> {
Unbounded
}
fn end(&self) -> Bound<&T> {
Unbounded
}
}
impl<T> RangeArgument<T> for RangeFrom<T> {
fn start(&self) -> Bound<&T> {
Included(&self.start)
}
fn end(&self) -> Bound<&T> {
Unbounded
}
}
impl<T> RangeArgument<T> for RangeTo<T> {
fn start(&self) -> Bound<&T> {
Unbounded
}
fn end(&self) -> Bound<&T> {
Excluded(&self.end)
}
}
impl<T> RangeArgument<T> for Range<T> {
fn start(&self) -> Bound<&T> {
Included(&self.start)
}
fn end(&self) -> Bound<&T> {
Excluded(&self.end)
}
}
/* ~one day~
impl<T> RangeArgument<T> for RangeToInclusive<T> {
fn start(&self) -> Bound<&T> {
Unbounded
}
fn end(&self) -> Bound<&T> {
Included(&self.end)
}
}
impl<T> RangeArgument<T> for RangeInclusive<T> {
fn start(&self) -> Bound<&T> {
Included(&self.start)
}
fn end(&self) -> Bound<&T> {
Included(&self.end)
}
}
*/
impl<T> RangeArgument<T> for (Bound<T>, Bound<T>) {
fn start(&self) -> Bound<&T> {
match *self {
(Included(ref start), _) => Included(start),
(Excluded(ref start), _) => Excluded(start),
(Unbounded, _) => Unbounded,
}
}
fn end(&self) -> Bound<&T> {
match *self {
(_, Included(ref end)) => Included(end),
(_, Excluded(ref end)) => Excluded(end),
(_, Unbounded) => Unbounded,
}
}
}
impl<'a, T: ?Sized + 'a> RangeArgument<T> for (Bound<&'a T>, Bound<&'a T>) {
fn start(&self) -> Bound<&T> {
self.0
}
fn end(&self) -> Bound<&T> {
self.1
}
}

Просмотреть файл

@ -27,7 +27,6 @@ rsdparsa_capi = { path = "../../../../media/webrtc/signaling/src/sdp/rsdparsa_ca
log = {version = "0.4", features = ["release_max_level_info"]}
env_logger = {version = "0.5", default-features = false} # disable `regex` to reduce code size
cose-c = { version = "0.1.5" }
ipdl_bindings = {path = "../../../../ipc/ipdl_new/ipdl_bindings"}
rkv = "0.4"
[build-dependencies]

Просмотреть файл

@ -31,7 +31,6 @@ extern crate u2fhid;
extern crate log;
extern crate cosec;
extern crate rsdparsa_capi;
extern crate ipdl_bindings;
use std::boxed::Box;
use std::env;

Просмотреть файл

@ -1,7 +0,0 @@
[package]
name = "mfbt-maybe"
version = "0.1.0"
authors = ["Tristan Bourvon <tristanbourvon@gmail.com>"]
[lib]
name = "mfbt_maybe"

Просмотреть файл

@ -1,43 +0,0 @@
// You know this is black magic, I know this is black magic, the code knows
// it's actually black magic - but let's just leave it alone.
// Thank you Manisheart for the trait type part.
pub struct Maybe<T: MaybeTrait> {
pub data: T::Data,
pub is_some: ::std::os::raw::c_char,
}
impl<T: MaybeTrait, U: Into<T>> From<Option<U>> for Maybe<T> {
fn from(o: Option<U>) -> Self {
T::from_option(o)
}
}
pub trait MaybeTrait {
type Data;
fn from_option<U: Into<Self>>(x: Option<U>) -> Maybe<Self>
where
Self: Sized;
}
#[macro_export]
macro_rules! maybe {
($t:ident) => {
impl MaybeTrait for $t {
type Data = [::std::os::raw::c_char; ::std::mem::size_of::<$t>()];
fn from_option<U: Into<Self>>(o: Option<U>) -> Maybe<Self> {
match o {
Some(x) => Maybe {
data: unsafe { ::std::mem::transmute(x.into()) },
is_some: 1,
},
None => Maybe {
data: unsafe { ::std::mem::zeroed() },
is_some: 0,
},
}
}
}
};
}