зеркало из https://github.com/mozilla/gecko-dev.git
Rewrite CPOWs to use one actor per process (bug 853209, r=billm,bholley,smaug).
This commit is contained in:
Родитель
e9dc650368
Коммит
71e7bc4fc9
|
@ -25,7 +25,6 @@
|
|||
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
||||
#include "mozilla/ipc/TestShellChild.h"
|
||||
#include "mozilla/ipc/XPCShellEnvironment.h"
|
||||
#include "mozilla/jsipc/PContextWrapperChild.h"
|
||||
#include "mozilla/layers/CompositorChild.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h"
|
||||
#include "mozilla/layers/PCompositorChild.h"
|
||||
|
@ -50,6 +49,7 @@
|
|||
#include "nsDebugImpl.h"
|
||||
#include "nsHashPropertyBag.h"
|
||||
#include "nsLayoutStylesheetCache.h"
|
||||
#include "nsIJSRuntimeService.h"
|
||||
|
||||
#include "IHistory.h"
|
||||
#include "nsDocShellCID.h"
|
||||
|
@ -64,6 +64,7 @@
|
|||
#include "nsFrameMessageManager.h"
|
||||
|
||||
#include "nsIGeolocationProvider.h"
|
||||
#include "JavaScriptParent.h"
|
||||
#include "mozilla/dom/PMemoryReportRequestChild.h"
|
||||
|
||||
#ifdef MOZ_PERMISSIONS
|
||||
|
@ -109,6 +110,7 @@
|
|||
#include "nsIPrincipal.h"
|
||||
#include "nsDeviceStorage.h"
|
||||
#include "AudioChannelService.h"
|
||||
#include "JavaScriptChild.h"
|
||||
#include "ProcessPriorityManager.h"
|
||||
|
||||
using namespace base;
|
||||
|
@ -123,6 +125,7 @@ using namespace mozilla::hal_sandbox;
|
|||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::layers;
|
||||
using namespace mozilla::net;
|
||||
using namespace mozilla::jsipc;
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
using namespace mozilla::system;
|
||||
#endif
|
||||
|
@ -552,6 +555,31 @@ static void FirstIdle(void)
|
|||
ContentChild::GetSingleton()->SendFirstIdle();
|
||||
}
|
||||
|
||||
mozilla::jsipc::PJavaScriptChild *
|
||||
ContentChild::AllocPJavaScript()
|
||||
{
|
||||
nsCOMPtr<nsIJSRuntimeService> svc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
|
||||
NS_ENSURE_TRUE(svc, NULL);
|
||||
|
||||
JSRuntime *rt;
|
||||
svc->GetRuntime(&rt);
|
||||
NS_ENSURE_TRUE(svc, NULL);
|
||||
|
||||
mozilla::jsipc::JavaScriptChild *child = new mozilla::jsipc::JavaScriptChild(rt);
|
||||
if (!child->init()) {
|
||||
delete child;
|
||||
return NULL;
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::DeallocPJavaScript(PJavaScriptChild *child)
|
||||
{
|
||||
delete child;
|
||||
return true;
|
||||
}
|
||||
|
||||
PBrowserChild*
|
||||
ContentChild::AllocPBrowser(const IPCTabContext& aContext,
|
||||
const uint32_t& aChromeFlags)
|
||||
|
@ -760,10 +788,19 @@ ContentChild::DeallocPTestShell(PTestShellChild* shell)
|
|||
return true;
|
||||
}
|
||||
|
||||
jsipc::JavaScriptChild *
|
||||
ContentChild::GetCPOWManager()
|
||||
{
|
||||
if (ManagedPJavaScriptChild().Length()) {
|
||||
return static_cast<JavaScriptChild*>(ManagedPJavaScriptChild()[0]);
|
||||
}
|
||||
JavaScriptChild* actor = static_cast<JavaScriptChild*>(SendPJavaScriptConstructor());
|
||||
return actor;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvPTestShellConstructor(PTestShellChild* actor)
|
||||
{
|
||||
actor->SendPContextWrapperConstructor()->SendPObjectWrapperConstructor(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,10 @@ class OptionalURIParams;
|
|||
class URIParams;
|
||||
}// namespace ipc
|
||||
|
||||
namespace jsipc {
|
||||
class JavaScriptChild;
|
||||
}
|
||||
|
||||
namespace layers {
|
||||
class PCompositorChild;
|
||||
} // namespace layers
|
||||
|
@ -126,6 +130,7 @@ public:
|
|||
virtual PTestShellChild* AllocPTestShell();
|
||||
virtual bool DeallocPTestShell(PTestShellChild*);
|
||||
virtual bool RecvPTestShellConstructor(PTestShellChild*);
|
||||
jsipc::JavaScriptChild *GetCPOWManager();
|
||||
|
||||
virtual PNeckoChild* AllocPNecko();
|
||||
virtual bool DeallocPNecko(PNeckoChild*);
|
||||
|
@ -156,6 +161,9 @@ public:
|
|||
const InfallibleTArray<OverrideMapping>& overrides,
|
||||
const nsCString& locale);
|
||||
|
||||
virtual mozilla::jsipc::PJavaScriptChild* AllocPJavaScript();
|
||||
virtual bool DeallocPJavaScript(mozilla::jsipc::PJavaScriptChild*);
|
||||
|
||||
virtual bool RecvSetOffline(const bool& offline);
|
||||
|
||||
virtual bool RecvNotifyVisited(const URIParams& aURI);
|
||||
|
|
|
@ -119,6 +119,7 @@ using namespace mozilla::system;
|
|||
#include "BluetoothService.h"
|
||||
#endif
|
||||
|
||||
#include "JavaScriptParent.h"
|
||||
#include "Crypto.h"
|
||||
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
|
@ -140,6 +141,7 @@ using namespace mozilla::idl;
|
|||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::layers;
|
||||
using namespace mozilla::net;
|
||||
using namespace mozilla::jsipc;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -1008,6 +1010,16 @@ ContentParent::NotifyTabDestroyed(PBrowserParent* aTab,
|
|||
}
|
||||
}
|
||||
|
||||
jsipc::JavaScriptParent*
|
||||
ContentParent::GetCPOWManager()
|
||||
{
|
||||
if (ManagedPJavaScriptParent().Length()) {
|
||||
return static_cast<JavaScriptParent*>(ManagedPJavaScriptParent()[0]);
|
||||
}
|
||||
JavaScriptParent* actor = static_cast<JavaScriptParent*>(SendPJavaScriptConstructor());
|
||||
return actor;
|
||||
}
|
||||
|
||||
TestShellParent*
|
||||
ContentParent::CreateTestShell()
|
||||
{
|
||||
|
@ -1578,6 +1590,24 @@ ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline)
|
|||
return true;
|
||||
}
|
||||
|
||||
mozilla::jsipc::PJavaScriptParent *
|
||||
ContentParent::AllocPJavaScript()
|
||||
{
|
||||
mozilla::jsipc::JavaScriptParent *parent = new mozilla::jsipc::JavaScriptParent();
|
||||
if (!parent->init()) {
|
||||
delete parent;
|
||||
return NULL;
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::DeallocPJavaScript(PJavaScriptParent *parent)
|
||||
{
|
||||
static_cast<mozilla::jsipc::JavaScriptParent *>(parent)->destroyFromContent();
|
||||
return true;
|
||||
}
|
||||
|
||||
PBrowserParent*
|
||||
ContentParent::AllocPBrowser(const IPCTabContext& aContext,
|
||||
const uint32_t &aChromeFlags)
|
||||
|
|
|
@ -44,6 +44,10 @@ class URIParams;
|
|||
class TestShellParent;
|
||||
} // namespace ipc
|
||||
|
||||
namespace jsipc {
|
||||
class JavaScriptParent;
|
||||
}
|
||||
|
||||
namespace layers {
|
||||
class PCompositorParent;
|
||||
} // namespace layers
|
||||
|
@ -126,6 +130,7 @@ public:
|
|||
TestShellParent* CreateTestShell();
|
||||
bool DestroyTestShell(TestShellParent* aTestShell);
|
||||
TestShellParent* GetTestShellSingleton();
|
||||
jsipc::JavaScriptParent *GetCPOWManager();
|
||||
|
||||
void ReportChildAlreadyBlocked();
|
||||
bool RequestRunToCompletion();
|
||||
|
@ -194,6 +199,7 @@ private:
|
|||
// using them.
|
||||
using PContentParent::SendPBrowserConstructor;
|
||||
using PContentParent::SendPTestShellConstructor;
|
||||
using PContentParent::SendPJavaScriptConstructor;
|
||||
|
||||
// No more than one of !!aApp, aIsForBrowser, and aIsForPreallocated may be
|
||||
// true.
|
||||
|
@ -251,6 +257,9 @@ private:
|
|||
bool* aIsForBrowser) MOZ_OVERRIDE;
|
||||
virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline) MOZ_OVERRIDE;
|
||||
|
||||
virtual mozilla::jsipc::PJavaScriptParent* AllocPJavaScript();
|
||||
virtual bool DeallocPJavaScript(mozilla::jsipc::PJavaScriptParent*);
|
||||
|
||||
virtual PBrowserParent* AllocPBrowser(const IPCTabContext& aContext,
|
||||
const uint32_t& aChromeFlags);
|
||||
virtual bool DeallocPBrowser(PBrowserParent* frame);
|
||||
|
|
|
@ -42,6 +42,7 @@ LOCAL_INCLUDES += \
|
|||
-I$(topsrcdir)/dom/bluetooth \
|
||||
-I$(topsrcdir)/dom/bluetooth/ipc \
|
||||
-I$(topsrcdir)/content/media/webspeech/synth/ipc \
|
||||
-I$(topsrcdir)/js/ipc \
|
||||
$(NULL)
|
||||
|
||||
DEFINES += -DBIN_SUFFIX='"$(BIN_SUFFIX)"'
|
||||
|
|
|
@ -20,6 +20,7 @@ include protocol PSms;
|
|||
include protocol PSpeechSynthesis;
|
||||
include protocol PStorage;
|
||||
include protocol PTestShell;
|
||||
include protocol PJavaScript;
|
||||
include DOMTypes;
|
||||
include InputStreamParams;
|
||||
include URIParams;
|
||||
|
@ -252,6 +253,7 @@ rpc protocol PContent
|
|||
manages PSpeechSynthesis;
|
||||
manages PStorage;
|
||||
manages PTestShell;
|
||||
manages PJavaScript;
|
||||
|
||||
both:
|
||||
// Depending on exactly how the new browser is being created, it might be
|
||||
|
@ -281,6 +283,8 @@ both:
|
|||
|
||||
async PBlob(BlobConstructorParams params);
|
||||
|
||||
PJavaScript();
|
||||
|
||||
child:
|
||||
/**
|
||||
* Update OS process privileges to |privs|. Can usually only be
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
include protocol PContent;
|
||||
include protocol PTestShellCommand;
|
||||
include protocol PContextWrapper;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
@ -15,7 +14,6 @@ rpc protocol PTestShell
|
|||
manager PContent;
|
||||
|
||||
manages PTestShellCommand;
|
||||
manages PContextWrapper;
|
||||
|
||||
child:
|
||||
__delete__();
|
||||
|
@ -23,10 +21,6 @@ child:
|
|||
ExecuteCommand(nsString aCommand);
|
||||
|
||||
PTestShellCommand(nsString aCommand);
|
||||
|
||||
parent:
|
||||
PContextWrapper();
|
||||
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
|
|
|
@ -3,13 +3,10 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "TestShellChild.h"
|
||||
#include "mozilla/jsipc/ContextWrapperChild.h"
|
||||
|
||||
using mozilla::ipc::TestShellChild;
|
||||
using mozilla::ipc::PTestShellCommandChild;
|
||||
using mozilla::ipc::XPCShellEnvironment;
|
||||
using mozilla::jsipc::PContextWrapperChild;
|
||||
using mozilla::jsipc::ContextWrapperChild;
|
||||
|
||||
TestShellChild::TestShellChild()
|
||||
: mXPCShell(XPCShellEnvironment::CreateEnvironment())
|
||||
|
@ -57,19 +54,3 @@ TestShellChild::RecvPTestShellCommandConstructor(PTestShellCommandChild* aActor,
|
|||
return PTestShellCommandChild::Send__delete__(aActor, response);
|
||||
}
|
||||
|
||||
PContextWrapperChild*
|
||||
TestShellChild::AllocPContextWrapper()
|
||||
{
|
||||
JSContext* cx;
|
||||
if (mXPCShell && (cx = mXPCShell->GetContext())) {
|
||||
return new ContextWrapperChild(cx);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
TestShellChild::DeallocPContextWrapper(PContextWrapperChild* actor)
|
||||
{
|
||||
delete actor;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -13,10 +13,6 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
namespace jsipc {
|
||||
class PContextWrapperChild;
|
||||
}
|
||||
|
||||
namespace ipc {
|
||||
|
||||
class XPCShellEnvironment;
|
||||
|
@ -39,9 +35,6 @@ public:
|
|||
bool
|
||||
DeallocPTestShellCommand(PTestShellCommandChild* aCommand);
|
||||
|
||||
PContextWrapperChild* AllocPContextWrapper();
|
||||
bool DeallocPContextWrapper(PContextWrapperChild* actor);
|
||||
|
||||
private:
|
||||
nsAutoPtr<XPCShellEnvironment> mXPCShell;
|
||||
};
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include "mozilla/Util.h"
|
||||
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/jsipc/ContextWrapperParent.h"
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
|
@ -17,8 +16,6 @@ using mozilla::ipc::TestShellParent;
|
|||
using mozilla::ipc::TestShellCommandParent;
|
||||
using mozilla::ipc::PTestShellCommandParent;
|
||||
using mozilla::dom::ContentParent;
|
||||
using mozilla::jsipc::PContextWrapperParent;
|
||||
using mozilla::jsipc::ContextWrapperParent;
|
||||
|
||||
PTestShellCommandParent*
|
||||
TestShellParent::AllocPTestShellCommand(const nsString& aCommand)
|
||||
|
@ -44,32 +41,6 @@ TestShellParent::CommandDone(TestShellCommandParent* command,
|
|||
return true;
|
||||
}
|
||||
|
||||
PContextWrapperParent*
|
||||
TestShellParent::AllocPContextWrapper()
|
||||
{
|
||||
return new ContextWrapperParent();
|
||||
}
|
||||
|
||||
bool
|
||||
TestShellParent::DeallocPContextWrapper(PContextWrapperParent* actor)
|
||||
{
|
||||
delete actor;
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
TestShellParent::GetGlobalJSObject(JSContext* cx, JSObject** globalp)
|
||||
{
|
||||
// TODO Unify this code with TabParent::GetGlobalJSObject.
|
||||
InfallibleTArray<PContextWrapperParent*> cwps(1);
|
||||
ManagedPContextWrapperParent(cwps);
|
||||
if (cwps.Length() < 1)
|
||||
return JS_FALSE;
|
||||
NS_ASSERTION(cwps.Length() == 1, "More than one PContextWrapper?");
|
||||
ContextWrapperParent* cwp = static_cast<ContextWrapperParent*>(cwps[0]);
|
||||
return cwp->GetGlobalJSObject(cx, globalp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
TestShellCommandParent::SetCallback(JSContext* aCx,
|
||||
JS::Value aCallback)
|
||||
|
|
|
@ -20,10 +20,6 @@ class JSObject;
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
namespace jsipc {
|
||||
class PContextWrapperParent;
|
||||
}
|
||||
|
||||
namespace ipc {
|
||||
|
||||
class TestShellCommandParent;
|
||||
|
@ -39,11 +35,6 @@ public:
|
|||
|
||||
bool
|
||||
CommandDone(TestShellCommandParent* aActor, const nsString& aResponse);
|
||||
|
||||
PContextWrapperParent* AllocPContextWrapper();
|
||||
bool DeallocPContextWrapper(PContextWrapperParent* actor);
|
||||
|
||||
JSBool GetGlobalJSObject(JSContext* cx, JSObject** globalp);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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/. */
|
||||
|
||||
#ifndef mozilla_jsipc_CPOWTypes_h
|
||||
#define mozilla_jsipc_CPOWTypes_h
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jspubtd.h"
|
||||
|
||||
using mozilla::void_t;
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
|
||||
template <typename P>
|
||||
struct CPOWSingleton
|
||||
{
|
||||
static void Write(IPC::Message*, const P&) {}
|
||||
static bool Read(const IPC::Message*, void**, P*) { return true; }
|
||||
};
|
||||
|
||||
template <typename Type, typename As>
|
||||
struct CPOWConvertible
|
||||
{
|
||||
static void Write(IPC::Message* m, const Type& t) {
|
||||
WriteParam(m, As(t));
|
||||
}
|
||||
static bool Read(const IPC::Message* m, void** iter, Type* tp) {
|
||||
As a;
|
||||
return (ReadParam(m, iter, &a) &&
|
||||
(*tp = Type(a), true));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace jsipc
|
||||
} // namespace mozilla
|
||||
|
||||
namespace IPC {
|
||||
|
||||
|
||||
template <> struct ParamTraits<JSType> : public mozilla::jsipc::CPOWConvertible<JSType, int> {};
|
||||
|
||||
}
|
||||
|
||||
// TODO Use a more standard logging mechanism.
|
||||
#ifdef LOGGING
|
||||
#define CPOW_LOG(PRINTF_ARGS) \
|
||||
JS_BEGIN_MACRO \
|
||||
printf("CPOW | "); \
|
||||
printf PRINTF_ARGS ; \
|
||||
printf("\n"); \
|
||||
JS_END_MACRO
|
||||
#define JSVAL_TO_CSTR(CX, V) \
|
||||
NS_ConvertUTF16toUTF8(nsString(JS_GetStringChars(JS_ValueToString(CX, V)))).get()
|
||||
#else
|
||||
#define CPOW_LOG(_) JS_BEGIN_MACRO JS_END_MACRO
|
||||
#define JSVAL_TO_CSTR(CX, V) ((char*)0)
|
||||
#endif
|
||||
|
||||
#endif /* mozilla_jsipc_CPOWTypes_h */
|
|
@ -1,80 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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/. */
|
||||
|
||||
#ifndef mozilla_jsipc_ContextWrapperChild_h
|
||||
#define mozilla_jsipc_ContextWrapperChild_h
|
||||
|
||||
#include "mozilla/jsipc/PContextWrapperChild.h"
|
||||
#include "mozilla/jsipc/ObjectWrapperChild.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
class ContextWrapperChild
|
||||
: public PContextWrapperChild
|
||||
{
|
||||
public:
|
||||
|
||||
ContextWrapperChild(JSContext* cx)
|
||||
: mContext(cx)
|
||||
{
|
||||
mResidentObjectTable.Init();
|
||||
}
|
||||
|
||||
JSContext* GetContext() { return mContext; }
|
||||
|
||||
PObjectWrapperChild* GetOrCreateWrapper(JSObject* obj_,
|
||||
bool makeGlobal = false)
|
||||
{
|
||||
if (!obj_) // Don't wrap nothin'!
|
||||
return NULL;
|
||||
JS::RootedObject obj(mContext, obj_);
|
||||
PObjectWrapperChild* wrapper;
|
||||
while (!mResidentObjectTable.Get(obj, &wrapper)) {
|
||||
wrapper = SendPObjectWrapperConstructor(AllocPObjectWrapper(obj),
|
||||
makeGlobal);
|
||||
if (wrapper)
|
||||
mResidentObjectTable.Put(obj, wrapper);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
PObjectWrapperChild* AllocPObjectWrapper(JSObject* obj) {
|
||||
return new ObjectWrapperChild(mContext, obj);
|
||||
}
|
||||
|
||||
PObjectWrapperChild* AllocPObjectWrapper(const bool&) {
|
||||
// This stuff is unused and billm has a patch to delete it.
|
||||
JSAutoRequest ar(mContext);
|
||||
return AllocPObjectWrapper(JS_GetGlobalForScopeChain(mContext));
|
||||
}
|
||||
|
||||
bool DeallocPObjectWrapper(PObjectWrapperChild* actor) {
|
||||
ObjectWrapperChild* owc = static_cast<ObjectWrapperChild*>(actor);
|
||||
mResidentObjectTable.Remove(owc->GetJSObject());
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
JSContext* const mContext;
|
||||
|
||||
nsClassHashtable<nsPtrHashKey<JSObject>,
|
||||
PObjectWrapperChild> mResidentObjectTable;
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* mozilla_jsipc_ContextWrapperChild_h */
|
|
@ -1,83 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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/. */
|
||||
|
||||
#ifndef mozilla_jsipc_ContextWrapperParent_h
|
||||
#define mozilla_jsipc_ContextWrapperParent_h
|
||||
|
||||
#include "mozilla/jsipc/PContextWrapperParent.h"
|
||||
#include "mozilla/jsipc/ObjectWrapperParent.h"
|
||||
#include "mozilla/jsipc/CPOWTypes.h"
|
||||
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "nsAutoJSValHolder.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
using mozilla::dom::ContentParent;
|
||||
|
||||
class ContextWrapperParent
|
||||
: public PContextWrapperParent
|
||||
{
|
||||
public:
|
||||
|
||||
ContextWrapperParent()
|
||||
: mGlobal(NULL)
|
||||
{}
|
||||
|
||||
JSBool GetGlobalJSObject(JSContext* cx, JSObject** globalp) {
|
||||
if (!mGlobal)
|
||||
return JS_FALSE;
|
||||
mGlobalHolder.Hold(cx);
|
||||
mGlobalHolder = *globalp = mGlobal->GetJSObject(cx);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
ObjectWrapperParent* GetGlobalObjectWrapper() const {
|
||||
return mGlobal;
|
||||
}
|
||||
|
||||
bool RequestRunToCompletion() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
ObjectWrapperParent* mGlobal;
|
||||
nsAutoJSValHolder mGlobalHolder;
|
||||
|
||||
PObjectWrapperParent* AllocPObjectWrapper(const bool&) {
|
||||
return new ObjectWrapperParent();
|
||||
}
|
||||
|
||||
bool RecvPObjectWrapperConstructor(PObjectWrapperParent* actor,
|
||||
const bool& makeGlobal)
|
||||
{
|
||||
if (makeGlobal) {
|
||||
mGlobalHolder.Release();
|
||||
mGlobal = static_cast<ObjectWrapperParent*>(actor);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeallocPObjectWrapper(PObjectWrapperParent* actor)
|
||||
{
|
||||
if (mGlobal &&
|
||||
mGlobal == static_cast<ObjectWrapperParent*>(actor)) {
|
||||
mGlobalHolder.Release();
|
||||
mGlobal = NULL;
|
||||
}
|
||||
delete actor;
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* mozilla_jsipc_ContextWrapperParent_h */
|
|
@ -0,0 +1,605 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=80:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "JavaScriptChild.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "xpcprivate.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "nsCxPusher.h"
|
||||
|
||||
using namespace JS;
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::jsipc;
|
||||
|
||||
using mozilla::AutoSafeJSContext;
|
||||
|
||||
JavaScriptChild::JavaScriptChild(JSRuntime *rt)
|
||||
: lastId_(0),
|
||||
rt_(rt)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
Trace(JSTracer *trc, void *data)
|
||||
{
|
||||
reinterpret_cast<JavaScriptChild *>(data)->trace(trc);
|
||||
}
|
||||
|
||||
JavaScriptChild::~JavaScriptChild()
|
||||
{
|
||||
JS_RemoveExtraGCRootsTracer(rt_, Trace, this);
|
||||
}
|
||||
|
||||
void
|
||||
JavaScriptChild::trace(JSTracer *trc)
|
||||
{
|
||||
objects_.trace(trc);
|
||||
ids_.trace(trc);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::init()
|
||||
{
|
||||
if (!JavaScriptShared::init())
|
||||
return false;
|
||||
if (!ids_.init())
|
||||
return false;
|
||||
|
||||
JS_AddExtraGCRootsTracer(rt_, Trace, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::RecvDropObject(const ObjectId &objId)
|
||||
{
|
||||
JSObject *obj = findObject(objId);
|
||||
if (obj) {
|
||||
ids_.remove(obj);
|
||||
objects_.remove(objId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::makeId(JSContext *cx, JSObject *obj, ObjectId *idp)
|
||||
{
|
||||
if (!obj) {
|
||||
*idp = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
ObjectId id = ids_.find(obj);
|
||||
if (id) {
|
||||
*idp = id;
|
||||
return true;
|
||||
}
|
||||
|
||||
id = ++lastId_;
|
||||
if (id > MAX_CPOW_IDS) {
|
||||
JS_ReportError(cx, "CPOW id limit reached");
|
||||
return false;
|
||||
}
|
||||
|
||||
id <<= OBJECT_EXTRA_BITS;
|
||||
if (JS_ObjectIsCallable(cx, obj))
|
||||
id |= OBJECT_IS_CALLABLE;
|
||||
|
||||
if (!objects_.add(id, obj))
|
||||
return false;
|
||||
if (!ids_.add(obj, id))
|
||||
return false;
|
||||
|
||||
*idp = id;
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
JavaScriptChild::unwrap(JSContext *cx, ObjectId id)
|
||||
{
|
||||
JSObject *obj = findObject(id);
|
||||
MOZ_ASSERT(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::fail(JSContext *cx, ReturnStatus *rs)
|
||||
{
|
||||
// By default, we set |undefined| unless we can get a more meaningful
|
||||
// exception.
|
||||
*rs = ReturnStatus(false, JSVariant(void_t()));
|
||||
|
||||
// Note we always return true from this function, since this propagates
|
||||
// to the IPC code, and we don't want a JS failure to cause the death
|
||||
// of the child process.
|
||||
|
||||
jsval exn;
|
||||
if (!JS_GetPendingException(cx, &exn))
|
||||
return true;
|
||||
|
||||
// If we don't clear the pending exception, JS will try to wrap it as it
|
||||
// leaves the current compartment. Since there is no previous compartment,
|
||||
// that would crash.
|
||||
JS_ClearPendingException(cx);
|
||||
|
||||
if (!toVariant(cx, exn, &rs->exn()))
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::ok(ReturnStatus *rs)
|
||||
{
|
||||
*rs = ReturnStatus(true, JSVariant(void_t()));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::AnswerHas(const ObjectId &objId, const nsString &id,
|
||||
ReturnStatus *rs, bool *bp)
|
||||
{
|
||||
AutoSafeJSContext cx;
|
||||
JSAutoRequest request(cx);
|
||||
|
||||
RootedObject obj(cx, findObject(objId));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
RootedId internedId(cx);
|
||||
if (!convertGeckoStringToId(cx, id, &internedId))
|
||||
return fail(cx, rs);
|
||||
|
||||
JSBool found;
|
||||
if (!JS_HasPropertyById(cx, obj, internedId, &found))
|
||||
return fail(cx, rs);
|
||||
*bp = !!found;
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::AnswerHasOwn(const ObjectId &objId, const nsString &id,
|
||||
ReturnStatus *rs, bool *bp)
|
||||
{
|
||||
AutoSafeJSContext cx;
|
||||
JSAutoRequest request(cx);
|
||||
|
||||
RootedObject obj(cx, findObject(objId));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
RootedId internedId(cx);
|
||||
if (!convertGeckoStringToId(cx, id, &internedId))
|
||||
return fail(cx, rs);
|
||||
|
||||
JSPropertyDescriptor desc;
|
||||
if (!JS_GetPropertyDescriptorById(cx, obj, internedId, 0, &desc))
|
||||
return fail(cx, rs);
|
||||
*bp = (desc.obj == obj);
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::AnswerGet(const ObjectId &objId, const ObjectId &receiverId,
|
||||
const nsString &id,
|
||||
ReturnStatus *rs, JSVariant *result)
|
||||
{
|
||||
AutoSafeJSContext cx;
|
||||
JSAutoRequest request(cx);
|
||||
|
||||
RootedObject obj(cx, findObject(objId));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
RootedObject receiver(cx, findObject(receiverId));
|
||||
if (!receiver)
|
||||
return false;
|
||||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
RootedId internedId(cx);
|
||||
if (!convertGeckoStringToId(cx, id, &internedId))
|
||||
return fail(cx, rs);
|
||||
|
||||
JS::Value val;
|
||||
if (!JS_ForwardGetPropertyTo(cx, obj, internedId, receiver, &val))
|
||||
return fail(cx, rs);
|
||||
|
||||
if (!toVariant(cx, val, result))
|
||||
return fail(cx, rs);
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::AnswerSet(const ObjectId &objId, const ObjectId &receiverId,
|
||||
const nsString &id, const bool &strict,
|
||||
const JSVariant &value,
|
||||
ReturnStatus *rs, JSVariant *result)
|
||||
{
|
||||
AutoSafeJSContext cx;
|
||||
JSAutoRequest request(cx);
|
||||
|
||||
// The outparam will be written to the buffer, so it must be set even if
|
||||
// the parent won't read it.
|
||||
*result = void_t();
|
||||
|
||||
RootedObject obj(cx, findObject(objId));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
RootedObject receiver(cx, findObject(receiverId));
|
||||
if (!receiver)
|
||||
return false;
|
||||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
RootedId internedId(cx);
|
||||
if (!convertGeckoStringToId(cx, id, &internedId))
|
||||
return fail(cx, rs);
|
||||
|
||||
MOZ_ASSERT(obj == receiver);
|
||||
|
||||
RootedValue val(cx);
|
||||
|
||||
if (!toValue(cx, value, &val))
|
||||
return fail(cx, rs);
|
||||
|
||||
if (!JS_SetPropertyById(cx, obj, internedId, val.address()))
|
||||
return fail(cx, rs);
|
||||
|
||||
if (!toVariant(cx, val, result))
|
||||
return fail(cx, rs);
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::AnswerCall(const ObjectId &objId,
|
||||
const nsTArray<JSParam> &argv,
|
||||
ReturnStatus *rs,
|
||||
JSVariant *result,
|
||||
nsTArray<JSParam> *outparams)
|
||||
{
|
||||
AutoSafeJSContext cx;
|
||||
JSAutoRequest request(cx);
|
||||
|
||||
// The outparam will be written to the buffer, so it must be set even if
|
||||
// the parent won't read it.
|
||||
*result = void_t();
|
||||
|
||||
RootedObject obj(cx, findObject(objId));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(argv.Length() >= 2);
|
||||
|
||||
RootedValue objv(cx);
|
||||
if (!toValue(cx, argv[0], &objv))
|
||||
return fail(cx, rs);
|
||||
|
||||
JSAutoCompartment comp(cx, &objv.toObject());
|
||||
|
||||
*result = JSVariant(void_t());
|
||||
|
||||
JS::AutoValueVector vals(cx);
|
||||
JS::AutoValueVector outobjects(cx);
|
||||
for (size_t i = 0; i < argv.Length(); i++) {
|
||||
if (argv[i].type() == JSParam::Tvoid_t) {
|
||||
// This is an outparam.
|
||||
JSCompartment *compartment = js::GetContextCompartment(cx);
|
||||
RootedObject global(cx, JS_GetGlobalForCompartmentOrNull(cx, compartment));
|
||||
RootedObject obj(cx, xpc::NewOutObject(cx, global));
|
||||
if (!obj)
|
||||
return fail(cx, rs);
|
||||
if (!outobjects.append(ObjectValue(*obj)))
|
||||
return fail(cx, rs);
|
||||
if (!vals.append(ObjectValue(*obj)))
|
||||
return fail(cx, rs);
|
||||
} else {
|
||||
RootedValue v(cx);
|
||||
if (!toValue(cx, argv[i].get_JSVariant(), &v))
|
||||
return fail(cx, rs);
|
||||
if (!vals.append(v))
|
||||
return fail(cx, rs);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t oldOpts =
|
||||
JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_DONT_REPORT_UNCAUGHT);
|
||||
|
||||
jsval rval;
|
||||
bool success = JS::Call(cx, vals[1], vals[0], vals.length() - 2, vals.begin() + 2, &rval);
|
||||
|
||||
JS_SetOptions(cx, oldOpts);
|
||||
|
||||
if (!success)
|
||||
return fail(cx, rs);
|
||||
|
||||
if (!toVariant(cx, rval, result))
|
||||
return fail(cx, rs);
|
||||
|
||||
// Prefill everything with a dummy jsval.
|
||||
for (size_t i = 0; i < outobjects.length(); i++)
|
||||
outparams->AppendElement(JSParam(void_t()));
|
||||
|
||||
// Go through each argument that was an outparam, retrieve the "value"
|
||||
// field, and add it to a temporary list. We need to do this separately
|
||||
// because the outparams vector is not rooted.
|
||||
vals.clear();
|
||||
for (size_t i = 0; i < outobjects.length(); i++) {
|
||||
RootedObject obj(cx, &outobjects[i].toObject());
|
||||
|
||||
jsval v;
|
||||
JSBool found;
|
||||
if (JS_HasProperty(cx, obj, "value", &found)) {
|
||||
if (!JS_GetProperty(cx, obj, "value", &v))
|
||||
return fail(cx, rs);
|
||||
} else {
|
||||
v = UndefinedValue();
|
||||
}
|
||||
if (!vals.append(v))
|
||||
return fail(cx, rs);
|
||||
}
|
||||
|
||||
// Copy the outparams. If any outparam is already set to a void_t, we
|
||||
// treat this as the outparam never having been set.
|
||||
for (size_t i = 0; i < vals.length(); i++) {
|
||||
JSVariant variant;
|
||||
if (!toVariant(cx, vals[i], &variant))
|
||||
return fail(cx, rs);
|
||||
outparams->ReplaceElementAt(i, JSParam(variant));
|
||||
}
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::AnswerInstanceOf(const ObjectId &objId,
|
||||
const JSIID &iid,
|
||||
ReturnStatus *rs,
|
||||
bool *instanceof)
|
||||
{
|
||||
AutoSafeJSContext cx;
|
||||
JSAutoRequest request(cx);
|
||||
|
||||
RootedObject obj(cx, findObject(objId));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
nsID nsiid;
|
||||
ConvertID(iid, &nsiid);
|
||||
|
||||
nsresult rv = xpc::HasInstance(cx, obj, &nsiid, instanceof);
|
||||
if (rv != NS_OK)
|
||||
return fail(cx, rs);
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
void
|
||||
EmptyDesc(PPropertyDescriptor *desc)
|
||||
{
|
||||
desc->objId() = 0;
|
||||
desc->attrs() = 0;
|
||||
desc->shortid() = 0;
|
||||
desc->value() = void_t();
|
||||
desc->getter() = 0;
|
||||
desc->setter() = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::AnswerGetPropertyDescriptor(const ObjectId &objId,
|
||||
const nsString &id,
|
||||
const uint32_t &flags,
|
||||
ReturnStatus *rs,
|
||||
PPropertyDescriptor *out)
|
||||
{
|
||||
AutoSafeJSContext cx;
|
||||
JSAutoRequest request(cx);
|
||||
|
||||
RootedObject obj(cx, findObject(objId));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
RootedId internedId(cx);
|
||||
if (!convertGeckoStringToId(cx, id, &internedId))
|
||||
return fail(cx, rs);
|
||||
|
||||
JSPropertyDescriptor desc;
|
||||
if (!JS_GetPropertyDescriptorById(cx, obj, internedId, flags, &desc))
|
||||
return fail(cx, rs);
|
||||
|
||||
if (!desc.obj) {
|
||||
EmptyDesc(out);
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
if (!fromDescriptor(cx, desc, out))
|
||||
return fail(cx, rs);
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::AnswerGetOwnPropertyDescriptor(const ObjectId &objId,
|
||||
const nsString &id,
|
||||
const uint32_t &flags,
|
||||
ReturnStatus *rs,
|
||||
PPropertyDescriptor *out)
|
||||
{
|
||||
AutoSafeJSContext cx;
|
||||
JSAutoRequest request(cx);
|
||||
|
||||
RootedObject obj(cx, findObject(objId));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
RootedId internedId(cx);
|
||||
if (!convertGeckoStringToId(cx, id, &internedId))
|
||||
return fail(cx, rs);
|
||||
|
||||
JSPropertyDescriptor desc;
|
||||
if (!JS_GetPropertyDescriptorById(cx, obj, internedId, flags, &desc))
|
||||
return fail(cx, rs);
|
||||
|
||||
if (desc.obj != obj) {
|
||||
EmptyDesc(out);
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
if (!fromDescriptor(cx, desc, out))
|
||||
return fail(cx, rs);
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::AnswerGetOwnPropertyNames(const ObjectId &objId,
|
||||
ReturnStatus *rs,
|
||||
nsTArray<nsString> *names)
|
||||
{
|
||||
AutoSafeJSContext cx;
|
||||
JSAutoRequest request(cx);
|
||||
|
||||
RootedObject obj(cx, findObject(objId));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
AutoIdVector props(cx);
|
||||
if (!js::GetPropertyNames(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, &props))
|
||||
return fail(cx, rs);
|
||||
|
||||
for (size_t i = 0; i < props.length(); i++) {
|
||||
nsString name;
|
||||
if (!convertIdToGeckoString(cx, props.handleAt(i), &name))
|
||||
return false;
|
||||
|
||||
names->AppendElement(name);
|
||||
}
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::AnswerKeys(const ObjectId &objId,
|
||||
ReturnStatus *rs,
|
||||
nsTArray<nsString> *names)
|
||||
{
|
||||
AutoSafeJSContext cx;
|
||||
JSAutoRequest request(cx);
|
||||
|
||||
RootedObject obj(cx, findObject(objId));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
AutoIdVector props(cx);
|
||||
if (!js::GetPropertyNames(cx, obj, JSITER_OWNONLY, &props))
|
||||
return fail(cx, rs);
|
||||
|
||||
for (size_t i = 0; i < props.length(); i++) {
|
||||
nsString name;
|
||||
if (!convertIdToGeckoString(cx, props.handleAt(i), &name))
|
||||
return false;
|
||||
|
||||
names->AppendElement(name);
|
||||
}
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::AnswerObjectClassIs(const ObjectId &objId,
|
||||
const uint32_t &classValue,
|
||||
bool *result)
|
||||
{
|
||||
AutoSafeJSContext cx;
|
||||
JSAutoRequest request(cx);
|
||||
|
||||
RootedObject obj(cx, findObject(objId));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
*result = js_ObjectClassIs(cx, obj, (js::ESClassValue)classValue);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::AnswerClassName(const ObjectId &objId,
|
||||
nsString *name)
|
||||
{
|
||||
AutoSafeJSContext cx;
|
||||
JSAutoRequest request(cx);
|
||||
|
||||
RootedObject obj(cx, findObject(objId));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
*name = NS_ConvertASCIItoUTF16(js_ObjectClassName(cx, obj));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::AnswerIsExtensible(const ObjectId &objId,
|
||||
ReturnStatus *rs,
|
||||
bool *result)
|
||||
{
|
||||
AutoSafeJSContext cx;
|
||||
JSAutoRequest request(cx);
|
||||
|
||||
*result = false;
|
||||
|
||||
RootedObject obj(cx, findObject(objId));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
JSBool extensible;
|
||||
if (!JS_IsExtensible(cx, obj, &extensible))
|
||||
return fail(cx, rs);
|
||||
|
||||
*result = !!extensible;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::AnswerPreventExtensions(const ObjectId &objId,
|
||||
ReturnStatus *rs)
|
||||
{
|
||||
AutoSafeJSContext cx;
|
||||
JSAutoRequest request(cx);
|
||||
|
||||
RootedObject obj(cx, findObject(objId));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
if (!JS_PreventExtensions(cx, obj))
|
||||
return fail(cx, rs);
|
||||
|
||||
return ok(rs);
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=80:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_jsipc_JavaScriptChild_h_
|
||||
#define mozilla_jsipc_JavaScriptChild_h_
|
||||
|
||||
#include "JavaScriptShared.h"
|
||||
#include "mozilla/jsipc/PJavaScriptChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
class JavaScriptChild
|
||||
: public PJavaScriptChild,
|
||||
public JavaScriptShared
|
||||
{
|
||||
public:
|
||||
JavaScriptChild(JSRuntime *rt);
|
||||
~JavaScriptChild();
|
||||
|
||||
bool init();
|
||||
void trace(JSTracer *trc);
|
||||
|
||||
bool RecvDropObject(const ObjectId &objId);
|
||||
|
||||
bool AnswerHas(const ObjectId &objId, const nsString &id,
|
||||
ReturnStatus *rs, bool *bp);
|
||||
bool AnswerHasOwn(const ObjectId &objId, const nsString &id,
|
||||
ReturnStatus *rs, bool *bp);
|
||||
bool AnswerGet(const ObjectId &objId, const ObjectId &receiverId,
|
||||
const nsString &id,
|
||||
ReturnStatus *rs, JSVariant *result);
|
||||
bool AnswerSet(const ObjectId &objId, const ObjectId &receiverId,
|
||||
const nsString &id, const bool &strict,
|
||||
const JSVariant &value,
|
||||
ReturnStatus *rs, JSVariant *result);
|
||||
bool AnswerCall(const ObjectId &objId,
|
||||
const nsTArray<JSParam> &argv,
|
||||
ReturnStatus *rs,
|
||||
JSVariant *result,
|
||||
nsTArray<JSParam> *outparams);
|
||||
|
||||
bool AnswerInstanceOf(const ObjectId &objId,
|
||||
const JSIID &iid,
|
||||
ReturnStatus *rs,
|
||||
bool *instanceof);
|
||||
bool AnswerGetPropertyDescriptor(const ObjectId &objId,
|
||||
const nsString &id,
|
||||
const uint32_t &flags,
|
||||
ReturnStatus *rs,
|
||||
PPropertyDescriptor *out);
|
||||
bool AnswerGetOwnPropertyDescriptor(const ObjectId &objId,
|
||||
const nsString &id,
|
||||
const uint32_t &flags,
|
||||
ReturnStatus *rs,
|
||||
PPropertyDescriptor *out);
|
||||
bool AnswerGetOwnPropertyNames(const ObjectId &objId,
|
||||
ReturnStatus *rs,
|
||||
nsTArray<nsString> *names);
|
||||
bool AnswerKeys(const ObjectId &objId,
|
||||
ReturnStatus *rs,
|
||||
nsTArray<nsString> *names);
|
||||
bool AnswerObjectClassIs(const ObjectId &objId,
|
||||
const uint32_t &classValue,
|
||||
bool *result);
|
||||
bool AnswerClassName(const ObjectId &objId,
|
||||
nsString *result);
|
||||
bool AnswerIsExtensible(const ObjectId &objId,
|
||||
ReturnStatus *rs,
|
||||
bool *result);
|
||||
bool AnswerPreventExtensions(const ObjectId &objId,
|
||||
ReturnStatus *rs);
|
||||
|
||||
protected:
|
||||
JSObject *unwrap(JSContext *cx, ObjectId id);
|
||||
|
||||
private:
|
||||
bool makeId(JSContext *cx, JSObject *obj, ObjectId *idp);
|
||||
bool fail(JSContext *cx, ReturnStatus *rs);
|
||||
bool ok(ReturnStatus *rs);
|
||||
|
||||
private:
|
||||
ObjectId lastId_;
|
||||
JSRuntime *rt_;
|
||||
ObjectIdCache ids_;
|
||||
};
|
||||
|
||||
} // mozilla
|
||||
} // jsipc
|
||||
|
||||
#endif
|
|
@ -0,0 +1,635 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=80:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "JavaScriptParent.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "jsproxy.h"
|
||||
#include "HeapAPI.h"
|
||||
#include "xpcprivate.h"
|
||||
#include "mozilla/Casting.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace JS;
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::jsipc;
|
||||
|
||||
JavaScriptParent::JavaScriptParent()
|
||||
: refcount_(1),
|
||||
inactive_(false)
|
||||
{
|
||||
}
|
||||
|
||||
static inline JavaScriptParent *
|
||||
ParentOf(JSObject *obj)
|
||||
{
|
||||
MOZ_ASSERT(JavaScriptParent::IsCPOW(obj));
|
||||
return reinterpret_cast<JavaScriptParent *>(GetProxyExtra(obj, 0).toPrivate());
|
||||
}
|
||||
|
||||
ObjectId
|
||||
JavaScriptParent::idOf(JSObject *obj)
|
||||
{
|
||||
MOZ_ASSERT(JavaScriptParent::IsCPOW(obj));
|
||||
|
||||
Value v = GetProxyExtra(obj, 1);
|
||||
MOZ_ASSERT(v.isDouble());
|
||||
|
||||
ObjectId objId = BitwiseCast<uint64_t>(v.toDouble());
|
||||
MOZ_ASSERT(findObject(objId) == obj);
|
||||
MOZ_ASSERT(objId);
|
||||
|
||||
return objId;
|
||||
}
|
||||
|
||||
int sCPOWProxyHandler;
|
||||
|
||||
class CPOWProxyHandler : public BaseProxyHandler
|
||||
{
|
||||
public:
|
||||
CPOWProxyHandler()
|
||||
: BaseProxyHandler(&sCPOWProxyHandler) {}
|
||||
virtual ~CPOWProxyHandler() {}
|
||||
|
||||
virtual bool finalizeInBackground(Value priv) MOZ_OVERRIDE {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
|
||||
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy,
|
||||
HandleId id, PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
|
||||
virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
PropertyDescriptor *desc) MOZ_OVERRIDE;
|
||||
virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy,
|
||||
AutoIdVector &props) MOZ_OVERRIDE;
|
||||
virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
|
||||
virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
|
||||
virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
|
||||
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
|
||||
HandleId id, MutableHandleValue vp) MOZ_OVERRIDE;
|
||||
virtual bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
|
||||
JS::HandleId id, bool strict, JS::MutableHandleValue vp) MOZ_OVERRIDE;
|
||||
virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) MOZ_OVERRIDE;
|
||||
virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
|
||||
MutableHandleValue vp) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
|
||||
virtual void finalize(JSFreeOp *fop, JSObject *proxy) MOZ_OVERRIDE;
|
||||
virtual bool objectClassIs(HandleObject obj, js::ESClassValue classValue, JSContext *cx) MOZ_OVERRIDE;
|
||||
virtual const char* className(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
|
||||
virtual bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
|
||||
virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) MOZ_OVERRIDE;
|
||||
|
||||
static CPOWProxyHandler singleton;
|
||||
};
|
||||
|
||||
CPOWProxyHandler CPOWProxyHandler::singleton;
|
||||
|
||||
bool
|
||||
CPOWProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
PropertyDescriptor *desc, unsigned flags)
|
||||
{
|
||||
return ParentOf(proxy)->getPropertyDescriptor(cx, proxy, id, desc, flags);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptParent::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
PropertyDescriptor *desc, unsigned flags)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
|
||||
nsString idstr;
|
||||
if (!convertIdToGeckoString(cx, id, &idstr))
|
||||
return false;
|
||||
|
||||
ReturnStatus status;
|
||||
PPropertyDescriptor result;
|
||||
if (!CallGetPropertyDescriptor(objId, idstr, flags, &status, &result))
|
||||
return ipcfail(cx);
|
||||
if (!ok(cx, status))
|
||||
return false;
|
||||
|
||||
return toDescriptor(cx, result, desc);
|
||||
}
|
||||
|
||||
bool
|
||||
CPOWProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy,
|
||||
HandleId id, PropertyDescriptor *desc, unsigned flags)
|
||||
{
|
||||
return ParentOf(proxy)->getOwnPropertyDescriptor(cx, proxy, id, desc, flags);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptParent::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
PropertyDescriptor *desc, unsigned flags)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
|
||||
nsString idstr;
|
||||
if (!convertIdToGeckoString(cx, id, &idstr))
|
||||
return false;
|
||||
|
||||
ReturnStatus status;
|
||||
PPropertyDescriptor result;
|
||||
if (!CallGetOwnPropertyDescriptor(objId, idstr, flags, &status, &result))
|
||||
return ipcfail(cx);
|
||||
if (!ok(cx, status))
|
||||
return false;
|
||||
|
||||
return toDescriptor(cx, result, desc);
|
||||
}
|
||||
|
||||
bool
|
||||
CPOWProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
PropertyDescriptor *desc)
|
||||
{
|
||||
MOZ_CRASH("unimplemented");
|
||||
}
|
||||
|
||||
bool
|
||||
CPOWProxyHandler::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props)
|
||||
{
|
||||
return ParentOf(proxy)->getOwnPropertyNames(cx, proxy, props);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptParent::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
|
||||
ReturnStatus status;
|
||||
InfallibleTArray<nsString> names;
|
||||
if (!CallGetOwnPropertyNames(objId, &status, &names))
|
||||
return ipcfail(cx);
|
||||
if (!ok(cx, status))
|
||||
return false;
|
||||
|
||||
RootedId name(cx);
|
||||
for (size_t i = 0; i < names.Length(); i++) {
|
||||
if (!convertGeckoStringToId(cx, names[i], &name))
|
||||
return false;
|
||||
if (!props.append(name))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CPOWProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
|
||||
{
|
||||
return ParentOf(proxy)->keys(cx, proxy, props);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptParent::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
|
||||
ReturnStatus status;
|
||||
InfallibleTArray<nsString> names;
|
||||
if (!CallKeys(objId, &status, &names))
|
||||
return ipcfail(cx);
|
||||
if (!ok(cx, status))
|
||||
return false;
|
||||
|
||||
RootedId name(cx);
|
||||
for (size_t i = 0; i < names.Length(); i++) {
|
||||
if (!convertGeckoStringToId(cx, names[i], &name))
|
||||
return false;
|
||||
if (!props.append(name))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CPOWProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
|
||||
{
|
||||
MOZ_CRASH("unimplemented");
|
||||
}
|
||||
|
||||
bool
|
||||
CPOWProxyHandler::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
|
||||
{
|
||||
MOZ_CRASH("unimplemented");
|
||||
}
|
||||
|
||||
bool
|
||||
CPOWProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy)
|
||||
{
|
||||
return ParentOf(proxy)->preventExtensions(cx, proxy);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptParent::preventExtensions(JSContext *cx, HandleObject proxy)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
|
||||
ReturnStatus status;
|
||||
if (!CallPreventExtensions(objId, &status))
|
||||
return ipcfail(cx);
|
||||
|
||||
return ok(cx, status);
|
||||
}
|
||||
|
||||
bool
|
||||
CPOWProxyHandler::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible)
|
||||
{
|
||||
return ParentOf(proxy)->isExtensible(cx, proxy, extensible);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptParent::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
|
||||
ReturnStatus status;
|
||||
if (!CallIsExtensible(objId, &status, extensible))
|
||||
return ipcfail(cx);
|
||||
|
||||
return ok(cx, status);
|
||||
}
|
||||
|
||||
bool
|
||||
CPOWProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
|
||||
{
|
||||
return ParentOf(proxy)->has(cx, proxy, id, bp);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptParent::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
|
||||
nsString idstr;
|
||||
if (!convertIdToGeckoString(cx, id, &idstr))
|
||||
return false;
|
||||
|
||||
ReturnStatus status;
|
||||
if (!CallHas(objId, idstr, &status, bp))
|
||||
return ipcfail(cx);
|
||||
|
||||
return ok(cx, status);
|
||||
}
|
||||
|
||||
bool
|
||||
CPOWProxyHandler::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
|
||||
{
|
||||
return ParentOf(proxy)->hasOwn(cx, proxy, id, bp);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptParent::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
|
||||
nsString idstr;
|
||||
if (!convertIdToGeckoString(cx, id, &idstr))
|
||||
return false;
|
||||
|
||||
ReturnStatus status;
|
||||
if (!CallHasOwn(objId, idstr, &status, bp))
|
||||
return ipcfail(cx);
|
||||
|
||||
return !!ok(cx, status);
|
||||
}
|
||||
|
||||
bool
|
||||
CPOWProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
|
||||
HandleId id, MutableHandleValue vp)
|
||||
{
|
||||
return ParentOf(proxy)->get(cx, proxy, receiver, id, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptParent::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
|
||||
HandleId id, MutableHandleValue vp)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
ObjectId receiverId = idOf(receiver);
|
||||
|
||||
nsString idstr;
|
||||
if (!convertIdToGeckoString(cx, id, &idstr))
|
||||
return false;
|
||||
|
||||
JSVariant val;
|
||||
ReturnStatus status;
|
||||
if (!CallGet(objId, receiverId, idstr, &status, &val))
|
||||
return ipcfail(cx);
|
||||
|
||||
if (!ok(cx, status))
|
||||
return false;
|
||||
|
||||
return toValue(cx, val, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
CPOWProxyHandler::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
|
||||
JS::HandleId id, bool strict, JS::MutableHandleValue vp)
|
||||
{
|
||||
return ParentOf(proxy)->set(cx, proxy, receiver, id, strict, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptParent::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
|
||||
JS::HandleId id, bool strict, JS::MutableHandleValue vp)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
ObjectId receiverId = idOf(receiver);
|
||||
|
||||
nsString idstr;
|
||||
if (!convertIdToGeckoString(cx, id, &idstr))
|
||||
return false;
|
||||
|
||||
JSVariant val;
|
||||
if (!toVariant(cx, vp, &val))
|
||||
return false;
|
||||
|
||||
ReturnStatus status;
|
||||
JSVariant result;
|
||||
if (!CallSet(objId, receiverId, idstr, strict, val, &status, &result))
|
||||
return ipcfail(cx);
|
||||
|
||||
if (!ok(cx, status))
|
||||
return false;
|
||||
|
||||
return toValue(cx, result, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
CPOWProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
|
||||
MutableHandleValue vp)
|
||||
{
|
||||
MOZ_CRASH("unimplemented");
|
||||
}
|
||||
|
||||
bool
|
||||
CPOWProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
|
||||
{
|
||||
return ParentOf(proxy)->call(cx, proxy, args);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptParent::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
|
||||
InfallibleTArray<JSParam> vals;
|
||||
AutoValueVector outobjects(cx);
|
||||
|
||||
RootedValue v(cx);
|
||||
for (size_t i = 0; i < args.length() + 2; i++) {
|
||||
v = args.base()[i];
|
||||
if (v.isObject()) {
|
||||
JSObject *obj = &v.toObject();
|
||||
if (xpc::IsOutObject(cx, obj)) {
|
||||
// Make sure it is not an in-out object.
|
||||
JSBool found;
|
||||
if (!JS_HasProperty(cx, obj, "value", &found))
|
||||
return false;
|
||||
if (found) {
|
||||
JS_ReportError(cx, "in-out objects cannot be sent via CPOWs yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
vals.AppendElement(JSParam(void_t()));
|
||||
if (!outobjects.append(ObjectValue(*obj)))
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
JSVariant val;
|
||||
if (!toVariant(cx, v, &val))
|
||||
return false;
|
||||
vals.AppendElement(JSParam(val));
|
||||
}
|
||||
|
||||
JSVariant result;
|
||||
ReturnStatus status;
|
||||
InfallibleTArray<JSParam> outparams;
|
||||
if (!CallCall(objId, vals, &status, &result, &outparams))
|
||||
return ipcfail(cx);
|
||||
if (!ok(cx, status))
|
||||
return false;
|
||||
|
||||
if (outparams.Length() != outobjects.length())
|
||||
return ipcfail(cx);
|
||||
|
||||
for (size_t i = 0; i < outparams.Length(); i++) {
|
||||
// Don't bother doing anything for outparams that weren't set.
|
||||
if (outparams[i].type() == JSParam::Tvoid_t)
|
||||
continue;
|
||||
|
||||
// Take the value the child process returned, and set it on the XPC
|
||||
// object.
|
||||
if (!toValue(cx, outparams[i], &v))
|
||||
return false;
|
||||
|
||||
JSObject *obj = &outobjects[i].toObject();
|
||||
if (!JS_SetProperty(cx, obj, "value", v.address()))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!toValue(cx, result, args.rval()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CPOWProxyHandler::finalize(JSFreeOp *fop, JSObject *proxy)
|
||||
{
|
||||
ParentOf(proxy)->drop(proxy);
|
||||
}
|
||||
|
||||
void
|
||||
JavaScriptParent::drop(JSObject *obj)
|
||||
{
|
||||
if (inactive_)
|
||||
return;
|
||||
|
||||
ObjectId objId = idOf(obj);
|
||||
|
||||
objects_.remove(objId);
|
||||
if (!SendDropObject(objId))
|
||||
MOZ_CRASH();
|
||||
decref();
|
||||
}
|
||||
|
||||
bool
|
||||
CPOWProxyHandler::objectClassIs(HandleObject proxy, js::ESClassValue classValue, JSContext *cx)
|
||||
{
|
||||
return ParentOf(proxy)->objectClassIs(cx, proxy, classValue);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptParent::objectClassIs(JSContext *cx, HandleObject proxy, js::ESClassValue classValue)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
|
||||
// This function is assumed infallible, so we just return false if the IPC
|
||||
// channel fails.
|
||||
bool result;
|
||||
if (!CallObjectClassIs(objId, classValue, &result))
|
||||
return false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const char *
|
||||
CPOWProxyHandler::className(JSContext *cx, HandleObject proxy)
|
||||
{
|
||||
return ParentOf(proxy)->className(cx, proxy);
|
||||
}
|
||||
|
||||
const char *
|
||||
JavaScriptParent::className(JSContext *cx, HandleObject proxy)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
|
||||
nsString name;
|
||||
if (!CallClassName(objId, &name))
|
||||
return NULL;
|
||||
|
||||
return ToNewCString(name);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptParent::init()
|
||||
{
|
||||
if (!JavaScriptShared::init())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptParent::makeId(JSContext *cx, JSObject *obj, ObjectId *idp)
|
||||
{
|
||||
if (!IsProxy(obj) || GetProxyHandler(obj) != &CPOWProxyHandler::singleton) {
|
||||
JS_ReportError(cx, "cannot ipc non-cpow object");
|
||||
return false;
|
||||
}
|
||||
|
||||
*idp = idOf(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
JavaScriptParent::unwrap(JSContext *cx, ObjectId objId)
|
||||
{
|
||||
if (JSObject *obj = findObject(objId)) {
|
||||
if (!JS_WrapObject(cx, &obj))
|
||||
return NULL;
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (objId > MAX_CPOW_IDS) {
|
||||
JS_ReportError(cx, "unusable CPOW id");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool callable = !!(objId & OBJECT_IS_CALLABLE);
|
||||
|
||||
RootedValue v(cx, UndefinedValue());
|
||||
JSObject *obj = NewProxyObject(cx,
|
||||
&CPOWProxyHandler::singleton,
|
||||
v,
|
||||
NULL,
|
||||
NULL,
|
||||
callable ? ProxyIsCallable : ProxyNotCallable);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
if (!objects_.add(objId, obj))
|
||||
return NULL;
|
||||
|
||||
// Incref once we know the decref will be called.
|
||||
incref();
|
||||
|
||||
SetProxyExtra(obj, 0, PrivateValue(this));
|
||||
SetProxyExtra(obj, 1, DoubleValue(BitwiseCast<double>(objId)));
|
||||
return obj;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptParent::ipcfail(JSContext *cx)
|
||||
{
|
||||
JS_ReportError(cx, "catastrophic IPC failure");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptParent::ok(JSContext *cx, const ReturnStatus &status)
|
||||
{
|
||||
if (status.ok())
|
||||
return true;
|
||||
|
||||
RootedValue exn(cx);
|
||||
if (!toValue(cx, status.exn(), &exn))
|
||||
return false;
|
||||
|
||||
JS_SetPendingException(cx, exn);
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
JavaScriptParent::decref()
|
||||
{
|
||||
refcount_--;
|
||||
if (!refcount_)
|
||||
delete this;
|
||||
}
|
||||
|
||||
void
|
||||
JavaScriptParent::incref()
|
||||
{
|
||||
refcount_++;
|
||||
}
|
||||
|
||||
void
|
||||
JavaScriptParent::destroyFromContent()
|
||||
{
|
||||
inactive_ = true;
|
||||
decref();
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
JavaScriptParent::IsCPOW(JSObject *obj)
|
||||
{
|
||||
return IsProxy(obj) && GetProxyHandler(obj) == &CPOWProxyHandler::singleton;
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
JavaScriptParent::InstanceOf(JSObject *obj, const nsID *id, bool *bp)
|
||||
{
|
||||
return ParentOf(obj)->instanceOf(obj, id, bp);
|
||||
}
|
||||
|
||||
nsresult
|
||||
JavaScriptParent::instanceOf(JSObject *obj, const nsID *id, bool *bp)
|
||||
{
|
||||
ObjectId objId = idOf(obj);
|
||||
|
||||
JSIID iid;
|
||||
ConvertID(*id, &iid);
|
||||
|
||||
ReturnStatus status;
|
||||
if (!CallInstanceOf(objId, iid, &status, bp))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
if (!status.ok())
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
return NS_OK;
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=80:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_jsipc_JavaScriptParent__
|
||||
#define mozilla_jsipc_JavaScriptParent__
|
||||
|
||||
#include "JavaScriptShared.h"
|
||||
#include "mozilla/jsipc/PJavaScriptParent.h"
|
||||
#include "jsclass.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#undef GetClassName
|
||||
#undef GetClassInfo
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
class JavaScriptParent
|
||||
: public PJavaScriptParent,
|
||||
public JavaScriptShared
|
||||
{
|
||||
public:
|
||||
JavaScriptParent();
|
||||
|
||||
bool init();
|
||||
|
||||
public:
|
||||
bool has(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
|
||||
bool hasOwn(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
|
||||
bool get(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
|
||||
JS::HandleId id, JS::MutableHandleValue vp);
|
||||
bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
|
||||
JS::HandleId id, bool strict, JS::MutableHandleValue vp);
|
||||
bool call(JSContext *cx, JS::HandleObject proxy, const JS::CallArgs &args);
|
||||
bool getPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
|
||||
JSPropertyDescriptor *desc, unsigned flags);
|
||||
bool getOwnPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
|
||||
JSPropertyDescriptor *desc, unsigned flags);
|
||||
bool getOwnPropertyNames(JSContext *cx, JS::HandleObject proxy, js::AutoIdVector &props);
|
||||
bool keys(JSContext *cx, JS::HandleObject proxy, js::AutoIdVector &props);
|
||||
bool objectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
|
||||
const char* className(JSContext *cx, JS::HandleObject proxy);
|
||||
bool preventExtensions(JSContext *cx, JS::HandleObject proxy);
|
||||
bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible);
|
||||
|
||||
void decref();
|
||||
void incref();
|
||||
void destroyFromContent();
|
||||
|
||||
void drop(JSObject *obj);
|
||||
|
||||
static bool IsCPOW(JSObject *obj);
|
||||
static nsresult InstanceOf(JSObject *obj, const nsID *id, bool *bp);
|
||||
|
||||
nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp);
|
||||
|
||||
protected:
|
||||
JSObject *unwrap(JSContext *cx, ObjectId objId);
|
||||
|
||||
private:
|
||||
bool makeId(JSContext *cx, JSObject *obj, ObjectId *idp);
|
||||
ObjectId idOf(JSObject *obj);
|
||||
|
||||
// Catastrophic IPC failure.
|
||||
bool ipcfail(JSContext *cx);
|
||||
|
||||
// Check whether a return status is okay, and if not, propagate its error.
|
||||
bool ok(JSContext *cx, const ReturnStatus &status);
|
||||
|
||||
private:
|
||||
uintptr_t refcount_;
|
||||
bool inactive_;
|
||||
};
|
||||
|
||||
} // jsipc
|
||||
} // mozilla
|
||||
|
||||
#endif // mozilla_jsipc_JavaScriptWrapper_h__
|
||||
|
|
@ -0,0 +1,397 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=80:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "JavaScriptShared.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "xpcprivate.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace JS;
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::jsipc;
|
||||
|
||||
ObjectStore::ObjectStore()
|
||||
: table_(SystemAllocPolicy())
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectStore::init()
|
||||
{
|
||||
return table_.init(32);
|
||||
}
|
||||
|
||||
void
|
||||
ObjectStore::trace(JSTracer *trc)
|
||||
{
|
||||
for (ObjectTable::Range r(table_.all()); !r.empty(); r.popFront()) {
|
||||
JSObject *obj = r.front().value;
|
||||
JS_CallObjectTracer(trc, &obj, "ipc-object");
|
||||
MOZ_ASSERT(obj == r.front().value);
|
||||
}
|
||||
}
|
||||
|
||||
JSObject *
|
||||
ObjectStore::find(ObjectId id)
|
||||
{
|
||||
ObjectTable::Ptr p = table_.lookup(id);
|
||||
if (!p)
|
||||
return NULL;
|
||||
return p->value;
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectStore::add(ObjectId id, JSObject *obj)
|
||||
{
|
||||
return table_.put(id, obj);
|
||||
}
|
||||
|
||||
void
|
||||
ObjectStore::remove(ObjectId id)
|
||||
{
|
||||
table_.remove(id);
|
||||
}
|
||||
|
||||
ObjectIdCache::ObjectIdCache()
|
||||
: table_(SystemAllocPolicy())
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectIdCache::init()
|
||||
{
|
||||
return table_.init(32);
|
||||
}
|
||||
|
||||
void
|
||||
ObjectIdCache::trace(JSTracer *trc)
|
||||
{
|
||||
for (ObjectIdTable::Range r(table_.all()); !r.empty(); r.popFront()) {
|
||||
JSObject *obj = r.front().key;
|
||||
JS_CallObjectTracer(trc, &obj, "ipc-id");
|
||||
MOZ_ASSERT(obj == r.front().key);
|
||||
}
|
||||
}
|
||||
|
||||
ObjectId
|
||||
ObjectIdCache::find(JSObject *obj)
|
||||
{
|
||||
ObjectIdTable::Ptr p = table_.lookup(obj);
|
||||
if (!p)
|
||||
return 0;
|
||||
return p->value;
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectIdCache::add(JSObject *obj, ObjectId id)
|
||||
{
|
||||
return table_.put(obj, id);
|
||||
}
|
||||
|
||||
void
|
||||
ObjectIdCache::remove(JSObject *obj)
|
||||
{
|
||||
table_.remove(obj);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptShared::init()
|
||||
{
|
||||
if (!objects_.init())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptShared::convertIdToGeckoString(JSContext *cx, JS::HandleId id, nsString *to)
|
||||
{
|
||||
RootedValue idval(cx);
|
||||
if (!JS_IdToValue(cx, id, idval.address()))
|
||||
return false;
|
||||
|
||||
RootedString str(cx, JS_ValueToString(cx, idval));
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
const jschar *chars = JS_GetStringCharsZ(cx, str);
|
||||
if (!chars)
|
||||
return false;
|
||||
|
||||
*to = chars;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptShared::convertGeckoStringToId(JSContext *cx, const nsString &from, JS::MutableHandleId to)
|
||||
{
|
||||
RootedString str(cx, JS_NewUCStringCopyN(cx, from.BeginReading(), from.Length()));
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
return JS_ValueToId(cx, StringValue(str), to.address());
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptShared::toVariant(JSContext *cx, jsval from, JSVariant *to)
|
||||
{
|
||||
switch (JS_TypeOfValue(cx, from)) {
|
||||
case JSTYPE_VOID:
|
||||
*to = void_t();
|
||||
return true;
|
||||
|
||||
case JSTYPE_NULL:
|
||||
{
|
||||
*to = uint64_t(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
case JSTYPE_OBJECT:
|
||||
case JSTYPE_FUNCTION:
|
||||
{
|
||||
JSObject *obj = from.toObjectOrNull();
|
||||
if (!obj) {
|
||||
JS_ASSERT(from == JSVAL_NULL);
|
||||
*to = uint64_t(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (xpc_JSObjectIsID(cx, obj)) {
|
||||
JSIID iid;
|
||||
const nsID *id = xpc_JSObjectToID(cx, obj);
|
||||
ConvertID(*id, &iid);
|
||||
*to = iid;
|
||||
return true;
|
||||
}
|
||||
|
||||
ObjectId id;
|
||||
if (!makeId(cx, obj, &id))
|
||||
return false;
|
||||
*to = uint64_t(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
case JSTYPE_STRING:
|
||||
{
|
||||
nsDependentJSString dep;
|
||||
if (!dep.init(cx, from))
|
||||
return false;
|
||||
*to = dep;
|
||||
return true;
|
||||
}
|
||||
|
||||
case JSTYPE_NUMBER:
|
||||
if (JSVAL_IS_INT(from))
|
||||
*to = double(from.toInt32());
|
||||
else
|
||||
*to = from.toDouble();
|
||||
return true;
|
||||
|
||||
case JSTYPE_BOOLEAN:
|
||||
*to = from.toBoolean();
|
||||
return true;
|
||||
|
||||
default:
|
||||
MOZ_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptShared::toValue(JSContext *cx, const JSVariant &from, MutableHandleValue to)
|
||||
{
|
||||
switch (from.type()) {
|
||||
case JSVariant::Tvoid_t:
|
||||
to.set(UndefinedValue());
|
||||
return true;
|
||||
|
||||
case JSVariant::Tuint64_t:
|
||||
{
|
||||
ObjectId id = from.get_uint64_t();
|
||||
if (id) {
|
||||
JSObject *obj = unwrap(cx, id);
|
||||
if (!obj)
|
||||
return false;
|
||||
to.set(ObjectValue(*obj));
|
||||
} else {
|
||||
to.set(JSVAL_NULL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case JSVariant::Tdouble:
|
||||
to.set(JS_NumberValue(from.get_double()));
|
||||
return true;
|
||||
|
||||
case JSVariant::Tbool:
|
||||
to.set(BOOLEAN_TO_JSVAL(from.get_bool()));
|
||||
return true;
|
||||
|
||||
case JSVariant::TnsString:
|
||||
{
|
||||
const nsString &old = from.get_nsString();
|
||||
JSString *str = JS_NewUCStringCopyN(cx, old.BeginReading(), old.Length());
|
||||
if (!str)
|
||||
return false;
|
||||
to.set(StringValue(str));
|
||||
return true;
|
||||
}
|
||||
|
||||
case JSVariant::TJSIID:
|
||||
{
|
||||
nsID iid;
|
||||
const JSIID &id = from.get_JSIID();
|
||||
ConvertID(id, &iid);
|
||||
|
||||
JSCompartment *compartment = GetContextCompartment(cx);
|
||||
RootedObject global(cx, JS_GetGlobalForCompartmentOrNull(cx, compartment));
|
||||
JSObject *obj = xpc_NewIDObject(cx, global, iid);
|
||||
if (!obj)
|
||||
return false;
|
||||
to.set(ObjectValue(*obj));
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
JavaScriptShared::ConvertID(const nsID &from, JSIID *to)
|
||||
{
|
||||
to->m0() = from.m0;
|
||||
to->m1() = from.m1;
|
||||
to->m2() = from.m2;
|
||||
to->m3_0() = from.m3[0];
|
||||
to->m3_1() = from.m3[1];
|
||||
to->m3_2() = from.m3[2];
|
||||
to->m3_3() = from.m3[3];
|
||||
to->m3_4() = from.m3[4];
|
||||
to->m3_5() = from.m3[5];
|
||||
to->m3_6() = from.m3[6];
|
||||
to->m3_7() = from.m3[7];
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
JavaScriptShared::ConvertID(const JSIID &from, nsID *to)
|
||||
{
|
||||
to->m0 = from.m0();
|
||||
to->m1 = from.m1();
|
||||
to->m2 = from.m2();
|
||||
to->m3[0] = from.m3_0();
|
||||
to->m3[1] = from.m3_1();
|
||||
to->m3[2] = from.m3_2();
|
||||
to->m3[3] = from.m3_3();
|
||||
to->m3[4] = from.m3_4();
|
||||
to->m3[5] = from.m3_5();
|
||||
to->m3[6] = from.m3_6();
|
||||
to->m3[7] = from.m3_7();
|
||||
}
|
||||
|
||||
static const uint32_t DefaultPropertyOp = 1;
|
||||
static const uint32_t GetterOnlyPropertyStub = 2;
|
||||
static const uint32_t UnknownPropertyOp = 3;
|
||||
|
||||
bool
|
||||
JavaScriptShared::fromDescriptor(JSContext *cx, const JSPropertyDescriptor &desc, PPropertyDescriptor *out)
|
||||
{
|
||||
out->attrs() = desc.attrs;
|
||||
out->shortid() = desc.shortid;
|
||||
if (!toVariant(cx, desc.value, &out->value()))
|
||||
return false;
|
||||
|
||||
if (!makeId(cx, desc.obj, &out->objId()))
|
||||
return false;
|
||||
|
||||
if (!desc.getter) {
|
||||
out->getter() = 0;
|
||||
} else if (desc.attrs & JSPROP_GETTER) {
|
||||
JSObject *getter = JS_FUNC_TO_DATA_PTR(JSObject *, desc.getter);
|
||||
if (!makeId(cx, getter, &out->getter()))
|
||||
return false;
|
||||
} else {
|
||||
if (desc.getter == JS_PropertyStub)
|
||||
out->getter() = DefaultPropertyOp;
|
||||
else
|
||||
out->getter() = UnknownPropertyOp;
|
||||
}
|
||||
|
||||
if (!desc.setter) {
|
||||
out->setter() = 0;
|
||||
} else if (desc.attrs & JSPROP_SETTER) {
|
||||
JSObject *setter = JS_FUNC_TO_DATA_PTR(JSObject *, desc.setter);
|
||||
if (!makeId(cx, setter, &out->setter()))
|
||||
return false;
|
||||
} else {
|
||||
if (desc.setter == JS_StrictPropertyStub)
|
||||
out->setter() = DefaultPropertyOp;
|
||||
else if (desc.setter == js_GetterOnlyPropertyStub)
|
||||
out->setter() = GetterOnlyPropertyStub;
|
||||
else
|
||||
out->setter() = UnknownPropertyOp;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
UnknownPropertyStub(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
|
||||
{
|
||||
JS_ReportError(cx, "getter could not be wrapped via CPOWs");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
UnknownStrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, MutableHandleValue vp)
|
||||
{
|
||||
JS_ReportError(cx, "setter could not be wrapped via CPOWs");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptShared::toDescriptor(JSContext *cx, const PPropertyDescriptor &in, JSPropertyDescriptor *out)
|
||||
{
|
||||
out->attrs = in.attrs();
|
||||
out->shortid = in.shortid();
|
||||
if (!toValue(cx, in.value(), &out->value))
|
||||
return false;
|
||||
if (!unwrap(cx, in.objId(), &out->obj))
|
||||
return false;
|
||||
|
||||
if (!in.getter()) {
|
||||
out->getter = NULL;
|
||||
} else if (in.attrs() & JSPROP_GETTER) {
|
||||
JSObject *getter;
|
||||
if (!unwrap(cx, in.getter(), &getter))
|
||||
return false;
|
||||
out->getter = JS_DATA_TO_FUNC_PTR(JSPropertyOp, getter);
|
||||
} else {
|
||||
if (in.getter() == DefaultPropertyOp)
|
||||
out->getter = JS_PropertyStub;
|
||||
else
|
||||
out->getter = UnknownPropertyStub;
|
||||
}
|
||||
|
||||
if (!in.setter()) {
|
||||
out->setter = NULL;
|
||||
} else if (in.attrs() & JSPROP_SETTER) {
|
||||
JSObject *setter;
|
||||
if (!unwrap(cx, in.setter(), &setter))
|
||||
return false;
|
||||
out->setter = JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, setter);
|
||||
} else {
|
||||
if (in.setter() == DefaultPropertyOp)
|
||||
out->setter = JS_StrictPropertyStub;
|
||||
else if (in.setter() == GetterOnlyPropertyStub)
|
||||
out->setter = js_GetterOnlyPropertyStub;
|
||||
else
|
||||
out->setter = UnknownStrictPropertyStub;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=80:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_jsipc_JavaScriptShared_h__
|
||||
#define mozilla_jsipc_JavaScriptShared_h__
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jspubtd.h"
|
||||
#include "js/HashTable.h"
|
||||
#include "mozilla/dom/DOMTypes.h"
|
||||
#include "mozilla/jsipc/PJavaScript.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsFrameMessageManager.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
typedef uint64_t ObjectId;
|
||||
|
||||
// Map ids -> JSObjects
|
||||
class ObjectStore
|
||||
{
|
||||
typedef js::DefaultHasher<ObjectId> TableKeyHasher;
|
||||
|
||||
typedef js::HashMap<ObjectId, JSObject *, TableKeyHasher, js::SystemAllocPolicy> ObjectTable;
|
||||
|
||||
public:
|
||||
ObjectStore();
|
||||
|
||||
bool init();
|
||||
void trace(JSTracer *trc);
|
||||
|
||||
bool add(ObjectId id, JSObject *obj);
|
||||
JSObject *find(ObjectId id);
|
||||
void remove(ObjectId id);
|
||||
|
||||
private:
|
||||
ObjectTable table_;
|
||||
};
|
||||
|
||||
// Map JSObjects -> ids
|
||||
class ObjectIdCache
|
||||
{
|
||||
typedef js::PointerHasher<JSObject *, 3> Hasher;
|
||||
typedef js::HashMap<JSObject *, ObjectId, Hasher, js::SystemAllocPolicy> ObjectIdTable;
|
||||
|
||||
public:
|
||||
ObjectIdCache();
|
||||
|
||||
bool init();
|
||||
void trace(JSTracer *trc);
|
||||
|
||||
bool add(JSObject *, ObjectId id);
|
||||
ObjectId find(JSObject *obj);
|
||||
void remove(JSObject *obj);
|
||||
|
||||
private:
|
||||
ObjectIdTable table_;
|
||||
};
|
||||
|
||||
class JavaScriptShared
|
||||
{
|
||||
public:
|
||||
bool init();
|
||||
|
||||
static const uint32_t OBJECT_EXTRA_BITS = 1;
|
||||
static const uint32_t OBJECT_IS_CALLABLE = (1 << 0);
|
||||
|
||||
protected:
|
||||
bool toVariant(JSContext *cx, jsval from, JSVariant *to);
|
||||
bool toValue(JSContext *cx, const JSVariant &from, JS::MutableHandleValue to);
|
||||
bool fromDescriptor(JSContext *cx, const JSPropertyDescriptor &desc, PPropertyDescriptor *out);
|
||||
bool toDescriptor(JSContext *cx, const PPropertyDescriptor &in, JSPropertyDescriptor *out);
|
||||
bool convertIdToGeckoString(JSContext *cx, JS::HandleId id, nsString *to);
|
||||
bool convertGeckoStringToId(JSContext *cx, const nsString &from, JS::MutableHandleId id);
|
||||
|
||||
bool toValue(JSContext *cx, const JSVariant &from, jsval *to) {
|
||||
JS::RootedValue v(cx);
|
||||
if (!toValue(cx, from, &v))
|
||||
return false;
|
||||
*to = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool makeId(JSContext *cx, JSObject *obj, ObjectId *idp) = 0;
|
||||
virtual JSObject *unwrap(JSContext *cx, ObjectId id) = 0;
|
||||
|
||||
bool unwrap(JSContext *cx, ObjectId id, JSObject **objp) {
|
||||
if (!id) {
|
||||
*objp = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
*objp = unwrap(cx, id);
|
||||
return !!*objp;
|
||||
}
|
||||
|
||||
static void ConvertID(const nsID &from, JSIID *to);
|
||||
static void ConvertID(const JSIID &from, nsID *to);
|
||||
|
||||
JSObject *findObject(uint32_t objId) {
|
||||
return objects_.find(objId);
|
||||
}
|
||||
|
||||
protected:
|
||||
ObjectStore objects_;
|
||||
};
|
||||
|
||||
// Use 47 at most, to be safe, since jsval privates are encoded as doubles.
|
||||
static const uint64_t MAX_CPOW_IDS = (uint64_t(1) << 47) - 1;
|
||||
|
||||
} // namespace jsipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -0,0 +1,78 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=80:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include DOMTypes;
|
||||
|
||||
using mozilla::void_t;
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
struct JSIID
|
||||
{
|
||||
uint32_t m0;
|
||||
uint16_t m1;
|
||||
uint16_t m2;
|
||||
uint8_t m3_0;
|
||||
uint8_t m3_1;
|
||||
uint8_t m3_2;
|
||||
uint8_t m3_3;
|
||||
uint8_t m3_4;
|
||||
uint8_t m3_5;
|
||||
uint8_t m3_6;
|
||||
uint8_t m3_7;
|
||||
};
|
||||
|
||||
union JSVariant
|
||||
{
|
||||
void_t; /* |undefined| */
|
||||
nsString; /* StringValue(x) */
|
||||
uint64_t; /* ID that maps to a JSObject (cpow on parent, original on child). */
|
||||
double; /* NumberValue(x) */
|
||||
bool; /* BooleanValue(x) */
|
||||
JSIID; /* XPC nsIID */
|
||||
};
|
||||
|
||||
struct ReturnStatus
|
||||
{
|
||||
bool ok; /* True for success, false for failure. */
|
||||
JSVariant exn; /* Exception, if |ok| is false. */
|
||||
};
|
||||
|
||||
union JSParam
|
||||
{
|
||||
void_t; /* value is strictly an xpc out param */
|
||||
JSVariant; /* actual value to pass through */
|
||||
};
|
||||
|
||||
struct PPropertyDescriptor
|
||||
{
|
||||
uint64_t objId;
|
||||
uint32_t attrs;
|
||||
uint32_t shortid;
|
||||
JSVariant value;
|
||||
|
||||
// How to interpret these values depends on whether JSPROP_GETTER/SETTER
|
||||
// are set. If set, the corresponding value is a CPOW or 0 for NULL.
|
||||
// Otherwise, the following table is used:
|
||||
//
|
||||
// 0 - NULL
|
||||
// 1 - Default getter or setter.
|
||||
// 2 - js_GetterOnlyPropertyStub (setter only)
|
||||
// 3 - Unknown
|
||||
uint64_t getter;
|
||||
uint64_t setter;
|
||||
};
|
||||
|
||||
struct CpowEntry
|
||||
{
|
||||
nsString name;
|
||||
JSVariant value;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -15,9 +15,15 @@ FORCE_STATIC_LIB = 1
|
|||
EXPORT_LIBRARY = 1
|
||||
FAIL_ON_WARNINGS = 1
|
||||
|
||||
# For nsDependentJSString
|
||||
EXPORTS_mozilla/jsipc = \
|
||||
JavaScriptParent.h \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES += \
|
||||
-I$(topsrcdir)/dom/base \
|
||||
-I$(topsrcdir)/js/ipc \
|
||||
-I$(topsrcdir)/js/public \
|
||||
-I$(topsrcdir)/js/xpconnect/src \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
|
|
@ -1,621 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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 "mozilla/GuardObjects.h"
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
#include "mozilla/jsipc/ContextWrapperChild.h"
|
||||
#include "mozilla/jsipc/ObjectWrapperChild.h"
|
||||
#include "mozilla/jsipc/CPOWTypes.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "nsJSUtils.h"
|
||||
|
||||
using namespace mozilla::jsipc;
|
||||
using namespace js;
|
||||
|
||||
namespace {
|
||||
|
||||
class MOZ_STACK_CLASS AutoContextPusher {
|
||||
|
||||
nsCxPusher mStack;
|
||||
JSContext* const mContext;
|
||||
const uint32_t mSavedOptions;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
||||
public:
|
||||
|
||||
AutoContextPusher(JSContext* cx
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: mContext(cx)
|
||||
, mSavedOptions(JS_SetOptions(cx, (JS_GetOptions(cx) |
|
||||
JSOPTION_DONT_REPORT_UNCAUGHT)))
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
mStack.Push(cx);
|
||||
}
|
||||
|
||||
~AutoContextPusher() {
|
||||
mStack.Pop();
|
||||
JS_SetOptions(mContext, mSavedOptions);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class StatusPtrOwner
|
||||
{
|
||||
OperationStatus* mStatusPtr;
|
||||
public:
|
||||
StatusPtrOwner() : mStatusPtr(NULL) {}
|
||||
void SetStatusPtr(OperationStatus* statusPtr) {
|
||||
mStatusPtr = statusPtr;
|
||||
// By default, initialize mStatusPtr to failure without an
|
||||
// exception. Doing so only when the union is uninitialized
|
||||
// allows AutoCheckOperation classes to be nested on the
|
||||
// stack, just in case AnswerConstruct, for example, calls
|
||||
// AnswerCall (as it once did, before there were unrelated
|
||||
// problems with that approach).
|
||||
if (mStatusPtr->type() == OperationStatus::T__None)
|
||||
*mStatusPtr = JS_FALSE;
|
||||
}
|
||||
OperationStatus* StatusPtr() {
|
||||
NS_ASSERTION(mStatusPtr, "Should have called SetStatusPtr by now.");
|
||||
return mStatusPtr;
|
||||
}
|
||||
};
|
||||
|
||||
typedef AutoCheckOperationBase<StatusPtrOwner> ACOBase;
|
||||
|
||||
class AutoCheckOperation : public ACOBase
|
||||
{
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
public:
|
||||
AutoCheckOperation(ObjectWrapperChild* owc,
|
||||
OperationStatus* statusPtr
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: ACOBase(NULL, owc)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
SetStatusPtr(statusPtr);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
ObjectWrapperChild::CheckOperation(JSContext*,
|
||||
OperationStatus* status)
|
||||
{
|
||||
NS_PRECONDITION(status->type() != OperationStatus::T__None,
|
||||
"Checking an uninitialized operation.");
|
||||
|
||||
JSContext* cx = Manager()->GetContext();
|
||||
jsval thrown;
|
||||
|
||||
if (JS_GetPendingException(cx, &thrown)) {
|
||||
NS_ASSERTION(!(status->type() == OperationStatus::TJSBool &&
|
||||
status->get_JSBool()),
|
||||
"Operation succeeded but exception was thrown?");
|
||||
JSVariant exception;
|
||||
if (!jsval_to_JSVariant(cx, thrown, &exception))
|
||||
exception = void_t(); // XXX Useful?
|
||||
*status = exception;
|
||||
JS_ClearPendingException(cx);
|
||||
}
|
||||
}
|
||||
|
||||
ObjectWrapperChild::ObjectWrapperChild(JSContext* cx, JSObject* obj)
|
||||
: mObj(obj)
|
||||
{
|
||||
AutoContextPusher acp(cx);
|
||||
#ifdef DEBUG
|
||||
bool added =
|
||||
#endif
|
||||
JS_AddObjectRoot(cx, &mObj);
|
||||
NS_ASSERTION(added, "ObjectWrapperChild constructor failed to root JSObject*");
|
||||
}
|
||||
|
||||
void
|
||||
ObjectWrapperChild::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
JSContext* cx = Manager()->GetContext();
|
||||
AutoContextPusher acp(cx);
|
||||
JS_RemoveObjectRoot(cx, &mObj);
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectWrapperChild::JSObject_to_JSVariant(JSContext* cx, JSObject* from,
|
||||
JSVariant* to)
|
||||
{
|
||||
*to = Manager()->GetOrCreateWrapper(from);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectWrapperChild::jsval_to_JSVariant(JSContext* cx, jsval from, JSVariant* to)
|
||||
{
|
||||
switch (JS_TypeOfValue(cx, from)) {
|
||||
case JSTYPE_VOID:
|
||||
*to = void_t();
|
||||
return true;
|
||||
case JSTYPE_NULL:
|
||||
if (from != JSVAL_NULL)
|
||||
return false;
|
||||
// fall through
|
||||
case JSTYPE_FUNCTION:
|
||||
// fall through
|
||||
case JSTYPE_OBJECT:
|
||||
return JSObject_to_JSVariant(cx, JSVAL_TO_OBJECT(from), to);
|
||||
case JSTYPE_STRING:
|
||||
{
|
||||
nsDependentJSString depStr;
|
||||
if (!depStr.init(cx, from))
|
||||
return false;
|
||||
*to = depStr;
|
||||
}
|
||||
return true;
|
||||
case JSTYPE_NUMBER:
|
||||
if (JSVAL_IS_INT(from))
|
||||
*to = JSVAL_TO_INT(from);
|
||||
else if (JSVAL_IS_DOUBLE(from))
|
||||
*to = JSVAL_TO_DOUBLE(from);
|
||||
else return false;
|
||||
return true;
|
||||
case JSTYPE_BOOLEAN:
|
||||
*to = !!JSVAL_TO_BOOLEAN(from);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/ bool
|
||||
ObjectWrapperChild::
|
||||
JSObject_from_PObjectWrapperChild(JSContext*,
|
||||
const PObjectWrapperChild* from,
|
||||
JSObject** to)
|
||||
{
|
||||
const ObjectWrapperChild* owc =
|
||||
static_cast<const ObjectWrapperChild*>(from);
|
||||
*to = owc ? owc->mObj : NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*static*/ bool
|
||||
ObjectWrapperChild::JSObject_from_JSVariant(JSContext* cx,
|
||||
const JSVariant& from,
|
||||
JSObject** to)
|
||||
{
|
||||
if (from.type() != JSVariant::TPObjectWrapperChild)
|
||||
return false;
|
||||
return JSObject_from_PObjectWrapperChild(cx,
|
||||
from.get_PObjectWrapperChild(),
|
||||
to);
|
||||
}
|
||||
|
||||
/*static*/ bool
|
||||
ObjectWrapperChild::jsval_from_JSVariant(JSContext* cx, const JSVariant& from,
|
||||
jsval* to)
|
||||
{
|
||||
switch (from.type()) {
|
||||
case JSVariant::Tvoid_t:
|
||||
*to = JSVAL_VOID;
|
||||
return true;
|
||||
case JSVariant::TPObjectWrapperChild:
|
||||
{
|
||||
JSObject* obj;
|
||||
if (!JSObject_from_JSVariant(cx, from, &obj))
|
||||
return false;
|
||||
*to = OBJECT_TO_JSVAL(obj);
|
||||
return true;
|
||||
}
|
||||
case JSVariant::TnsString:
|
||||
{
|
||||
const nsString& str = from.get_nsString();
|
||||
JSString* s = JS_NewUCStringCopyN(cx,
|
||||
str.BeginReading(),
|
||||
str.Length());
|
||||
if (!s)
|
||||
return false;
|
||||
*to = STRING_TO_JSVAL(s);
|
||||
}
|
||||
return true;
|
||||
case JSVariant::Tint:
|
||||
*to = INT_TO_JSVAL(from.get_int());
|
||||
return true;
|
||||
case JSVariant::Tdouble:
|
||||
*to = JS_NumberValue(from.get_double());
|
||||
return true;
|
||||
case JSVariant::Tbool:
|
||||
*to = BOOLEAN_TO_JSVAL(from.get_bool());
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ContextWrapperChild*
|
||||
ObjectWrapperChild::Manager()
|
||||
{
|
||||
PContextWrapperChild* pcwc = PObjectWrapperChild::Manager();
|
||||
return static_cast<ContextWrapperChild*>(pcwc);
|
||||
}
|
||||
|
||||
static bool
|
||||
jsid_to_nsString(JSContext* cx, jsid from, nsString* to)
|
||||
{
|
||||
if (JSID_IS_STRING(from)) {
|
||||
size_t length;
|
||||
const jschar* chars = JS_GetInternedStringCharsAndLength(JSID_TO_STRING(from), &length);
|
||||
*to = nsDependentString(chars, length);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
jsid_from_nsString(JSContext* cx, const nsString& from, jsid* to)
|
||||
{
|
||||
JSString* str = JS_NewUCStringCopyN(cx, from.BeginReading(), from.Length());
|
||||
if (!str)
|
||||
return false;
|
||||
return JS_ValueToId(cx, STRING_TO_JSVAL(str), to);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// The general schema for ObjectWrapperChild::Answer* methods:
|
||||
bool
|
||||
ObjectWrapperChild::AnswerSomething(/* in-parameters */
|
||||
/* out-parameters */)
|
||||
{
|
||||
// initialize out-parameters for failure
|
||||
JSContext* cx = Manager()->GetContext();
|
||||
AutoContextPusher acp(cx);
|
||||
// validate in-parameters, else return false
|
||||
// successfully perform local JS operations, else return true
|
||||
// perform out-parameter conversions, else return false
|
||||
return true;
|
||||
}
|
||||
// There's an important subtlety here: though a local JS operation may
|
||||
// fail, leaving out-parameters uninitialized, we must initialize all
|
||||
// out-parameters when reporting success (returning true) to the IPC
|
||||
// messaging system. See AnswerGetProperty for illustration.
|
||||
#endif
|
||||
|
||||
bool
|
||||
ObjectWrapperChild::AnswerAddProperty(const nsString& id,
|
||||
OperationStatus* status)
|
||||
{
|
||||
JSContext* cx = Manager()->GetContext();
|
||||
JS::RootedId interned_id(cx);
|
||||
AutoContextPusher acp(cx);
|
||||
AutoCheckOperation aco(this, status);
|
||||
|
||||
if (!jsid_from_nsString(cx, id, interned_id.address()))
|
||||
return false;
|
||||
|
||||
*status = JS_DefinePropertyById(cx, mObj, interned_id, JSVAL_VOID,
|
||||
NULL, NULL, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectWrapperChild::AnswerGetProperty(const nsString& id,
|
||||
OperationStatus* status, JSVariant* vp)
|
||||
{
|
||||
JSContext* cx = Manager()->GetContext();
|
||||
JS::RootedId interned_id(cx);
|
||||
JS::RootedValue val(cx);
|
||||
AutoContextPusher acp(cx);
|
||||
AutoCheckOperation aco(this, status);
|
||||
|
||||
if (!jsid_from_nsString(cx, id, interned_id.address()))
|
||||
return false;
|
||||
|
||||
*status = JS_GetPropertyById(cx, mObj, interned_id, val.address());
|
||||
|
||||
// Since we fully expect this call to jsval_to_JSVariant to return
|
||||
// true, we can't just leave vp uninitialized when JS_GetPropertyById
|
||||
// returns JS_FALSE. This pitfall could be avoided in general if IPDL
|
||||
// ensured that outparams were pre-initialized to some default value
|
||||
// (XXXfixme cjones?).
|
||||
return jsval_to_JSVariant(cx, aco.Ok() ? val : JSVAL_VOID, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectWrapperChild::AnswerSetProperty(const nsString& id, const JSVariant& v,
|
||||
OperationStatus* status, JSVariant* vp)
|
||||
{
|
||||
*vp = v;
|
||||
|
||||
JSContext* cx = Manager()->GetContext();
|
||||
JS::RootedId interned_id(cx);
|
||||
JS::RootedValue val(cx);
|
||||
AutoContextPusher acp(cx);
|
||||
AutoCheckOperation aco(this, status);
|
||||
|
||||
if (!jsid_from_nsString(cx, id, interned_id.address()) ||
|
||||
!jsval_from_JSVariant(cx, v, val.address())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*status = JS_SetPropertyById(cx, mObj, interned_id, val.address());
|
||||
|
||||
return jsval_to_JSVariant(cx, aco.Ok() ? val : JSVAL_VOID, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectWrapperChild::AnswerDelProperty(const nsString& id,
|
||||
OperationStatus* status, JSVariant* vp)
|
||||
{
|
||||
JSContext* cx = Manager()->GetContext();
|
||||
JS::RootedId interned_id(cx);
|
||||
JS::RootedValue val(cx);
|
||||
AutoContextPusher acp(cx);
|
||||
AutoCheckOperation aco(this, status);
|
||||
|
||||
if (!jsid_from_nsString(cx, id, interned_id.address()))
|
||||
return false;
|
||||
|
||||
*status = JS_DeletePropertyById2(cx, mObj, interned_id, val.address());
|
||||
|
||||
return jsval_to_JSVariant(cx, aco.Ok() ? val : JSVAL_VOID, vp);
|
||||
}
|
||||
|
||||
static const uint32_t sNextIdIndexSlot = 0;
|
||||
static const uint32_t sNumNewEnumerateStateSlots = 1;
|
||||
|
||||
static void
|
||||
CPOW_NewEnumerateState_FreeIds(JSObject* state)
|
||||
{
|
||||
nsTArray<nsString>* strIds =
|
||||
static_cast<nsTArray<nsString>*>(JS_GetPrivate(state));
|
||||
|
||||
if (strIds) {
|
||||
delete strIds;
|
||||
JS_SetPrivate(state, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
CPOW_NewEnumerateState_Finalize(JSFreeOp* fop, JSObject* state)
|
||||
{
|
||||
CPOW_NewEnumerateState_FreeIds(state);
|
||||
}
|
||||
|
||||
// Similar to IteratorClass in XPCWrapper.cpp
|
||||
static const JSClass sCPOW_NewEnumerateState_JSClass = {
|
||||
"CPOW NewEnumerate State",
|
||||
JSCLASS_HAS_PRIVATE |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(sNumNewEnumerateStateSlots),
|
||||
JS_PropertyStub, JS_DeletePropertyStub,
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub,
|
||||
JS_ConvertStub, CPOW_NewEnumerateState_Finalize
|
||||
};
|
||||
|
||||
bool
|
||||
ObjectWrapperChild::AnswerNewEnumerateInit(/* no in-parameters */
|
||||
OperationStatus* status, JSVariant* statep, int* idp)
|
||||
{
|
||||
*idp = 0;
|
||||
|
||||
JSContext* cx = Manager()->GetContext();
|
||||
AutoContextPusher acp(cx);
|
||||
AutoCheckOperation aco(this, status);
|
||||
|
||||
JSClass* clasp = const_cast<JSClass*>(&sCPOW_NewEnumerateState_JSClass);
|
||||
JS::Rooted<JSObject*> state(cx, JS_NewObjectWithGivenProto(cx, clasp, NULL, NULL));
|
||||
if (!state)
|
||||
return false;
|
||||
|
||||
for (JS::RootedObject proto(cx, mObj); proto; ) {
|
||||
AutoIdArray ids(cx, JS_Enumerate(cx, proto));
|
||||
for (size_t i = 0; i < ids.length(); ++i)
|
||||
JS_DefinePropertyById(cx, state, ids[i], JSVAL_VOID,
|
||||
NULL, NULL, JSPROP_ENUMERATE | JSPROP_SHARED);
|
||||
|
||||
if (!JS_GetPrototype(cx, proto, proto.address()))
|
||||
return false;
|
||||
}
|
||||
|
||||
InfallibleTArray<nsString>* strIds;
|
||||
{
|
||||
AutoIdArray ids(cx, JS_Enumerate(cx, state));
|
||||
if (!ids)
|
||||
return false;
|
||||
strIds = new InfallibleTArray<nsString>(ids.length());
|
||||
for (size_t i = 0; i < ids.length(); ++i)
|
||||
if (!jsid_to_nsString(cx, ids[i], strIds->AppendElement())) {
|
||||
delete strIds;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*idp = strIds->Length();
|
||||
|
||||
JS_SetPrivate(state, strIds);
|
||||
JS_SetReservedSlot(state, sNextIdIndexSlot, JSVAL_ZERO);
|
||||
|
||||
*status = JSObject_to_JSVariant(cx, state, statep);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectWrapperChild::AnswerNewEnumerateNext(const JSVariant& in_state,
|
||||
OperationStatus* status, JSVariant* statep, nsString* idp)
|
||||
{
|
||||
JSObject* state;
|
||||
|
||||
*statep = in_state;
|
||||
idp->Truncate();
|
||||
|
||||
JSContext* cx = Manager()->GetContext();
|
||||
AutoContextPusher acp(cx);
|
||||
AutoCheckOperation aco(this, status);
|
||||
|
||||
if (!JSObject_from_JSVariant(cx, in_state, &state))
|
||||
return false;
|
||||
|
||||
InfallibleTArray<nsString>* strIds =
|
||||
static_cast<InfallibleTArray<nsString>*>(JS_GetPrivate(state));
|
||||
|
||||
if (!strIds)
|
||||
return false;
|
||||
|
||||
jsval v = JS_GetReservedSlot(state, sNextIdIndexSlot);
|
||||
|
||||
int32_t i = JSVAL_TO_INT(v);
|
||||
NS_ASSERTION(i >= 0, "Index of next jsid negative?");
|
||||
NS_ASSERTION(size_t(i) <= strIds->Length(), "Index of next jsid too large?");
|
||||
|
||||
if (size_t(i) == strIds->Length()) {
|
||||
*status = JS_TRUE;
|
||||
return JSObject_to_JSVariant(cx, NULL, statep);
|
||||
}
|
||||
|
||||
*idp = strIds->ElementAt(i);
|
||||
JS_SetReservedSlot(state, sNextIdIndexSlot, INT_TO_JSVAL(i + 1));
|
||||
*status = JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectWrapperChild::RecvNewEnumerateDestroy(const JSVariant& in_state)
|
||||
{
|
||||
JSObject* state;
|
||||
|
||||
JSContext* cx = Manager()->GetContext();
|
||||
AutoContextPusher acp(cx);
|
||||
|
||||
if (!JSObject_from_JSVariant(cx, in_state, &state))
|
||||
return false;
|
||||
|
||||
CPOW_NewEnumerateState_FreeIds(state);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectWrapperChild::AnswerNewResolve(const nsString& id, const int& flags,
|
||||
OperationStatus* status, PObjectWrapperChild** obj2)
|
||||
{
|
||||
*obj2 = NULL;
|
||||
|
||||
JSContext* cx = Manager()->GetContext();
|
||||
JS::RootedId interned_id(cx);
|
||||
AutoContextPusher acp(cx);
|
||||
AutoCheckOperation aco(this, status);
|
||||
|
||||
if (!jsid_from_nsString(cx, id, interned_id.address()))
|
||||
return false;
|
||||
|
||||
CPOW_LOG(("new-resolving \"%s\"...",
|
||||
NS_ConvertUTF16toUTF8(id).get()));
|
||||
|
||||
JS::Rooted<JSPropertyDescriptor> desc(cx);
|
||||
if (!JS_GetPropertyDescriptorById(cx, mObj, interned_id, flags, desc.address()))
|
||||
return true;
|
||||
|
||||
*status = JS_TRUE;
|
||||
|
||||
if (desc.get().obj)
|
||||
*obj2 = Manager()->GetOrCreateWrapper(desc.get().obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectWrapperChild::AnswerConvert(const JSType& type,
|
||||
OperationStatus* status, JSVariant* vp)
|
||||
{
|
||||
JSContext* cx = Manager()->GetContext();
|
||||
JS::RootedValue v(cx);
|
||||
AutoContextPusher acp(cx);
|
||||
AutoCheckOperation aco(this, status);
|
||||
*status = JS_ConvertValue(cx, OBJECT_TO_JSVAL(mObj), type, v.address());
|
||||
return jsval_to_JSVariant(cx, aco.Ok() ? v : JSVAL_VOID, vp);
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Should be an overestimate of typical JS function arity.
|
||||
typedef nsAutoTArray<jsval, 5> AutoJSArgs;
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectWrapperChild::AnswerCall(PObjectWrapperChild* receiver, const InfallibleTArray<JSVariant>& argv,
|
||||
OperationStatus* status, JSVariant* rval)
|
||||
{
|
||||
JSContext* cx = Manager()->GetContext();
|
||||
AutoContextPusher acp(cx);
|
||||
AutoCheckOperation aco(this, status);
|
||||
|
||||
JS::RootedObject obj(cx);
|
||||
if (!JSObject_from_PObjectWrapperChild(cx, receiver, obj.address()))
|
||||
return false;
|
||||
|
||||
AutoJSArgs args;
|
||||
uint32_t argc = argv.Length();
|
||||
jsval *jsargs = args.AppendElements(argc);
|
||||
if (!jsargs)
|
||||
return false;
|
||||
AutoArrayRooter tvr(cx, argc, jsargs);
|
||||
|
||||
for (uint32_t i = 0; i < argc; ++i)
|
||||
if (!jsval_from_JSVariant(cx, argv.ElementAt(i), jsargs + i))
|
||||
return false;
|
||||
|
||||
JS::RootedValue rv(cx);
|
||||
*status = JS_CallFunctionValue(cx, obj, OBJECT_TO_JSVAL(mObj),
|
||||
argv.Length(), jsargs, rv.address());
|
||||
|
||||
return jsval_to_JSVariant(cx, aco.Ok() ? rv : JSVAL_VOID, rval);
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectWrapperChild::AnswerConstruct(const InfallibleTArray<JSVariant>& argv,
|
||||
OperationStatus* status, PObjectWrapperChild** rval)
|
||||
{
|
||||
JSContext* cx = Manager()->GetContext();
|
||||
AutoContextPusher acp(cx);
|
||||
AutoCheckOperation aco(this, status);
|
||||
|
||||
AutoJSArgs args;
|
||||
uint32_t argc = argv.Length();
|
||||
jsval* jsargs = args.AppendElements(argc);
|
||||
if (!jsargs)
|
||||
return false;
|
||||
AutoArrayRooter tvr(cx, argc, jsargs);
|
||||
|
||||
for (uint32_t i = 0; i < argc; ++i)
|
||||
if (!jsval_from_JSVariant(cx, argv.ElementAt(i), jsargs + i))
|
||||
return false;
|
||||
|
||||
JSObject* obj = JS_New(cx, mObj, argc, jsargs);
|
||||
|
||||
*status = !!obj;
|
||||
*rval = Manager()->GetOrCreateWrapper(obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectWrapperChild::AnswerHasInstance(const JSVariant& v,
|
||||
OperationStatus* status, JSBool* bp)
|
||||
{
|
||||
JSContext* cx = Manager()->GetContext();
|
||||
JS::RootedValue candidate(cx);
|
||||
AutoContextPusher acp(cx);
|
||||
AutoCheckOperation aco(this, status);
|
||||
if (!jsval_from_JSVariant(cx, v, candidate.address()))
|
||||
return false;
|
||||
*status = JS_HasInstance(cx, mObj, candidate, bp);
|
||||
return true;
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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/. */
|
||||
|
||||
#ifndef mozilla_jsipc_ObjectWrapperChild_h
|
||||
#define mozilla_jsipc_ObjectWrapperChild_h
|
||||
|
||||
#include "mozilla/jsipc/PObjectWrapperChild.h"
|
||||
|
||||
// For OperationChecker and AutoCheckOperationBase.
|
||||
#include "mozilla/jsipc/ObjectWrapperParent.h"
|
||||
|
||||
using mozilla::jsipc::JSVariant;
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
class ContextWrapperChild;
|
||||
|
||||
class ObjectWrapperChild
|
||||
: public PObjectWrapperChild
|
||||
, public OperationChecker
|
||||
{
|
||||
public:
|
||||
|
||||
ObjectWrapperChild(JSContext* cx, JSObject* obj);
|
||||
|
||||
JSObject* GetJSObject() const { return mObj; }
|
||||
|
||||
void CheckOperation(JSContext* cx, OperationStatus* status);
|
||||
|
||||
private:
|
||||
|
||||
JSObject* mObj;
|
||||
|
||||
bool JSObject_to_JSVariant(JSContext* cx, JSObject* from, JSVariant* to);
|
||||
bool jsval_to_JSVariant(JSContext* cx, jsval from, JSVariant* to);
|
||||
|
||||
static bool JSObject_from_PObjectWrapperChild(JSContext* cx,
|
||||
const PObjectWrapperChild* from,
|
||||
JSObject** to);
|
||||
static bool JSObject_from_JSVariant(JSContext* cx, const JSVariant& from,
|
||||
JSObject** to);
|
||||
static bool jsval_from_JSVariant(JSContext* cx, const JSVariant& from,
|
||||
jsval* to);
|
||||
|
||||
ContextWrapperChild* Manager();
|
||||
|
||||
protected:
|
||||
|
||||
void ActorDestroy(ActorDestroyReason why);
|
||||
|
||||
bool AnswerAddProperty(const nsString& id,
|
||||
OperationStatus* status);
|
||||
|
||||
bool AnswerGetProperty(const nsString& id,
|
||||
OperationStatus* status, JSVariant* vp);
|
||||
|
||||
bool AnswerSetProperty(const nsString& id, const JSVariant& v,
|
||||
OperationStatus* status, JSVariant* vp);
|
||||
|
||||
bool AnswerDelProperty(const nsString& id,
|
||||
OperationStatus* status, JSVariant* vp);
|
||||
|
||||
bool AnswerNewEnumerateInit(/* no in-parameters */
|
||||
OperationStatus* status, JSVariant* statep, int* idp);
|
||||
|
||||
bool AnswerNewEnumerateNext(const JSVariant& in_state,
|
||||
OperationStatus* status, JSVariant* statep, nsString* idp);
|
||||
|
||||
bool RecvNewEnumerateDestroy(const JSVariant& in_state);
|
||||
|
||||
bool AnswerNewResolve(const nsString& id, const int& flags,
|
||||
OperationStatus* status, PObjectWrapperChild** obj2);
|
||||
|
||||
bool AnswerConvert(const JSType& type,
|
||||
OperationStatus* status, JSVariant* vp);
|
||||
|
||||
bool AnswerCall(PObjectWrapperChild* receiver, const InfallibleTArray<JSVariant>& argv,
|
||||
OperationStatus* status, JSVariant* rval);
|
||||
|
||||
bool AnswerConstruct(const InfallibleTArray<JSVariant>& argv,
|
||||
OperationStatus* status, PObjectWrapperChild** rval);
|
||||
|
||||
bool AnswerHasInstance(const JSVariant& v,
|
||||
OperationStatus* status, JSBool* bp);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* mozilla_jsipc_ObjectWrapperChild_h */
|
|
@ -1,733 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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 "mozilla/GuardObjects.h"
|
||||
|
||||
#include "mozilla/jsipc/ObjectWrapperParent.h"
|
||||
#include "mozilla/jsipc/ContextWrapperParent.h"
|
||||
#include "mozilla/jsipc/CPOWTypes.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsJSUtils.h"
|
||||
|
||||
#include "jsutil.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
using namespace mozilla::jsipc;
|
||||
using namespace JS;
|
||||
|
||||
namespace {
|
||||
|
||||
// Only need one reserved slot because the ObjectWrapperParent* is
|
||||
// stored in the private slot.
|
||||
static const unsigned sFlagsSlot = 0;
|
||||
static const unsigned sNumSlots = 1;
|
||||
static const unsigned CPOW_FLAG_RESOLVING = 1 << 0;
|
||||
|
||||
class AutoResolveFlag
|
||||
{
|
||||
Rooted<JSObject*> mObj;
|
||||
unsigned mOldFlags;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
||||
static unsigned GetFlags(JSObject* obj) {
|
||||
jsval v = JS_GetReservedSlot(obj, sFlagsSlot);
|
||||
return JSVAL_TO_INT(v);
|
||||
}
|
||||
|
||||
static unsigned SetFlags(JSObject* obj, unsigned flags) {
|
||||
unsigned oldFlags = GetFlags(obj);
|
||||
if (oldFlags != flags)
|
||||
JS_SetReservedSlot(obj, sFlagsSlot, INT_TO_JSVAL(flags));
|
||||
return oldFlags;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
AutoResolveFlag(JSContext *cx, JSObject* obj
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: mObj(cx, obj)
|
||||
, mOldFlags(SetFlags(obj, GetFlags(obj) | CPOW_FLAG_RESOLVING))
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
~AutoResolveFlag() {
|
||||
SetFlags(mObj, mOldFlags);
|
||||
}
|
||||
|
||||
static JSBool IsSet(JSObject* obj) {
|
||||
return GetFlags(obj) & CPOW_FLAG_RESOLVING;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class StatusMemberOwner
|
||||
{
|
||||
OperationStatus mStatus;
|
||||
public:
|
||||
StatusMemberOwner() : mStatus(JS_FALSE) {}
|
||||
OperationStatus* StatusPtr() {
|
||||
return &mStatus;
|
||||
}
|
||||
};
|
||||
|
||||
typedef AutoCheckOperationBase<StatusMemberOwner> ACOBase;
|
||||
|
||||
class AutoCheckOperation : public ACOBase
|
||||
{
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
public:
|
||||
AutoCheckOperation(JSContext* cx,
|
||||
ObjectWrapperParent* owp
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: ACOBase(cx, owp)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
ObjectWrapperParent::CheckOperation(JSContext* cx,
|
||||
OperationStatus* status)
|
||||
{
|
||||
NS_PRECONDITION(status->type() != OperationStatus::T__None,
|
||||
"Checking an uninitialized operation.");
|
||||
|
||||
switch (status->type()) {
|
||||
case OperationStatus::TJSVariant:
|
||||
{
|
||||
Rooted<Value> thrown(cx);
|
||||
if (jsval_from_JSVariant(cx, status->get_JSVariant(), thrown.address()))
|
||||
JS_SetPendingException(cx, thrown);
|
||||
*status = JS_FALSE;
|
||||
}
|
||||
break;
|
||||
case OperationStatus::TJSBool:
|
||||
if (!status->get_JSBool() && !JS_IsExceptionPending(cx)) {
|
||||
NS_WARNING("CPOW operation failed without setting an exception.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("Invalid or uninitialized OperationStatus type.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename RType>
|
||||
static RType
|
||||
with_error(JSContext* cx,
|
||||
RType rval,
|
||||
const char* error = NULL)
|
||||
{
|
||||
if (!JS_IsExceptionPending(cx))
|
||||
JS_ReportError(cx, error ? error : "Unspecified CPOW error");
|
||||
return rval;
|
||||
}
|
||||
|
||||
const js::Class ObjectWrapperParent::sCPOW_JSClass = {
|
||||
"CrossProcessObjectWrapper",
|
||||
JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE |
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(sNumSlots),
|
||||
ObjectWrapperParent::CPOW_AddProperty,
|
||||
ObjectWrapperParent::CPOW_DelProperty,
|
||||
ObjectWrapperParent::CPOW_GetProperty,
|
||||
ObjectWrapperParent::CPOW_SetProperty,
|
||||
(JSEnumerateOp) ObjectWrapperParent::CPOW_NewEnumerate,
|
||||
(JSResolveOp) ObjectWrapperParent::CPOW_NewResolve,
|
||||
ObjectWrapperParent::CPOW_Convert,
|
||||
ObjectWrapperParent::CPOW_Finalize,
|
||||
nullptr, // checkAccess
|
||||
ObjectWrapperParent::CPOW_Call,
|
||||
ObjectWrapperParent::CPOW_HasInstance,
|
||||
ObjectWrapperParent::CPOW_Construct,
|
||||
nullptr // trace
|
||||
};
|
||||
|
||||
void
|
||||
ObjectWrapperParent::ActorDestroy(ActorDestroyReason)
|
||||
{
|
||||
if (mObj) {
|
||||
JS_SetPrivate(mObj, NULL);
|
||||
mObj = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ContextWrapperParent*
|
||||
ObjectWrapperParent::Manager()
|
||||
{
|
||||
PContextWrapperParent* pcwp = PObjectWrapperParent::Manager();
|
||||
return static_cast<ContextWrapperParent*>(pcwp);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
ObjectWrapperParent::GetJSObject(JSContext* cx) const
|
||||
{
|
||||
if (!mObj) {
|
||||
js::Class *clasp = const_cast<js::Class *>(&ObjectWrapperParent::sCPOW_JSClass);
|
||||
mObj = JS_NewObject(cx, js::Jsvalify(clasp), NULL, NULL);
|
||||
if (mObj) {
|
||||
JS_SetPrivate(mObj, (void*)this);
|
||||
JS_SetReservedSlot(mObj, sFlagsSlot, JSVAL_ZERO);
|
||||
}
|
||||
}
|
||||
return mObj;
|
||||
}
|
||||
|
||||
static ObjectWrapperParent*
|
||||
Unwrap(JSContext* cx, JSObject* objArg)
|
||||
{
|
||||
Rooted<JSObject*> obj(cx, objArg), proto(cx);
|
||||
while (js::GetObjectClass(obj) != &ObjectWrapperParent::sCPOW_JSClass) {
|
||||
if (!js::GetObjectProto(cx, obj, &proto) || !proto)
|
||||
return NULL;
|
||||
obj = proto;
|
||||
}
|
||||
|
||||
ObjectWrapperParent* self =
|
||||
static_cast<ObjectWrapperParent*>(JS_GetPrivate(obj));
|
||||
|
||||
NS_ASSERTION(!self || self->GetJSObjectOrNull() == obj,
|
||||
"Wrapper and wrapped object disagree?");
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*static*/ bool
|
||||
ObjectWrapperParent::jsval_to_JSVariant(JSContext* cx, jsval from,
|
||||
JSVariant* to)
|
||||
{
|
||||
switch (JS_TypeOfValue(cx, from)) {
|
||||
case JSTYPE_VOID:
|
||||
*to = void_t();
|
||||
return true;
|
||||
case JSTYPE_NULL:
|
||||
if (from != JSVAL_NULL)
|
||||
return false;
|
||||
// fall through
|
||||
case JSTYPE_FUNCTION:
|
||||
// CPOWs can fool JS_TypeOfValue into returning JSTYPE_FUNCTION
|
||||
// because they have a call hook, but CPOWs are really objects, so
|
||||
// fall through to the JSTYPE_OBJECT case:
|
||||
case JSTYPE_OBJECT:
|
||||
{
|
||||
PObjectWrapperParent* powp;
|
||||
if (!JSObject_to_PObjectWrapperParent(cx, JSVAL_TO_OBJECT(from), &powp))
|
||||
return with_error(cx, false, "Cannot pass parent-created object to child");
|
||||
*to = powp;
|
||||
}
|
||||
return true;
|
||||
case JSTYPE_STRING:
|
||||
{
|
||||
nsDependentJSString depStr;
|
||||
if (!depStr.init(cx, from))
|
||||
return false;
|
||||
*to = depStr;
|
||||
}
|
||||
return true;
|
||||
case JSTYPE_NUMBER:
|
||||
if (JSVAL_IS_INT(from))
|
||||
*to = JSVAL_TO_INT(from);
|
||||
else if (JSVAL_IS_DOUBLE(from))
|
||||
*to = JSVAL_TO_DOUBLE(from);
|
||||
else return false;
|
||||
return true;
|
||||
case JSTYPE_BOOLEAN:
|
||||
*to = !!JSVAL_TO_BOOLEAN(from);
|
||||
return true;
|
||||
default:
|
||||
return with_error(cx, false, "Bad jsval type");
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/ bool
|
||||
ObjectWrapperParent::jsval_from_JSVariant(JSContext* cx, const JSVariant& from,
|
||||
jsval* to)
|
||||
{
|
||||
switch (from.type()) {
|
||||
case JSVariant::Tvoid_t:
|
||||
*to = JSVAL_VOID;
|
||||
return true;
|
||||
case JSVariant::TPObjectWrapperParent:
|
||||
return jsval_from_PObjectWrapperParent(cx, from.get_PObjectWrapperParent(), to);
|
||||
case JSVariant::TnsString:
|
||||
{
|
||||
JSString* str = JS_NewUCStringCopyZ(cx, from.get_nsString().BeginReading());
|
||||
if (!str)
|
||||
return false;
|
||||
*to = STRING_TO_JSVAL(str);
|
||||
return true;
|
||||
}
|
||||
case JSVariant::Tint:
|
||||
*to = INT_TO_JSVAL(from.get_int());
|
||||
return true;
|
||||
case JSVariant::Tdouble:
|
||||
*to = JS_NumberValue(from.get_double());
|
||||
return true;
|
||||
case JSVariant::Tbool:
|
||||
*to = BOOLEAN_TO_JSVAL(from.get_bool());
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/ bool
|
||||
ObjectWrapperParent::boolean_from_JSVariant(JSContext* cx, const JSVariant& from,
|
||||
JSBool* to)
|
||||
{
|
||||
switch (from.type()) {
|
||||
case JSVariant::Tvoid_t:
|
||||
*to = false;
|
||||
return true;
|
||||
case JSVariant::TPObjectWrapperParent: {
|
||||
Rooted<Value> v(cx);
|
||||
if (!jsval_from_PObjectWrapperParent(cx, from.get_PObjectWrapperParent(), v.address()))
|
||||
return false;
|
||||
*to = JS::ToBoolean(v);
|
||||
return true;
|
||||
}
|
||||
case JSVariant::TnsString:
|
||||
{
|
||||
JSString* str = JS_NewUCStringCopyZ(cx, from.get_nsString().BeginReading());
|
||||
if (!str)
|
||||
return false;
|
||||
*to = JS::ToBoolean(JS::StringValue(str));
|
||||
return true;
|
||||
}
|
||||
case JSVariant::Tint:
|
||||
*to = from.get_int() != 0;
|
||||
return true;
|
||||
case JSVariant::Tdouble:
|
||||
*to = JS::ToBoolean(JS::DoubleValue(from.get_double()));
|
||||
return true;
|
||||
case JSVariant::Tbool:
|
||||
*to = from.get_bool();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/ bool
|
||||
ObjectWrapperParent::
|
||||
JSObject_to_PObjectWrapperParent(JSContext* cx, JSObject* from, PObjectWrapperParent** to)
|
||||
{
|
||||
if (!from) {
|
||||
*to = NULL;
|
||||
return true;
|
||||
}
|
||||
ObjectWrapperParent* owp = Unwrap(cx, from);
|
||||
if (!owp)
|
||||
return false;
|
||||
*to = owp;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*static*/ bool
|
||||
ObjectWrapperParent::
|
||||
JSObject_from_PObjectWrapperParent(JSContext* cx,
|
||||
const PObjectWrapperParent* from,
|
||||
MutableHandleObject to)
|
||||
{
|
||||
const ObjectWrapperParent* owp =
|
||||
static_cast<const ObjectWrapperParent*>(from);
|
||||
to.set(owp
|
||||
? owp->GetJSObject(cx)
|
||||
: JSVAL_TO_OBJECT(JSVAL_NULL));
|
||||
return true;
|
||||
}
|
||||
|
||||
/*static*/ bool
|
||||
ObjectWrapperParent::
|
||||
jsval_from_PObjectWrapperParent(JSContext* cx,
|
||||
const PObjectWrapperParent* from,
|
||||
jsval* to)
|
||||
{
|
||||
Rooted<JSObject*> obj(cx);
|
||||
if (!JSObject_from_PObjectWrapperParent(cx, from, &obj))
|
||||
return false;
|
||||
*to = OBJECT_TO_JSVAL(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
jsid_from_int(JSContext* cx, int from, jsid* to)
|
||||
{
|
||||
jsval v = INT_TO_JSVAL(from);
|
||||
return JS_ValueToId(cx, v, to);
|
||||
}
|
||||
|
||||
static bool
|
||||
jsid_from_nsString(JSContext* cx, const nsString& from, jsid* to)
|
||||
{
|
||||
JSString* str = JS_NewUCStringCopyZ(cx, from.BeginReading());
|
||||
if (!str)
|
||||
return false;
|
||||
return JS_ValueToId(cx, STRING_TO_JSVAL(str), to);
|
||||
}
|
||||
|
||||
static bool
|
||||
jsval_to_nsString(JSContext* cx, jsid from, nsString* to)
|
||||
{
|
||||
JSString* str;
|
||||
const jschar* chars;
|
||||
jsval idval;
|
||||
if (JS_IdToValue(cx, from, &idval) &&
|
||||
(str = JS_ValueToString(cx, idval)) &&
|
||||
(chars = JS_GetStringCharsZ(cx, str))) {
|
||||
*to = chars;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*static*/ JSBool
|
||||
ObjectWrapperParent::CPOW_AddProperty(JSContext *cx, HandleObject obj, HandleId id,
|
||||
MutableHandleValue vp)
|
||||
{
|
||||
CPOW_LOG(("Calling CPOW_AddProperty (%s)...",
|
||||
JSVAL_TO_CSTR(cx, id)));
|
||||
|
||||
ObjectWrapperParent* self = Unwrap(cx, obj);
|
||||
if (!self)
|
||||
return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_AddProperty");
|
||||
|
||||
if (AutoResolveFlag::IsSet(obj))
|
||||
return JS_TRUE;
|
||||
|
||||
AutoCheckOperation aco(cx, self);
|
||||
|
||||
nsString in_id;
|
||||
|
||||
if (!jsval_to_nsString(cx, id, &in_id))
|
||||
return JS_FALSE;
|
||||
|
||||
return (self->Manager()->RequestRunToCompletion() &&
|
||||
self->CallAddProperty(in_id,
|
||||
aco.StatusPtr()) &&
|
||||
aco.Ok());
|
||||
}
|
||||
|
||||
/*static*/ JSBool
|
||||
ObjectWrapperParent::CPOW_GetProperty(JSContext *cx, HandleObject obj, HandleId id,
|
||||
MutableHandleValue vp)
|
||||
{
|
||||
CPOW_LOG(("Calling CPOW_GetProperty (%s)...",
|
||||
JSVAL_TO_CSTR(cx, id)));
|
||||
|
||||
ObjectWrapperParent* self = Unwrap(cx, obj);
|
||||
if (!self)
|
||||
return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_GetProperty");
|
||||
|
||||
AutoCheckOperation aco(cx, self);
|
||||
|
||||
nsString in_id;
|
||||
|
||||
if (!jsval_to_nsString(cx, id, &in_id))
|
||||
return JS_FALSE;
|
||||
|
||||
JSVariant out_v;
|
||||
|
||||
return (self->Manager()->RequestRunToCompletion() &&
|
||||
self->CallGetProperty(in_id,
|
||||
aco.StatusPtr(), &out_v) &&
|
||||
aco.Ok() &&
|
||||
self->jsval_from_JSVariant(cx, out_v, vp.address()));
|
||||
}
|
||||
|
||||
/*static*/ JSBool
|
||||
ObjectWrapperParent::CPOW_SetProperty(JSContext *cx, HandleObject obj, HandleId id,
|
||||
JSBool strict, MutableHandleValue vp)
|
||||
{
|
||||
CPOW_LOG(("Calling CPOW_SetProperty (%s)...",
|
||||
JSVAL_TO_CSTR(cx, id)));
|
||||
|
||||
ObjectWrapperParent* self = Unwrap(cx, obj);
|
||||
if (!self)
|
||||
return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_SetProperty");
|
||||
|
||||
AutoCheckOperation aco(cx, self);
|
||||
|
||||
nsString in_id;
|
||||
JSVariant in_v;
|
||||
|
||||
if (!jsval_to_nsString(cx, id, &in_id) ||
|
||||
!self->jsval_to_JSVariant(cx, vp, &in_v))
|
||||
return JS_FALSE;
|
||||
|
||||
JSVariant out_v;
|
||||
|
||||
return (self->Manager()->RequestRunToCompletion() &&
|
||||
self->CallSetProperty(in_id, in_v,
|
||||
aco.StatusPtr(), &out_v) &&
|
||||
aco.Ok() &&
|
||||
self->jsval_from_JSVariant(cx, out_v, vp.address()));
|
||||
}
|
||||
|
||||
/*static*/ JSBool
|
||||
ObjectWrapperParent::CPOW_DelProperty(JSContext *cx, HandleObject obj, HandleId id,
|
||||
JSBool *succeeded)
|
||||
{
|
||||
CPOW_LOG(("Calling CPOW_DelProperty (%s)...",
|
||||
JSVAL_TO_CSTR(cx, id)));
|
||||
|
||||
ObjectWrapperParent* self = Unwrap(cx, obj);
|
||||
if (!self)
|
||||
return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_DelProperty");
|
||||
|
||||
AutoCheckOperation aco(cx, self);
|
||||
|
||||
nsString in_id;
|
||||
|
||||
if (!jsval_to_nsString(cx, id, &in_id))
|
||||
return JS_FALSE;
|
||||
|
||||
JSVariant out_v;
|
||||
|
||||
return (self->Manager()->RequestRunToCompletion() &&
|
||||
self->CallDelProperty(in_id,
|
||||
aco.StatusPtr(), &out_v) &&
|
||||
aco.Ok() &&
|
||||
boolean_from_JSVariant(cx, out_v, succeeded));
|
||||
}
|
||||
|
||||
JSBool
|
||||
ObjectWrapperParent::NewEnumerateInit(JSContext* cx, jsval* statep, jsid* idp)
|
||||
{
|
||||
AutoCheckOperation aco(cx, this);
|
||||
|
||||
JSVariant out_state;
|
||||
int out_id;
|
||||
|
||||
return (CallNewEnumerateInit(aco.StatusPtr(), &out_state, &out_id) &&
|
||||
aco.Ok() &&
|
||||
jsval_from_JSVariant(cx, out_state, statep) &&
|
||||
(!idp || jsid_from_int(cx, out_id, idp)));
|
||||
}
|
||||
|
||||
JSBool
|
||||
ObjectWrapperParent::NewEnumerateNext(JSContext* cx, jsval* statep, jsid* idp)
|
||||
{
|
||||
AutoCheckOperation aco(cx, this);
|
||||
|
||||
JSVariant in_state;
|
||||
|
||||
if (!jsval_to_JSVariant(cx, *statep, &in_state))
|
||||
return JS_FALSE;
|
||||
|
||||
JSVariant out_state;
|
||||
nsString out_id;
|
||||
|
||||
if (CallNewEnumerateNext(in_state,
|
||||
aco.StatusPtr(), &out_state, &out_id) &&
|
||||
aco.Ok() &&
|
||||
jsval_from_JSVariant(cx, out_state, statep) &&
|
||||
jsid_from_nsString(cx, out_id, idp))
|
||||
{
|
||||
JSObject* obj = GetJSObject(cx);
|
||||
AutoResolveFlag arf(cx, obj);
|
||||
return JS_DefinePropertyById(cx, obj, *idp, JSVAL_VOID, NULL, NULL,
|
||||
JSPROP_ENUMERATE);
|
||||
}
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
ObjectWrapperParent::NewEnumerateDestroy(JSContext* cx, jsval state)
|
||||
{
|
||||
AutoCheckOperation aco(cx, this);
|
||||
|
||||
JSVariant in_state;
|
||||
|
||||
if (!jsval_to_JSVariant(cx, state, &in_state))
|
||||
return JS_FALSE;
|
||||
|
||||
return SendNewEnumerateDestroy(in_state);
|
||||
}
|
||||
|
||||
/*static*/ JSBool
|
||||
ObjectWrapperParent::CPOW_NewEnumerate(JSContext *cx, HandleObject obj,
|
||||
JSIterateOp enum_op, jsval *statep,
|
||||
jsid *idp)
|
||||
{
|
||||
CPOW_LOG(("Calling CPOW_NewEnumerate..."));
|
||||
|
||||
ObjectWrapperParent* self = Unwrap(cx, obj);
|
||||
if (!self)
|
||||
return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_NewEnumerate");
|
||||
|
||||
switch (enum_op) {
|
||||
case JSENUMERATE_INIT:
|
||||
case JSENUMERATE_INIT_ALL:
|
||||
self->Manager()->RequestRunToCompletion();
|
||||
return self->NewEnumerateInit(cx, statep, idp);
|
||||
case JSENUMERATE_NEXT:
|
||||
return self->NewEnumerateNext(cx, statep, idp);
|
||||
case JSENUMERATE_DESTROY:
|
||||
return self->NewEnumerateDestroy(cx, *statep);
|
||||
}
|
||||
|
||||
NS_NOTREACHED("Unknown enum_op value in CPOW_NewEnumerate");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/*static*/ JSBool
|
||||
ObjectWrapperParent::CPOW_NewResolve(JSContext *cx, HandleObject obj, HandleId id,
|
||||
unsigned flags, MutableHandleObject objp)
|
||||
{
|
||||
CPOW_LOG(("Calling CPOW_NewResolve (%s)...",
|
||||
JSVAL_TO_CSTR(cx, id)));
|
||||
|
||||
ObjectWrapperParent* self = Unwrap(cx, obj);
|
||||
if (!self)
|
||||
return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_NewResolve");
|
||||
|
||||
AutoCheckOperation aco(cx, self);
|
||||
|
||||
nsString in_id;
|
||||
|
||||
if (!jsval_to_nsString(cx, id, &in_id))
|
||||
return JS_FALSE;
|
||||
|
||||
PObjectWrapperParent* out_pobj;
|
||||
|
||||
if (!self->Manager()->RequestRunToCompletion() ||
|
||||
!self->CallNewResolve(in_id, flags,
|
||||
aco.StatusPtr(), &out_pobj) ||
|
||||
!aco.Ok() ||
|
||||
!JSObject_from_PObjectWrapperParent(cx, out_pobj, objp))
|
||||
return JS_FALSE;
|
||||
|
||||
if (objp) {
|
||||
AutoResolveFlag arf(cx, objp.get());
|
||||
Rooted<JSObject*> obj2(cx, objp);
|
||||
JS_DefinePropertyById(cx, obj2, id, JSVAL_VOID, NULL, NULL,
|
||||
JSPROP_ENUMERATE);
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*static*/ JSBool
|
||||
ObjectWrapperParent::CPOW_Convert(JSContext *cx, HandleObject obj, JSType type,
|
||||
MutableHandleValue vp)
|
||||
{
|
||||
CPOW_LOG(("Calling CPOW_Convert (to %s)...",
|
||||
JS_GetTypeName(cx, type)));
|
||||
|
||||
ObjectWrapperParent* self = Unwrap(cx, obj);
|
||||
if (!self)
|
||||
return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_Convert");
|
||||
|
||||
vp.set(OBJECT_TO_JSVAL(obj));
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
ObjectWrapperParent::CPOW_Finalize(js::FreeOp* fop, JSObject* obj)
|
||||
{
|
||||
CPOW_LOG(("Calling CPOW_Finalize..."));
|
||||
|
||||
MOZ_ASSERT(js::GetObjectClass(obj) == &ObjectWrapperParent::sCPOW_JSClass);
|
||||
ObjectWrapperParent* self =
|
||||
static_cast<ObjectWrapperParent*>(JS_GetPrivate(obj));
|
||||
if (self) {
|
||||
self->mObj = NULL;
|
||||
unused << ObjectWrapperParent::Send__delete__(self);
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/ JSBool
|
||||
ObjectWrapperParent::CPOW_Call(JSContext* cx, unsigned argc, jsval* vp)
|
||||
{
|
||||
CPOW_LOG(("Calling CPOW_Call..."));
|
||||
|
||||
Rooted<JSObject*> thisobj(cx, JS_THIS_OBJECT(cx, vp));
|
||||
if (!thisobj)
|
||||
return JS_FALSE;
|
||||
|
||||
ObjectWrapperParent* function =
|
||||
Unwrap(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
|
||||
if (!function)
|
||||
return with_error(cx, JS_FALSE, "Could not unwrap CPOW function");
|
||||
|
||||
AutoCheckOperation aco(cx, function);
|
||||
|
||||
ObjectWrapperParent* receiver = Unwrap(cx, thisobj);
|
||||
if (!receiver) {
|
||||
// Substitute child global for parent global object.
|
||||
// TODO First make sure we're really replacing the global object?
|
||||
ContextWrapperParent* manager =
|
||||
static_cast<ContextWrapperParent*>(function->Manager());
|
||||
receiver = manager->GetGlobalObjectWrapper();
|
||||
}
|
||||
|
||||
InfallibleTArray<JSVariant> in_argv(argc);
|
||||
jsval* argv = JS_ARGV(cx, vp);
|
||||
for (unsigned i = 0; i < argc; i++)
|
||||
if (!jsval_to_JSVariant(cx, argv[i], in_argv.AppendElement()))
|
||||
return JS_FALSE;
|
||||
|
||||
JSVariant out_rval;
|
||||
|
||||
return (function->Manager()->RequestRunToCompletion() &&
|
||||
function->CallCall(receiver, in_argv,
|
||||
aco.StatusPtr(), &out_rval) &&
|
||||
aco.Ok() &&
|
||||
jsval_from_JSVariant(cx, out_rval, vp));
|
||||
}
|
||||
|
||||
/*static*/ JSBool
|
||||
ObjectWrapperParent::CPOW_Construct(JSContext* cx, unsigned argc, jsval* vp)
|
||||
{
|
||||
CPOW_LOG(("Calling CPOW_Construct..."));
|
||||
|
||||
ObjectWrapperParent* constructor = Unwrap(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
|
||||
if (!constructor)
|
||||
return with_error(cx, JS_FALSE, "Could not unwrap CPOW constructor function");
|
||||
|
||||
AutoCheckOperation aco(cx, constructor);
|
||||
|
||||
InfallibleTArray<JSVariant> in_argv(argc);
|
||||
jsval* argv = JS_ARGV(cx, vp);
|
||||
for (unsigned i = 0; i < argc; i++)
|
||||
if (!jsval_to_JSVariant(cx, argv[i], in_argv.AppendElement()))
|
||||
return JS_FALSE;
|
||||
|
||||
PObjectWrapperParent* out_powp;
|
||||
|
||||
return (constructor->Manager()->RequestRunToCompletion() &&
|
||||
constructor->CallConstruct(in_argv, aco.StatusPtr(), &out_powp) &&
|
||||
aco.Ok() &&
|
||||
jsval_from_PObjectWrapperParent(cx, out_powp, vp));
|
||||
}
|
||||
|
||||
/*static*/ JSBool
|
||||
ObjectWrapperParent::CPOW_HasInstance(JSContext *cx, HandleObject obj, MutableHandleValue v,
|
||||
JSBool *bp)
|
||||
{
|
||||
CPOW_LOG(("Calling CPOW_HasInstance..."));
|
||||
|
||||
*bp = JS_FALSE;
|
||||
|
||||
ObjectWrapperParent* self = Unwrap(cx, obj);
|
||||
if (!self)
|
||||
return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_HasInstance");
|
||||
|
||||
AutoCheckOperation aco(cx, self);
|
||||
|
||||
JSVariant in_v;
|
||||
|
||||
if (!jsval_to_JSVariant(cx, v, &in_v))
|
||||
return JS_FALSE;
|
||||
|
||||
return (self->Manager()->RequestRunToCompletion() &&
|
||||
self->CallHasInstance(in_v,
|
||||
aco.StatusPtr(), bp) &&
|
||||
aco.Ok());
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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/. */
|
||||
|
||||
#ifndef mozilla_jsipc_ObjectWrapperParent_h
|
||||
#define mozilla_jsipc_ObjectWrapperParent_h
|
||||
|
||||
#include "mozilla/jsipc/PObjectWrapperParent.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsclass.h"
|
||||
#include "nsAutoJSValHolder.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
class ContextWrapperParent;
|
||||
|
||||
class OperationChecker {
|
||||
public:
|
||||
virtual void CheckOperation(JSContext* cx,
|
||||
OperationStatus* status) = 0;
|
||||
};
|
||||
|
||||
class ObjectWrapperParent
|
||||
: public PObjectWrapperParent
|
||||
, public OperationChecker
|
||||
{
|
||||
public:
|
||||
|
||||
ObjectWrapperParent()
|
||||
: mObj(NULL)
|
||||
{}
|
||||
|
||||
JSObject* GetJSObject(JSContext* cx) const;
|
||||
|
||||
JSObject* GetJSObjectOrNull() const {
|
||||
return mObj;
|
||||
}
|
||||
|
||||
jsval GetJSVal(JSContext* cx) const {
|
||||
return OBJECT_TO_JSVAL(GetJSObject(cx));
|
||||
}
|
||||
|
||||
void CheckOperation(JSContext* cx,
|
||||
OperationStatus* status);
|
||||
|
||||
static const js::Class sCPOW_JSClass;
|
||||
|
||||
protected:
|
||||
|
||||
void ActorDestroy(ActorDestroyReason why);
|
||||
|
||||
ContextWrapperParent* Manager();
|
||||
|
||||
private:
|
||||
|
||||
mutable JSObject* mObj;
|
||||
|
||||
static JSBool
|
||||
CPOW_AddProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
|
||||
JS::MutableHandleValue vp);
|
||||
|
||||
static JSBool
|
||||
CPOW_DelProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JSBool *succeeded);
|
||||
|
||||
static JSBool
|
||||
CPOW_GetProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
|
||||
JS::MutableHandleValue vp);
|
||||
|
||||
static JSBool
|
||||
CPOW_SetProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JSBool strict,
|
||||
JS::MutableHandleValue vp);
|
||||
|
||||
JSBool NewEnumerateInit(JSContext* cx, jsval* statep, jsid* idp);
|
||||
JSBool NewEnumerateNext(JSContext* cx, jsval* statep, jsid* idp);
|
||||
JSBool NewEnumerateDestroy(JSContext* cx, jsval state);
|
||||
static JSBool
|
||||
CPOW_NewEnumerate(JSContext *cx, JS::HandleObject obj, JSIterateOp enum_op,
|
||||
jsval *statep, jsid *idp);
|
||||
|
||||
static JSBool
|
||||
CPOW_NewResolve(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned flags,
|
||||
JS::MutableHandleObject objp);
|
||||
|
||||
static JSBool
|
||||
CPOW_Convert(JSContext *cx, JS::HandleObject obj, JSType type, JS::MutableHandleValue vp);
|
||||
|
||||
static void
|
||||
CPOW_Finalize(js::FreeOp* fop, JSObject* obj);
|
||||
|
||||
static JSBool
|
||||
CPOW_Call(JSContext* cx, unsigned argc, jsval* vp);
|
||||
|
||||
static JSBool
|
||||
CPOW_Construct(JSContext *cx, unsigned argc, jsval *vp);
|
||||
|
||||
static JSBool
|
||||
CPOW_HasInstance(JSContext *cx, JS::HandleObject obj, JS::MutableHandleValue vp, JSBool *bp);
|
||||
|
||||
static bool jsval_to_JSVariant(JSContext* cx, jsval from, JSVariant* to);
|
||||
static bool jsval_from_JSVariant(JSContext* cx, const JSVariant& from,
|
||||
jsval* to);
|
||||
static bool boolean_from_JSVariant(JSContext* cx, const JSVariant& from,
|
||||
JSBool* to);
|
||||
static bool
|
||||
JSObject_to_PObjectWrapperParent(JSContext* cx, JSObject* from,
|
||||
PObjectWrapperParent** to);
|
||||
static bool
|
||||
JSObject_from_PObjectWrapperParent(JSContext* cx,
|
||||
const PObjectWrapperParent* from,
|
||||
JS::MutableHandleObject to);
|
||||
static bool
|
||||
jsval_from_PObjectWrapperParent(JSContext* cx,
|
||||
const PObjectWrapperParent* from,
|
||||
jsval* to);
|
||||
};
|
||||
|
||||
template <class StatusOwnerPolicy>
|
||||
class AutoCheckOperationBase
|
||||
: public StatusOwnerPolicy
|
||||
{
|
||||
JSContext* const mContext;
|
||||
OperationChecker* const mChecker;
|
||||
|
||||
protected:
|
||||
|
||||
AutoCheckOperationBase(JSContext* cx,
|
||||
OperationChecker* checker)
|
||||
: mContext(cx)
|
||||
, mChecker(checker)
|
||||
{}
|
||||
|
||||
virtual ~AutoCheckOperationBase() {
|
||||
mChecker->CheckOperation(mContext, StatusOwnerPolicy::StatusPtr());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool Ok() {
|
||||
return (StatusOwnerPolicy::StatusPtr()->type() == OperationStatus::TJSBool &&
|
||||
StatusOwnerPolicy::StatusPtr()->get_JSBool());
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* mozilla_jsipc_ObjectWrapperParent_h */
|
|
@ -1,23 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=80:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PTestShell;
|
||||
include protocol PObjectWrapper;
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
rpc protocol PContextWrapper
|
||||
{
|
||||
manager PTestShell;
|
||||
manages PObjectWrapper;
|
||||
parent:
|
||||
async __delete__();
|
||||
async PObjectWrapper(bool makeGlobal);
|
||||
};
|
||||
|
||||
}}
|
|
@ -0,0 +1,47 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=80:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PContent;
|
||||
include DOMTypes;
|
||||
include JavaScriptTypes;
|
||||
|
||||
using mozilla::void_t;
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
rpc protocol PJavaScript
|
||||
{
|
||||
manager PContent;
|
||||
|
||||
child:
|
||||
// The parent process no longer holds any references to the child object.
|
||||
async DropObject(uint64_t objId);
|
||||
|
||||
// These roughly map to the ProxyHandler hooks that CPOWs need.
|
||||
urgent Has(uint64_t objId, nsString id) returns (ReturnStatus rs, bool has);
|
||||
urgent HasOwn(uint64_t objId, nsString id) returns (ReturnStatus rs, bool has);
|
||||
urgent Get(uint64_t objId, uint64_t receiverId, nsString id) returns (ReturnStatus rs, JSVariant result);
|
||||
urgent Set(uint64_t objId, uint64_t receiverId, nsString id, bool strict, JSVariant value) returns (ReturnStatus rs, JSVariant result);
|
||||
urgent Call(uint64_t objId, JSParam[] argv) returns (ReturnStatus rs, JSVariant result, JSParam[] outparams);
|
||||
|
||||
urgent InstanceOf(uint64_t objId, JSIID iid) returns (ReturnStatus rs, bool instanceof);
|
||||
urgent GetPropertyDescriptor(uint64_t objId, nsString id, uint32_t flags) returns (ReturnStatus rs, PPropertyDescriptor result);
|
||||
urgent GetOwnPropertyDescriptor(uint64_t objId, nsString id, uint32_t flags) returns (ReturnStatus rs, PPropertyDescriptor result);
|
||||
urgent GetOwnPropertyNames(uint64_t objId) returns (ReturnStatus rs, nsString[] names);
|
||||
urgent Keys(uint64_t objId) returns (ReturnStatus rs, nsString[] names);
|
||||
urgent ObjectClassIs(uint64_t objId, uint32_t classValue) returns (bool result);
|
||||
urgent ClassName(uint64_t objId) returns (nsString name);
|
||||
urgent IsExtensible(uint64_t objId) returns (ReturnStatus rs, bool result);
|
||||
urgent PreventExtensions(uint64_t objId) returns (ReturnStatus rs);
|
||||
|
||||
parent:
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=80:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PContextWrapper;
|
||||
|
||||
include "mozilla/jsipc/CPOWTypes.h";
|
||||
|
||||
using mozilla::void_t;
|
||||
using JSType;
|
||||
using JSBool;
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
union JSVariant {
|
||||
void_t;
|
||||
nullable PObjectWrapper;
|
||||
nsString;
|
||||
int;
|
||||
double;
|
||||
bool; // We'd like to use JSBool here, but IPC::ParamTraits would
|
||||
// treat JSBool as int.
|
||||
};
|
||||
|
||||
union OperationStatus {
|
||||
JSBool;
|
||||
JSVariant; // Exception thrown.
|
||||
};
|
||||
|
||||
rpc protocol PObjectWrapper
|
||||
{
|
||||
manager PContextWrapper;
|
||||
|
||||
child:
|
||||
__delete__(); // unroot
|
||||
|
||||
rpc AddProperty(nsString id)
|
||||
returns (OperationStatus status);
|
||||
|
||||
rpc GetProperty(nsString id)
|
||||
returns (OperationStatus status,
|
||||
JSVariant vp);
|
||||
|
||||
rpc SetProperty(nsString id,
|
||||
JSVariant v)
|
||||
returns (OperationStatus status,
|
||||
JSVariant vp);
|
||||
|
||||
rpc DelProperty(nsString id)
|
||||
returns (OperationStatus status,
|
||||
JSVariant vp);
|
||||
|
||||
rpc NewEnumerateInit()
|
||||
returns (OperationStatus status,
|
||||
JSVariant statep,
|
||||
int idp);
|
||||
|
||||
rpc NewEnumerateNext(JSVariant in_state)
|
||||
returns (OperationStatus status,
|
||||
JSVariant statep,
|
||||
nsString idp);
|
||||
|
||||
async NewEnumerateDestroy(JSVariant in_state);
|
||||
|
||||
rpc NewResolve(nsString id,
|
||||
int flags)
|
||||
returns (OperationStatus status,
|
||||
nullable PObjectWrapper obj2);
|
||||
|
||||
rpc Convert(JSType type)
|
||||
returns (OperationStatus status,
|
||||
JSVariant vp);
|
||||
|
||||
rpc Call(PObjectWrapper receiver,
|
||||
JSVariant[] argv)
|
||||
returns (OperationStatus status,
|
||||
JSVariant rval);
|
||||
|
||||
rpc Construct(JSVariant[] argv)
|
||||
returns (OperationStatus status,
|
||||
nullable PObjectWrapper rval);
|
||||
|
||||
rpc HasInstance(JSVariant v)
|
||||
returns (OperationStatus status,
|
||||
JSBool bp);
|
||||
};
|
||||
|
||||
}}
|
|
@ -3,6 +3,6 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
IPDLSRCS = \
|
||||
PContextWrapper.ipdl \
|
||||
PObjectWrapper.ipdl \
|
||||
JavaScriptTypes.ipdlh \
|
||||
PJavaScript.ipdl \
|
||||
$(NULL)
|
||||
|
|
|
@ -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/.
|
||||
|
||||
toolkit.jar:
|
||||
content/global/cpow/test.xul (tests/adhoc/test.xul)
|
||||
content/global/cpow/child.html (tests/adhoc/child.html)
|
|
@ -6,16 +6,9 @@
|
|||
|
||||
MODULE = 'js'
|
||||
|
||||
EXPORTS.mozilla.jsipc += [
|
||||
'CPOWTypes.h',
|
||||
'ContextWrapperChild.h',
|
||||
'ContextWrapperParent.h',
|
||||
'ObjectWrapperChild.h',
|
||||
'ObjectWrapperParent.h',
|
||||
]
|
||||
|
||||
CPP_SOURCES += [
|
||||
'ObjectWrapperChild.cpp',
|
||||
'ObjectWrapperParent.cpp',
|
||||
'JavaScriptChild.cpp',
|
||||
'JavaScriptParent.cpp',
|
||||
'JavaScriptShared.cpp',
|
||||
]
|
||||
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
window.foo = {
|
||||
a: 42,
|
||||
b: 37 * 73,
|
||||
ctor: function(name, value) {
|
||||
this[name] = value;
|
||||
},
|
||||
fakector: function(name, value) {
|
||||
window[name] = "oyez";
|
||||
this[name] = value;
|
||||
return window;
|
||||
},
|
||||
f: function(x) {
|
||||
document.body.appendChild(document.createElement("div")).innerHTML =
|
||||
"called f(" + x + ")";
|
||||
return x + Math.PI;
|
||||
},
|
||||
pitch: function(ball) {
|
||||
throw ball;
|
||||
}
|
||||
};
|
||||
window.foo.self = window.foo;
|
||||
</script>
|
||||
oyez
|
||||
</body>
|
||||
</html>
|
|
@ -1,103 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
width="800" height="600" orient="vertical">
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
var cpow_tests = {
|
||||
resolve: function(obj, keys) {
|
||||
alert("resolving");
|
||||
keys = keys.split(" ");
|
||||
for (var i = 0; i != keys.length; ++i)
|
||||
alert("has " + keys[i] + "? " + (keys[i] in obj));
|
||||
alert("done resolving");
|
||||
},
|
||||
iterate: function(obj) {
|
||||
alert("iterating");
|
||||
for (var k in obj)
|
||||
alert("key: " + k);
|
||||
alert("done iterating");
|
||||
},
|
||||
navigate: function(child) {
|
||||
alert("navigating");
|
||||
child.location = prompt("Where to?");
|
||||
setTimeout(function() {
|
||||
alert(child.location.href);
|
||||
}, 2000);
|
||||
},
|
||||
construct: function(foo) {
|
||||
alert(new foo.ctor("answer", 42).answer);
|
||||
alert(new foo.fakector("answer", 42).answer);
|
||||
},
|
||||
indirect_eval: function(child) {
|
||||
alert(child.eval("location.href"));
|
||||
alert(new child.Function("x", "return x+1")(42));
|
||||
},
|
||||
funcalls: function(foo) {
|
||||
var fn = foo.f;
|
||||
alert(foo.f(2));
|
||||
alert(fn.call.call(fn, foo, 3));
|
||||
},
|
||||
equality: function(child) {
|
||||
var foo = child.foo,
|
||||
self = foo.self;
|
||||
alert("foo == self? " + (foo == self));
|
||||
alert("foo === self? " + (foo === self));
|
||||
},
|
||||
exceptions: function(child) {
|
||||
var ball = "ball";
|
||||
try {
|
||||
child.foo.pitch(ball);
|
||||
alert("shouldn't reach this point");
|
||||
} catch (x) {
|
||||
alert("ball === x? " + (ball === x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getCPOW() {
|
||||
if (!getCPOW.cpow) {
|
||||
var page = document.getElementById("page"),
|
||||
owner = page.QueryInterface(Components.interfaces.nsIFrameLoaderOwner);
|
||||
getCPOW.cpow = owner.crossProcessObjectWrapper;
|
||||
alert("got fresh CPOW");
|
||||
}
|
||||
return getCPOW.cpow;
|
||||
}
|
||||
|
||||
function test_cpow() {
|
||||
var child = getCPOW();
|
||||
cpow_tests.construct(child.foo);
|
||||
cpow_tests.resolve(child.location, "href hostname");
|
||||
cpow_tests.iterate(child.location);
|
||||
cpow_tests.iterate(child.foo);
|
||||
cpow_tests.funcalls(child.foo);
|
||||
cpow_tests.navigate(child);
|
||||
cpow_tests.equality(child);
|
||||
cpow_tests.exceptions(child);
|
||||
setTimeout(function() {
|
||||
alert("going back");
|
||||
child.history.back();
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
function show_location() {
|
||||
var child = getCPOW();
|
||||
child.location += "#fragment";
|
||||
alert(child.location.href);
|
||||
alert(child.document.documentURI);
|
||||
}
|
||||
</script>
|
||||
|
||||
<toolbar id="controls">
|
||||
<toolbarbutton onclick="test_cpow()" label="Run tests."/>
|
||||
<toolbarbutton onclick="show_location()" label="Show location."/>
|
||||
</toolbar>
|
||||
|
||||
<browser remote="true" width="200" height="200"
|
||||
type="content"
|
||||
src="child.html"
|
||||
id="page" />
|
||||
|
||||
</window>
|
|
@ -1,11 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; 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/.
|
||||
|
||||
MODULE = 'test_jsipc'
|
||||
|
||||
# FIXME/bug 575918: out-of-process xpcshell is broken on OS X
|
||||
if CONFIG['OS_ARCH'] != 'Darwin':
|
||||
XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
|
|
@ -1,66 +0,0 @@
|
|||
var data = {
|
||||
answer: 42,
|
||||
nested: { objects: { work: "yes they do" } },
|
||||
arr: [
|
||||
"zeroeth",
|
||||
{ foo: "bar" },
|
||||
function() { return data },
|
||||
{ toString: function() { return "last" } }
|
||||
],
|
||||
toString: function() {
|
||||
return "CPOW";
|
||||
}
|
||||
};
|
||||
|
||||
var empty = function() {
|
||||
this.try_to_delete = "just try";
|
||||
};
|
||||
empty.prototype = {
|
||||
try_to_delete: "bwahaha",
|
||||
inherited: "inherited",
|
||||
method: function() {
|
||||
return "called"
|
||||
}
|
||||
};
|
||||
data.derived = new empty;
|
||||
|
||||
(data.constructor = function(value) {
|
||||
var self = this;
|
||||
this.value = value;
|
||||
this.check = function(that) {
|
||||
do_check_eq(this.value, that.value);
|
||||
do_check_eq(this, self);
|
||||
do_check_eq(this, that);
|
||||
do_check_false(this.isGlobal());
|
||||
};
|
||||
}).prototype = {
|
||||
isGlobal: function() {
|
||||
return (function() { return this })() == this;
|
||||
}
|
||||
};
|
||||
|
||||
function A() {
|
||||
this.a = A;
|
||||
this.b = A;
|
||||
}
|
||||
function B() {
|
||||
this.b = B;
|
||||
this.c = B;
|
||||
}
|
||||
B.prototype = new A;
|
||||
|
||||
function pitch(ball) {
|
||||
throw ball;
|
||||
}
|
||||
|
||||
get_set = {
|
||||
get foo() { return 42; },
|
||||
get foo_throws() { throw "BAM"; },
|
||||
set one(val) { this.two = val + 1; }
|
||||
};
|
||||
|
||||
function type(x) {
|
||||
return typeof x;
|
||||
}
|
||||
|
||||
function run_test() {}
|
|
@ -1,277 +0,0 @@
|
|||
function run_test() {
|
||||
run_test_in_child("cpow_child.js", run_actual_tests);
|
||||
}
|
||||
|
||||
function run_actual_tests() {
|
||||
var obj = getChildGlobalObject();
|
||||
|
||||
test_properties(obj.data);
|
||||
test_delete(obj.data);
|
||||
test_toString(obj.data);
|
||||
test_inheritance(obj.data.derived);
|
||||
test_constructor(obj.data.constructor,
|
||||
obj.Function,
|
||||
obj.Object,
|
||||
obj.Date);
|
||||
test_instanceof(obj.A, obj.B);
|
||||
test_enumeration(obj.A, obj.B);
|
||||
test_Array(obj.Array);
|
||||
test_Function(obj.Function);
|
||||
test_exceptions(obj.pitch, obj.Object);
|
||||
test_generators(obj.Function);
|
||||
test_Iterator(obj.data, obj.Iterator, obj.StopIteration);
|
||||
test_getters_setters(obj.get_set, obj.Function);
|
||||
test_forbidden_things(obj);
|
||||
|
||||
do_test_finished();
|
||||
}
|
||||
|
||||
function test_properties(data) {
|
||||
do_check_true("answer" in data);
|
||||
do_check_false("cnefhasefho" in data.nested);
|
||||
|
||||
do_check_eq(data.answer, 42);
|
||||
do_check_eq(data.nested.objects.work,
|
||||
"yes they do");
|
||||
do_check_eq(data.asodfijasdiofj, void(0));
|
||||
|
||||
do_check_eq(data.arr.length, 4);
|
||||
do_check_eq(data.arr[4], void(0));
|
||||
do_check_eq(data.arr[0], "zeroeth");
|
||||
do_check_eq(data.arr[1].foo, "bar");
|
||||
|
||||
do_check_true(2 in data.arr);
|
||||
do_check_eq(data.arr[2], data.arr[2]); // ensure reuse
|
||||
do_check_true(data.arr[2]() === data);
|
||||
do_check_eq(data.arr[2]().arr[0], "zeroeth");
|
||||
do_check_true("call" in data.arr[2]);
|
||||
|
||||
do_check_eq(data.arr[3], "last");
|
||||
}
|
||||
|
||||
function test_delete(data) {
|
||||
do_check_eq(data.derived.try_to_delete, "just try");
|
||||
do_check_true(delete data.derived.try_to_delete);
|
||||
do_check_eq(data.derived.try_to_delete, "bwahaha");
|
||||
do_check_true(delete data.derived.try_to_delete);
|
||||
do_check_eq(data.derived.try_to_delete, "bwahaha");
|
||||
}
|
||||
|
||||
function test_toString(data) {
|
||||
do_check_eq(data.toString(), "CPOW");
|
||||
do_check_eq(data + "asdf", "CPOWasdf");
|
||||
do_check_eq(new String(data), "CPOW");
|
||||
}
|
||||
|
||||
function test_inheritance(derived) {
|
||||
do_check_true("inherited" in derived);
|
||||
do_check_false(derived.hasOwnProperty("inherited"));
|
||||
var base = derived.__proto__;
|
||||
do_check_true(base.hasOwnProperty("inherited"));
|
||||
do_check_eq(derived.inherited, "inherited");
|
||||
do_check_eq(derived.method(), "called");
|
||||
do_check_eq(base.method, derived.method);
|
||||
do_check_true(base.method === derived.method);
|
||||
}
|
||||
|
||||
function test_constructor(ctor,
|
||||
ChildFunction,
|
||||
ChildObject,
|
||||
ChildDate) {
|
||||
var obj = new ctor(42);
|
||||
obj.check(obj);
|
||||
|
||||
// Re-run test_inheritance, creating locally everything that
|
||||
// test_inheritance expects to be created in the child process:
|
||||
var empty = new ChildFunction(),
|
||||
proto = new ChildObject();
|
||||
proto.inherited = "inherited";
|
||||
proto.method = new ChildFunction("return 'called'");
|
||||
empty.prototype = proto;
|
||||
test_inheritance(new empty);
|
||||
|
||||
var cd = new ChildDate,
|
||||
tolerance_ms = 20000; // Ridiculously large to accommodate gcZeal delays.
|
||||
do_check_eq(Math.max(Math.abs(cd.getTime() - new Date),
|
||||
tolerance_ms),
|
||||
tolerance_ms);
|
||||
do_check_true(cd instanceof ChildDate);
|
||||
}
|
||||
|
||||
function test_enumeration(A, B) {
|
||||
function check(obj, nk, s) {
|
||||
var keys = [];
|
||||
for (var k in obj)
|
||||
keys[keys.length] = k;
|
||||
do_check_eq(keys.length, nk);
|
||||
do_check_eq(keys.sort().join("~"), s);
|
||||
}
|
||||
check(new B, 3, "a~b~c");
|
||||
check(B.prototype, 2, "a~b");
|
||||
B.prototype = A.prototype;
|
||||
A.prototype = new B;
|
||||
check(new A, 3, "a~b~c");
|
||||
check(new B, 2, "b~c");
|
||||
|
||||
// Put things back the way they were, mostly:
|
||||
A.prototype = B.prototype;
|
||||
B.prototype = new A;
|
||||
}
|
||||
|
||||
function test_instanceof(A, B) {
|
||||
var a = new A, b = new B;
|
||||
do_check_true(a instanceof A);
|
||||
do_check_false(a instanceof B);
|
||||
do_check_true(b instanceof A);
|
||||
do_check_true(b instanceof B);
|
||||
}
|
||||
|
||||
function test_Array(ChildArray) {
|
||||
do_check_true(!!ChildArray);
|
||||
var arr = new ChildArray(1, new ChildArray(2, 3), 4);
|
||||
do_check_eq(arr.length, 3);
|
||||
do_check_eq(arr.slice(1).shift()[1], 3);
|
||||
arr[2] = arr[1];
|
||||
do_check_eq(arr.pop()[0], 2);
|
||||
}
|
||||
|
||||
function test_Function(ChildFunction) {
|
||||
var succ = new ChildFunction("x", "return x + 1");
|
||||
do_check_eq(succ(succ(3)), 5);
|
||||
do_check_eq(succ + "", "" + new Function("x", "return x + 1"));
|
||||
}
|
||||
|
||||
function test_exceptions(pitch, ChildObject) {
|
||||
try {
|
||||
throw "parent-only";
|
||||
} catch (x) {
|
||||
do_check_eq(x, "parent-only");
|
||||
}
|
||||
var ball = new ChildObject(),
|
||||
thrown = false;
|
||||
ball.sport = "baseball";
|
||||
try {
|
||||
pitch(ball);
|
||||
do_throw("Should have thrown.");
|
||||
} catch (x) {
|
||||
thrown = true;
|
||||
do_check_eq(x.sport, "baseball");
|
||||
do_check_eq(x, ball);
|
||||
do_check_true(x === ball);
|
||||
}
|
||||
do_check_true(thrown);
|
||||
}
|
||||
|
||||
function test_generators(ChildFunction) {
|
||||
// Run the test with own Function just to keep sane:
|
||||
if (ChildFunction != Function)
|
||||
test_generators(Function);
|
||||
|
||||
var count = 0, sum = 0,
|
||||
genFn = new ChildFunction("for(var i = 1; i < 4; i++) yield i");
|
||||
|
||||
var gen = genFn();
|
||||
do try { sum += gen.next(); }
|
||||
catch (x) { break; }
|
||||
while ((count += 1));
|
||||
do_check_eq(count, 3);
|
||||
do_check_eq(sum, 6);
|
||||
|
||||
try {
|
||||
for (var n in genFn()) {
|
||||
count += 1;
|
||||
sum += n;
|
||||
}
|
||||
} catch (x) {}
|
||||
do_check_eq(count, 6);
|
||||
do_check_eq(sum, 12);
|
||||
}
|
||||
|
||||
function test_Iterator(data, ChildIterator, ChildStopIteration) {
|
||||
do_check_true(data && ChildIterator && true);
|
||||
var copy = {},
|
||||
thrown = null;
|
||||
try {
|
||||
for (var kv in ChildIterator(data)) {
|
||||
do_check_true(kv[0] in data);
|
||||
do_check_eq(data[kv[0]], kv[1]);
|
||||
copy[kv[0]] = kv[1];
|
||||
}
|
||||
// XXX I shouldn't have to be catching this, should I?
|
||||
} catch (x) { thrown = x; }
|
||||
do_check_true(thrown != null);
|
||||
do_check_true(thrown instanceof ChildStopIteration);
|
||||
do_check_eq(copy + "", "CPOW");
|
||||
}
|
||||
|
||||
function test_getters_setters(get_set, ChildFunction) {
|
||||
do_check_eq(get_set.foo, 42);
|
||||
var thrown = null;
|
||||
try { get_set.bar = get_set.foo_throws; }
|
||||
catch (x) { thrown = x; }
|
||||
do_check_true(thrown != null);
|
||||
do_check_eq(thrown, "BAM");
|
||||
do_check_false("bar" in get_set);
|
||||
|
||||
get_set.two = 2222;
|
||||
get_set.one = 1;
|
||||
do_check_eq(get_set.two, 2);
|
||||
|
||||
var getter = new ChildFunction("return 'you got me'");
|
||||
get_set.__defineGetter__("defined_getter", getter);
|
||||
do_check_eq(get_set.defined_getter, "you got me");
|
||||
do_check_eq(get_set.__lookupGetter__("defined_getter"),
|
||||
getter);
|
||||
|
||||
var setter = new ChildFunction("val", "this.side_effect = val");
|
||||
get_set.__defineSetter__("defined_setter", setter);
|
||||
get_set.side_effect = "can't touch this";
|
||||
get_set.defined_setter = "you set me";
|
||||
do_check_eq(get_set.side_effect, "you set me");
|
||||
do_check_eq(get_set.__lookupSetter__("defined_setter"),
|
||||
setter);
|
||||
}
|
||||
|
||||
function test_forbidden_things(child) {
|
||||
var x_count = 0;
|
||||
|
||||
do_check_eq(child.type(42), "number");
|
||||
|
||||
try {
|
||||
child.type(function(){});
|
||||
do_throw("Should not have been able to pass a parent-created " +
|
||||
"function to the child");
|
||||
} catch (x) {
|
||||
print(x);
|
||||
x_count += 1;
|
||||
}
|
||||
|
||||
try {
|
||||
child.type({});
|
||||
do_throw("Should not have been able to pass a parent-created " +
|
||||
"object to the child");
|
||||
} catch (x) {
|
||||
print(x);
|
||||
x_count += 1;
|
||||
}
|
||||
|
||||
try {
|
||||
child.type.prop = {};
|
||||
do_throw("Should not have been able to set a property of a child " +
|
||||
"object to a parent-created object value");
|
||||
} catch (x) {
|
||||
print(x);
|
||||
x_count += 1;
|
||||
}
|
||||
|
||||
try {
|
||||
child.type.prop = function(){};
|
||||
do_throw("Should not have been able to set a property of a child " +
|
||||
"object to a parent-created function value");
|
||||
} catch (x) {
|
||||
print(x);
|
||||
x_count += 1;
|
||||
}
|
||||
|
||||
do_check_eq(x_count, 4);
|
||||
}
|
|
@ -760,13 +760,15 @@ js::gc::MarkRuntime(JSTracer *trc, bool useSavedRoots)
|
|||
}
|
||||
|
||||
/* The embedding can register additional roots here. */
|
||||
if (JSTraceDataOp op = rt->gcBlackRootsTraceOp)
|
||||
(*op)(trc, rt->gcBlackRootsData);
|
||||
for (size_t i = 0; i < rt->gcBlackRootTracers.length(); i++) {
|
||||
const JSRuntime::ExtraTracer &e = rt->gcBlackRootTracers[i];
|
||||
(*e.op)(trc, e.data);
|
||||
}
|
||||
|
||||
/* During GC, we don't mark gray roots at this stage. */
|
||||
if (JSTraceDataOp op = rt->gcGrayRootsTraceOp) {
|
||||
if (JSTraceDataOp op = rt->gcGrayRootTracer.op) {
|
||||
if (!IS_GC_MARKING_TRACER(trc))
|
||||
(*op)(trc, rt->gcGrayRootsData);
|
||||
(*op)(trc, rt->gcGrayRootTracer.data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -774,9 +776,9 @@ void
|
|||
js::gc::BufferGrayRoots(GCMarker *gcmarker)
|
||||
{
|
||||
JSRuntime *rt = gcmarker->runtime;
|
||||
if (JSTraceDataOp op = rt->gcGrayRootsTraceOp) {
|
||||
if (JSTraceDataOp op = rt->gcGrayRootTracer.op) {
|
||||
gcmarker->startBufferingGrayRoots();
|
||||
(*op)(gcmarker, rt->gcGrayRootsData);
|
||||
(*op)(gcmarker, rt->gcGrayRootTracer.data);
|
||||
gcmarker->endBufferingGrayRoots();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -816,10 +816,6 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
|
|||
analysisPurgeCallback(NULL),
|
||||
analysisPurgeTriggerBytes(0),
|
||||
gcMallocBytes(0),
|
||||
gcBlackRootsTraceOp(NULL),
|
||||
gcBlackRootsData(NULL),
|
||||
gcGrayRootsTraceOp(NULL),
|
||||
gcGrayRootsData(NULL),
|
||||
autoGCRooters(NULL),
|
||||
scriptAndCountsVector(NULL),
|
||||
NaNValue(UndefinedValue()),
|
||||
|
@ -2292,12 +2288,24 @@ JS_AnchorPtr(void *p)
|
|||
{
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_SetExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_AddExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
|
||||
{
|
||||
AssertHeapIsIdle(rt);
|
||||
rt->gcBlackRootsTraceOp = traceOp;
|
||||
rt->gcBlackRootsData = data;
|
||||
return !!rt->gcBlackRootTracers.append(JSRuntime::ExtraTracer(traceOp, data));
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_RemoveExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
|
||||
{
|
||||
AssertHeapIsIdle(rt);
|
||||
for (size_t i = 0; i < rt->gcBlackRootTracers.length(); i++) {
|
||||
JSRuntime::ExtraTracer *e = &rt->gcBlackRootTracers[i];
|
||||
if (e->op == traceOp && e->data == data) {
|
||||
rt->gcBlackRootTracers.erase(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
|
@ -7157,3 +7165,15 @@ JS_GetScriptedGlobal(JSContext *cx)
|
|||
return &i.scopeChain()->global();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_PreventExtensions(JSContext *cx, JS::HandleObject obj)
|
||||
{
|
||||
JSBool extensible;
|
||||
if (!JS_IsExtensible(cx, obj, &extensible))
|
||||
return JS_TRUE;
|
||||
if (extensible)
|
||||
return JS_TRUE;
|
||||
|
||||
return JSObject::preventExtensions(cx, obj);
|
||||
}
|
||||
|
||||
|
|
|
@ -2373,8 +2373,12 @@ JS_AnchorPtr(void *p);
|
|||
* JS_CallTracer whenever the root contains a traceable thing.
|
||||
* data: the data argument to pass to each invocation of traceOp.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_AddExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data);
|
||||
|
||||
/* Undo a call to JS_AddExtraGCRootsTracer. */
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_SetExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data);
|
||||
JS_RemoveExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data);
|
||||
|
||||
/*
|
||||
* JS_CallTracer API and related macros for implementors of JSTraceOp, to
|
||||
|
@ -3217,6 +3221,9 @@ JS_DeepFreezeObject(JSContext *cx, JSObject *obj);
|
|||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_FreezeObject(JSContext *cx, JSObject *obj);
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_PreventExtensions(JSContext *cx, JS::HandleObject obj);
|
||||
|
||||
extern JS_PUBLIC_API(JSObject *)
|
||||
JS_New(JSContext *cx, JSObject *ctor, unsigned argc, jsval *argv);
|
||||
|
||||
|
|
|
@ -1165,16 +1165,27 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||
return needsBarrier_;
|
||||
}
|
||||
|
||||
struct ExtraTracer {
|
||||
JSTraceDataOp op;
|
||||
void *data;
|
||||
|
||||
ExtraTracer()
|
||||
: op(NULL), data(NULL)
|
||||
{}
|
||||
ExtraTracer(JSTraceDataOp op, void *data)
|
||||
: op(op), data(data)
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* The trace operations to trace embedding-specific GC roots. One is for
|
||||
* tracing through black roots and the other is for tracing through gray
|
||||
* roots. The black/gray distinction is only relevant to the cycle
|
||||
* collector.
|
||||
*/
|
||||
JSTraceDataOp gcBlackRootsTraceOp;
|
||||
void *gcBlackRootsData;
|
||||
JSTraceDataOp gcGrayRootsTraceOp;
|
||||
void *gcGrayRootsData;
|
||||
typedef js::Vector<ExtraTracer, 4, js::SystemAllocPolicy> ExtraTracerVector;
|
||||
ExtraTracerVector gcBlackRootTracers;
|
||||
ExtraTracer gcGrayRootTracer;
|
||||
|
||||
/* Stack of thread-stack-allocated GC roots. */
|
||||
js::AutoGCRooter *autoGCRooters;
|
||||
|
|
|
@ -52,8 +52,8 @@ JS_SetSourceHook(JSRuntime *rt, JS_SourceHook hook)
|
|||
JS_FRIEND_API(void)
|
||||
JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
|
||||
{
|
||||
rt->gcGrayRootsTraceOp = traceOp;
|
||||
rt->gcGrayRootsData = data;
|
||||
rt->gcGrayRootTracer.op = traceOp;
|
||||
rt->gcGrayRootTracer.data = data;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSString *)
|
||||
|
@ -302,6 +302,18 @@ JS_DefineFunctionsWithHelp(JSContext *cx, JSObject *objArg, const JSFunctionSpec
|
|||
return true;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
js_ObjectClassIs(JSContext *cx, HandleObject obj, ESClassValue classValue)
|
||||
{
|
||||
return ObjectClassIs(obj, classValue, cx);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(const char *)
|
||||
js_ObjectClassName(JSContext *cx, HandleObject obj)
|
||||
{
|
||||
return JSObject::className(cx, obj);
|
||||
}
|
||||
|
||||
AutoSwitchCompartment::AutoSwitchCompartment(JSContext *cx, JSCompartment *newCompartment
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
|
||||
: cx(cx), oldCompartment(cx->compartment())
|
||||
|
|
|
@ -133,6 +133,12 @@ js_GetterOnlyPropertyStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
|
|||
JS_FRIEND_API(void)
|
||||
js_ReportOverRecursed(JSContext *maybecx);
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
js_ObjectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
|
||||
|
||||
JS_FRIEND_API(const char *)
|
||||
js_ObjectClassName(JSContext *cx, JS::HandleObject obj);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
/*
|
||||
|
|
|
@ -2917,8 +2917,8 @@ MarkGrayReferences(JSRuntime *rt)
|
|||
gcmarker->markBufferedGrayRoots(zone);
|
||||
} else {
|
||||
JS_ASSERT(!rt->gcIsIncremental);
|
||||
if (JSTraceDataOp op = rt->gcGrayRootsTraceOp)
|
||||
(*op)(gcmarker, rt->gcGrayRootsData);
|
||||
if (JSTraceDataOp op = rt->gcGrayRootTracer.op)
|
||||
(*op)(gcmarker, rt->gcGrayRootTracer.data);
|
||||
}
|
||||
SliceBudget budget;
|
||||
gcmarker->drainMarkStack(budget);
|
||||
|
|
|
@ -680,19 +680,6 @@ SendCommand(JSContext* cx,
|
|||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
GetChildGlobalObject(JSContext* cx,
|
||||
unsigned,
|
||||
jsval* vp)
|
||||
{
|
||||
JS::Rooted<JSObject*> global(cx);
|
||||
if (XRE_GetChildGlobalObject(cx, global.address())) {
|
||||
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(global));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* JSContext option name to flag map. The option names are in alphabetical
|
||||
* order for better reporting.
|
||||
|
@ -919,7 +906,6 @@ static const JSFunctionSpec glob_functions[] = {
|
|||
JS_FS("dumpHeap", DumpHeap, 5,0),
|
||||
#endif
|
||||
JS_FS("sendCommand", SendCommand, 1,0),
|
||||
JS_FS("getChildGlobalObject", GetChildGlobalObject, 0,0),
|
||||
JS_FS("atob", Atob, 1,0),
|
||||
JS_FS("btoa", Btoa, 1,0),
|
||||
JS_FS("Blob", Blob, 2,JSFUN_CONSTRUCTOR),
|
||||
|
|
|
@ -32,8 +32,11 @@ LOCAL_INCLUDES = \
|
|||
-I$(topsrcdir)/layout/base \
|
||||
-I$(topsrcdir)/dom/base \
|
||||
-I$(topsrcdir)/xpcom/ds \
|
||||
-I$(topsrcdir)/js/ipc \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||
|
||||
SHARED_LIBRARY_LIBS = \
|
||||
../loader/$(LIB_PREFIX)jsloader_s.$(LIB_SUFFIX) \
|
||||
../wrappers/$(LIB_PREFIX)xpcwrappers_s.$(LIB_SUFFIX) \
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "JavaScriptParent.h"
|
||||
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/PrimitiveConversions.h"
|
||||
|
@ -62,6 +63,18 @@ XPCConvert::IsMethodReflectable(const XPTMethodDescriptor& info)
|
|||
return true;
|
||||
}
|
||||
|
||||
static JSObject*
|
||||
UnwrapNativeCPOW(nsISupports* wrapper)
|
||||
{
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> underware = do_QueryInterface(wrapper);
|
||||
if (underware) {
|
||||
JSObject* mainObj = underware->GetJSObject();
|
||||
if (mainObj && mozilla::jsipc::JavaScriptParent::IsCPOW(mainObj))
|
||||
return mainObj;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
// static
|
||||
|
@ -793,8 +806,7 @@ XPCConvert::NativeInterface2JSObject(jsval* d,
|
|||
*d = JSVAL_NULL;
|
||||
if (dest)
|
||||
*dest = nullptr;
|
||||
nsISupports *src = aHelper.Object();
|
||||
if (!src)
|
||||
if (!aHelper.Object())
|
||||
return true;
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
|
||||
|
@ -839,6 +851,17 @@ XPCConvert::NativeInterface2JSObject(jsval* d,
|
|||
flat = nullptr;
|
||||
}
|
||||
|
||||
// Don't double wrap CPOWs. This is a temporary measure for compatibility
|
||||
// with objects that don't provide necessary QIs (such as objects under
|
||||
// the new DOM bindings). We expect the other side of the CPOW to have
|
||||
// the appropriate wrappers in place.
|
||||
if (JSObject *cpow = UnwrapNativeCPOW(aHelper.Object())) {
|
||||
if (!JS_WrapObject(cx, &cpow))
|
||||
return false;
|
||||
*d = OBJECT_TO_JSVAL(cpow);
|
||||
return true;
|
||||
}
|
||||
|
||||
// We can't simply construct a slim wrapper. Go ahead and create an
|
||||
// XPCWrappedNative for this object. At this point, |flat| could be
|
||||
// non-null, meaning that either we already have a wrapped native from
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "XPCWrapper.h"
|
||||
#include "JavaScriptParent.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
using namespace JS;
|
||||
|
@ -476,7 +477,10 @@ static JSObject *
|
|||
FindObjectForHasInstance(JSContext *cx, HandleObject objArg)
|
||||
{
|
||||
RootedObject obj(cx, objArg), proto(cx);
|
||||
while (obj && !IS_WN_REFLECTOR(obj) && !IsDOMObject(obj)) {
|
||||
|
||||
while (obj && !IS_WN_REFLECTOR(obj) &&
|
||||
!IsDOMObject(obj) && !mozilla::jsipc::JavaScriptParent::IsCPOW(obj))
|
||||
{
|
||||
if (js::IsWrapper(obj)) {
|
||||
obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
|
||||
continue;
|
||||
|
@ -488,6 +492,57 @@ FindObjectForHasInstance(JSContext *cx, HandleObject objArg)
|
|||
return obj;
|
||||
}
|
||||
|
||||
nsresult
|
||||
xpc::HasInstance(JSContext *cx, HandleObject objArg, const nsID *iid, bool *bp)
|
||||
{
|
||||
*bp = false;
|
||||
|
||||
RootedObject obj(cx, FindObjectForHasInstance(cx, objArg));
|
||||
if (!obj)
|
||||
return NS_OK;
|
||||
|
||||
if (IsDOMObject(obj)) {
|
||||
// Not all DOM objects implement nsISupports. But if they don't,
|
||||
// there's nothing to do in this HasInstance hook.
|
||||
nsISupports *identity = UnwrapDOMObjectToISupports(obj);
|
||||
if (!identity)
|
||||
return NS_OK;;
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
identity->QueryInterface(*iid, getter_AddRefs(supp));
|
||||
*bp = supp;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mozilla::jsipc::JavaScriptParent::IsCPOW(obj))
|
||||
return mozilla::jsipc::JavaScriptParent::InstanceOf(obj, iid, bp);
|
||||
|
||||
MOZ_ASSERT(IS_WN_REFLECTOR(obj));
|
||||
XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj);
|
||||
if (!other_wrapper)
|
||||
return NS_OK;
|
||||
|
||||
// We'll trust the interface set of the wrapper if this is known
|
||||
// to be an interface that the objects *expects* to be able to
|
||||
// handle.
|
||||
if (other_wrapper->HasInterfaceNoQI(*iid)) {
|
||||
*bp = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Otherwise, we'll end up Querying the native object to be sure.
|
||||
XPCCallContext ccx(JS_CALLER, cx);
|
||||
|
||||
AutoMarkingNativeInterfacePtr iface(ccx);
|
||||
iface = XPCNativeInterface::GetNewOrUsed(iid);
|
||||
|
||||
nsresult findResult = NS_OK;
|
||||
if (iface && other_wrapper->FindTearOff(iface, false, &findResult))
|
||||
*bp = true;
|
||||
if (NS_FAILED(findResult) && findResult != NS_ERROR_NO_INTERFACE)
|
||||
return findResult;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* bool hasInstance (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval val, out bool bp); */
|
||||
NS_IMETHODIMP
|
||||
|
@ -496,60 +551,16 @@ nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper,
|
|||
const jsval &val, bool *bp, bool *_retval)
|
||||
{
|
||||
*bp = false;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (!JSVAL_IS_PRIMITIVE(val)) {
|
||||
// we have a JSObject
|
||||
RootedObject obj(cx, JSVAL_TO_OBJECT(val));
|
||||
if (JSVAL_IS_PRIMITIVE(val))
|
||||
return NS_OK;
|
||||
|
||||
NS_ASSERTION(obj, "when is an object not an object?");
|
||||
// we have a JSObject
|
||||
RootedObject obj(cx, JSVAL_TO_OBJECT(val));
|
||||
|
||||
// is this really a native xpcom object with a wrapper?
|
||||
const nsIID* iid;
|
||||
mInfo->GetIIDShared(&iid);
|
||||
|
||||
obj = FindObjectForHasInstance(cx, obj);
|
||||
if (!obj)
|
||||
return NS_OK;
|
||||
|
||||
if (IsDOMObject(obj)) {
|
||||
// Not all DOM objects implement nsISupports. But if they don't,
|
||||
// there's nothing to do in this HasInstance hook.
|
||||
nsISupports *identity = UnwrapDOMObjectToISupports(obj);
|
||||
if (!identity)
|
||||
return NS_OK;
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
identity->QueryInterface(*iid, getter_AddRefs(supp));
|
||||
*bp = supp;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(IS_WN_REFLECTOR(obj));
|
||||
XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj);
|
||||
if (!other_wrapper)
|
||||
return NS_OK;
|
||||
|
||||
// We'll trust the interface set of the wrapper if this is known
|
||||
// to be an interface that the objects *expects* to be able to
|
||||
// handle.
|
||||
if (other_wrapper->HasInterfaceNoQI(*iid)) {
|
||||
*bp = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Otherwise, we'll end up Querying the native object to be sure.
|
||||
XPCCallContext ccx(JS_CALLER, cx);
|
||||
|
||||
AutoMarkingNativeInterfacePtr iface(ccx);
|
||||
iface = XPCNativeInterface::GetNewOrUsed(iid);
|
||||
|
||||
nsresult findResult = NS_OK;
|
||||
if (iface && other_wrapper->FindTearOff(iface, false, &findResult))
|
||||
*bp = true;
|
||||
if (NS_FAILED(findResult) && findResult != NS_ERROR_NO_INTERFACE)
|
||||
rv = findResult;
|
||||
}
|
||||
return rv;
|
||||
const nsIID* iid;
|
||||
mInfo->GetIIDShared(&iid);
|
||||
return xpc::HasInstance(cx, obj, iid, bp);
|
||||
}
|
||||
|
||||
/* string canCreateWrapper (in nsIIDPtr iid); */
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
using namespace xpc;
|
||||
using namespace JS;
|
||||
|
@ -1649,8 +1650,37 @@ nsXPCWrappedJSClass::GetInterfaceName()
|
|||
return mName;
|
||||
}
|
||||
|
||||
static void
|
||||
FinalizeStub(JSFreeOp *fop, JSObject *obj)
|
||||
{
|
||||
}
|
||||
|
||||
static JSClass XPCOutParamClass = {
|
||||
"XPCOutParam",
|
||||
0,
|
||||
JS_PropertyStub,
|
||||
JS_DeletePropertyStub,
|
||||
JS_PropertyStub,
|
||||
JS_StrictPropertyStub,
|
||||
JS_EnumerateStub,
|
||||
JS_ResolveStub,
|
||||
JS_ConvertStub,
|
||||
FinalizeStub,
|
||||
NULL, /* checkAccess */
|
||||
NULL, /* call */
|
||||
NULL, /* hasInstance */
|
||||
NULL, /* construct */
|
||||
NULL /* trace */
|
||||
};
|
||||
|
||||
bool
|
||||
xpc::IsOutObject(JSContext* cx, JSObject* obj)
|
||||
{
|
||||
return js::GetObjectJSClass(obj) == &XPCOutParamClass;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
nsXPCWrappedJSClass::NewOutObject(JSContext* cx, JSObject* scope)
|
||||
xpc::NewOutObject(JSContext* cx, JSObject* scope)
|
||||
{
|
||||
return JS_NewObject(cx, nullptr, nullptr, JS_GetGlobalForObject(cx, scope));
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ XPC_MSG_DEF(NS_ERROR_XPC_BAD_INITIALIZER_NAME , "Bad initializer name
|
|||
XPC_MSG_DEF(NS_ERROR_XPC_HAS_BEEN_SHUTDOWN , "Operation failed because the XPConnect subsystem has been shutdown")
|
||||
XPC_MSG_DEF(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN , "Cannot modify properties of a WrappedNative")
|
||||
XPC_MSG_DEF(NS_ERROR_XPC_BAD_CONVERT_JS_ZERO_ISNOT_NULL , "Could not convert JavaScript argument - 0 was passed, expected object. Did you mean null?")
|
||||
XPC_MSG_DEF(NS_ERROR_XPC_CANT_PASS_CPOW_TO_NATIVE , "It's illegal to pass a CPOW to native code")
|
||||
|
||||
|
||||
/* common global codes (from nsError.h) */
|
||||
|
|
|
@ -2708,8 +2708,6 @@ private:
|
|||
nsXPCWrappedJSClass(JSContext* cx, REFNSIID aIID,
|
||||
nsIInterfaceInfo* aInfo);
|
||||
|
||||
JSObject* NewOutObject(JSContext* cx, JSObject* scope);
|
||||
|
||||
JSBool IsReflectable(uint16_t i) const
|
||||
{return (JSBool)(mDescriptors[i/32] & (1 << (i%32)));}
|
||||
void SetReflectable(uint16_t i, JSBool b)
|
||||
|
@ -3867,6 +3865,11 @@ GetObjectScope(JSObject *obj)
|
|||
extern JSBool gDebugMode;
|
||||
extern JSBool gDesiredDebugMode;
|
||||
|
||||
JSObject* NewOutObject(JSContext* cx, JSObject* scope);
|
||||
bool IsOutObject(JSContext* cx, JSObject* obj);
|
||||
|
||||
nsresult HasInstance(JSContext *cx, JS::HandleObject objArg, const nsID *iid, bool *bp);
|
||||
|
||||
// Internal use only.
|
||||
bool PushJSContext(JSContext *aCx);
|
||||
void PopJSContext();
|
||||
|
|
|
@ -69,8 +69,6 @@
|
|||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
|
||||
#include "mozilla/jsipc/ContextWrapperParent.h"
|
||||
|
||||
#include "mozilla/ipc/TestShellParent.h"
|
||||
#include "mozilla/ipc/XPCShellEnvironment.h"
|
||||
|
||||
|
@ -96,9 +94,6 @@ using mozilla::dom::ContentProcess;
|
|||
using mozilla::dom::ContentParent;
|
||||
using mozilla::dom::ContentChild;
|
||||
|
||||
using mozilla::jsipc::PContextWrapperParent;
|
||||
using mozilla::jsipc::ContextWrapperParent;
|
||||
|
||||
using mozilla::ipc::TestShellParent;
|
||||
using mozilla::ipc::TestShellCommandParent;
|
||||
using mozilla::ipc::XPCShellEnvironment;
|
||||
|
@ -763,13 +758,6 @@ XRE_SendTestShellCommand(JSContext* aCx,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
XRE_GetChildGlobalObject(JSContext* aCx, JSObject** aGlobalP)
|
||||
{
|
||||
TestShellParent* tsp = GetOrCreateTestShellParent();
|
||||
return tsp && tsp->GetGlobalJSObject(aCx, aGlobalP);
|
||||
}
|
||||
|
||||
bool
|
||||
XRE_ShutdownTestShell()
|
||||
{
|
||||
|
|
|
@ -464,7 +464,9 @@ CycleCollectedJSRuntime::CycleCollectedJSRuntime(uint32_t aMaxbytes,
|
|||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
JS_SetExtraGCRootsTracer(mJSRuntime, TraceBlackJS, this);
|
||||
if (!JS_AddExtraGCRootsTracer(mJSRuntime, TraceBlackJS, this)) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
JS_SetGrayGCRootsTracer(mJSRuntime, TraceGrayJS, this);
|
||||
|
||||
mJSHolders.Init(512);
|
||||
|
|
|
@ -592,6 +592,7 @@
|
|||
ERROR(NS_ERROR_XPC_HAS_BEEN_SHUTDOWN, FAILURE(51)),
|
||||
ERROR(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, FAILURE(52)),
|
||||
ERROR(NS_ERROR_XPC_BAD_CONVERT_JS_ZERO_ISNOT_NULL, FAILURE(53)),
|
||||
ERROR(NS_ERROR_XPC_CANT_PASS_CPOW_TO_NATIVE, FAILURE(54)),
|
||||
/* any new errors here should have an associated entry added in xpc.msg */
|
||||
|
||||
ERROR(NS_SUCCESS_I_DID_SOMETHING, SUCCESS(1)),
|
||||
|
|
|
@ -435,10 +435,6 @@ XRE_API(bool,
|
|||
void* aCallback))
|
||||
class JSObject;
|
||||
|
||||
XRE_API(bool,
|
||||
XRE_GetChildGlobalObject, (JSContext* aCx,
|
||||
JSObject** globalp))
|
||||
|
||||
XRE_API(bool,
|
||||
XRE_ShutdownTestShell, ())
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче