gecko-dev/js/xpconnect/src/XPCJSContextStack.cpp

127 строки
3.6 KiB
C++

/* -*- 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/. */
/* Implement global service to track stack of JSContext. */
#include "xpcprivate.h"
#include "XPCWrapper.h"
#include "nsDOMJSUtils.h"
#include "nsNullPrincipal.h"
#include "mozilla/dom/BindingUtils.h"
using namespace mozilla;
using namespace JS;
using namespace xpc;
using mozilla::dom::DestroyProtoAndIfaceCache;
/***************************************************************************/
XPCJSContextStack::~XPCJSContextStack()
{
if (mSafeJSContext) {
JS_DestroyContextNoGC(mSafeJSContext);
mSafeJSContext = nullptr;
}
}
JSContext*
XPCJSContextStack::Pop()
{
MOZ_ASSERT(!mStack.IsEmpty());
uint32_t idx = mStack.Length() - 1; // The thing we're popping
JSContext* cx = mStack[idx].cx;
mStack.RemoveElementAt(idx);
if (idx == 0) {
js::Debug_SetActiveJSContext(mRuntime->Runtime(), nullptr);
return cx;
}
--idx; // Advance to new top of the stack
XPCJSContextInfo& e = mStack[idx];
if (e.cx && e.savedFrameChain) {
// Pop() can be called outside any request for e.cx.
JSAutoRequest ar(e.cx);
JS_RestoreFrameChain(e.cx);
e.savedFrameChain = false;
}
js::Debug_SetActiveJSContext(mRuntime->Runtime(), e.cx);
return cx;
}
bool
XPCJSContextStack::Push(JSContext* cx)
{
js::Debug_SetActiveJSContext(mRuntime->Runtime(), cx);
if (mStack.Length() == 0) {
mStack.AppendElement(cx);
return true;
}
XPCJSContextInfo& e = mStack[mStack.Length() - 1];
if (e.cx) {
// The cx we're pushing is also stack-top. In general we still need to
// call JS_SaveFrameChain here. But if that would put us in a
// compartment that's same-origin with the current one, we can skip it.
if (e.cx == cx) {
// DOM JSContexts don't store their default compartment object on
// the cx, so in those cases we need to fetch it via the scx
// instead. And in some cases (i.e. the SafeJSContext), we have no
// default compartment object at all.
RootedObject defaultScope(cx, GetDefaultScopeFromJSContext(cx));
if (defaultScope) {
nsIPrincipal* currentPrincipal =
GetCompartmentPrincipal(js::GetContextCompartment(cx));
nsIPrincipal* defaultPrincipal = GetObjectPrincipal(defaultScope);
if (currentPrincipal->Equals(defaultPrincipal)) {
mStack.AppendElement(cx);
return true;
}
}
}
{
// Push() can be called outside any request for e.cx.
JSAutoRequest ar(e.cx);
if (!JS_SaveFrameChain(e.cx))
return false;
e.savedFrameChain = true;
}
}
mStack.AppendElement(cx);
return true;
}
bool
XPCJSContextStack::HasJSContext(JSContext* cx)
{
for (uint32_t i = 0; i < mStack.Length(); i++)
if (cx == mStack[i].cx)
return true;
return false;
}
JSContext*
XPCJSContextStack::GetSafeJSContext()
{
MOZ_ASSERT(mSafeJSContext);
return mSafeJSContext;
}
JSContext*
XPCJSContextStack::InitSafeJSContext()
{
MOZ_ASSERT(!mSafeJSContext);
mSafeJSContext = JS_NewContext(XPCJSRuntime::Get()->Runtime(), 8192);
if (!mSafeJSContext)
MOZ_CRASH();
return mSafeJSContext;
}