mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 937317 - Implement and expose GetIncumbentGlobal. r=bz,luke
This commit is contained in:
parent
286a469f49
commit
550f45cbab
@ -1545,6 +1545,7 @@ public:
|
||||
|
||||
static JSContext *GetCurrentJSContext();
|
||||
static JSContext *GetSafeJSContext();
|
||||
static JSContext *GetCurrentJSContextForThread();
|
||||
static JSContext *GetDefaultJSContextForThread();
|
||||
|
||||
/**
|
||||
|
@ -5262,6 +5262,17 @@ nsContentUtils::GetDefaultJSContextForThread()
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
JSContext *
|
||||
nsContentUtils::GetCurrentJSContextForThread()
|
||||
{
|
||||
if (MOZ_LIKELY(NS_IsMainThread())) {
|
||||
return GetCurrentJSContext();
|
||||
} else {
|
||||
return workers::GetCurrentThreadJSContext();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
nsContentUtils::ASCIIToLower(nsAString& aStr)
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsIScriptContext.h"
|
||||
@ -91,6 +92,39 @@ void DestroyScriptSettings()
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
// Note: When we're ready to expose it, GetEntryGlobal will look similar to
|
||||
// GetIncumbentGlobal below.
|
||||
|
||||
nsIGlobalObject*
|
||||
GetIncumbentGlobal()
|
||||
{
|
||||
// We need the current JSContext in order to check the JS for
|
||||
// scripted frames that may have appeared since anyone last
|
||||
// manipulated the stack. If it's null, that means that there
|
||||
// must be no entry point on the stack, and therefore no incumbent
|
||||
// global either.
|
||||
JSContext *cx = nsContentUtils::GetCurrentJSContextForThread();
|
||||
if (!cx) {
|
||||
MOZ_ASSERT(ScriptSettingsStack::Ref().EntryPoint() == nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// See what the JS engine has to say. If we've got a scripted caller
|
||||
// override in place, the JS engine will lie to us and pretend that
|
||||
// there's nothing on the JS stack, which will cause us to check the
|
||||
// incumbent script stack below.
|
||||
JS::RootedScript script(cx);
|
||||
if (JS_DescribeScriptedCaller(cx, &script, nullptr)) {
|
||||
JS::RootedObject global(cx, JS_GetGlobalFromScript(script));
|
||||
MOZ_ASSERT(global);
|
||||
return xpc::GetNativeForGlobal(global);
|
||||
}
|
||||
|
||||
// Ok, nothing from the JS engine. Let's use whatever's on the
|
||||
// explicit stack.
|
||||
return ScriptSettingsStack::Ref().Incumbent();
|
||||
}
|
||||
|
||||
AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
||||
bool aIsMainThread,
|
||||
JSContext* aCx)
|
||||
@ -128,6 +162,7 @@ AutoEntryScript::~AutoEntryScript()
|
||||
AutoIncumbentScript::AutoIncumbentScript(nsIGlobalObject* aGlobalObject)
|
||||
: mStack(ScriptSettingsStack::Ref())
|
||||
, mEntry(aGlobalObject, /* aCandidate = */ false)
|
||||
, mCallerOverride(nsContentUtils::GetCurrentJSContextForThread())
|
||||
{
|
||||
mStack.Push(&mEntry);
|
||||
}
|
||||
|
@ -27,6 +27,12 @@ namespace dom {
|
||||
void InitScriptSettings();
|
||||
void DestroyScriptSettings();
|
||||
|
||||
// Note: We don't yet expose GetEntryGlobal, because in order for it to be
|
||||
// correct, we first need to replace a bunch of explicit cx pushing in the
|
||||
// browser with AutoEntryScript. But GetIncumbentGlobal is simpler, because it
|
||||
// can mostly be inferred from the JS stack.
|
||||
nsIGlobalObject* GetIncumbentGlobal();
|
||||
|
||||
class ScriptSettingsStack;
|
||||
struct ScriptSettingsStackEntry {
|
||||
nsCOMPtr<nsIGlobalObject> mGlobalObject;
|
||||
@ -86,6 +92,7 @@ public:
|
||||
private:
|
||||
dom::ScriptSettingsStack& mStack;
|
||||
dom::ScriptSettingsStackEntry mEntry;
|
||||
JS::AutoHideScriptedCaller mCallerOverride;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -6108,12 +6108,44 @@ JS_DescribeScriptedCaller(JSContext *cx, MutableHandleScript script, unsigned *l
|
||||
if (i.done())
|
||||
return false;
|
||||
|
||||
// If the caller is hidden, the embedding wants us to return null here so
|
||||
// that it can check its own stack.
|
||||
if (i.activation()->scriptedCallerIsHidden())
|
||||
return false;
|
||||
|
||||
script.set(i.script());
|
||||
if (lineno)
|
||||
*lineno = js::PCToLineNumber(i.script(), i.pc());
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace JS {
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
HideScriptedCaller(JSContext *cx)
|
||||
{
|
||||
MOZ_ASSERT(cx);
|
||||
|
||||
// If there's no accessible activation on the stack, we'll return null from
|
||||
// JS_DescribeScriptedCaller anyway, so there's no need to annotate
|
||||
// anything.
|
||||
Activation *act = cx->runtime()->mainThread.activation();
|
||||
if (!act)
|
||||
return;
|
||||
act->hideScriptedCaller();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
UnhideScriptedCaller(JSContext *cx)
|
||||
{
|
||||
Activation *act = cx->runtime()->mainThread.activation();
|
||||
if (!act)
|
||||
return;
|
||||
act->unhideScriptedCaller();
|
||||
}
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
static PRStatus
|
||||
CallOnce(void *func)
|
||||
|
@ -4576,10 +4576,53 @@ JS_IsIdentifier(JSContext *cx, JS::HandleString str, bool *isIdentifier);
|
||||
/*
|
||||
* Return the current script and line number of the most currently running
|
||||
* frame. Returns true if a scripted frame was found, false otherwise.
|
||||
*
|
||||
* If a the embedding has hidden the scripted caller for the topmost activation
|
||||
* record, this will also return false.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DescribeScriptedCaller(JSContext *cx, JS::MutableHandleScript script, unsigned *lineno);
|
||||
|
||||
namespace JS {
|
||||
|
||||
/*
|
||||
* Informs the JS engine that the scripted caller should be hidden. This can be
|
||||
* used by the embedding to maintain an override of the scripted caller in its
|
||||
* calculations, by hiding the scripted caller in the JS engine and pushing data
|
||||
* onto a separate stack, which it inspects when JS_DescribeScriptedCaller
|
||||
* returns null.
|
||||
*
|
||||
* We maintain a counter on each activation record. Add() increments the counter
|
||||
* of the topmost activation, and Remove() decrements it. The count may never
|
||||
* drop below zero, and must always be exactly zero when the activation is
|
||||
* popped from the stack.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
HideScriptedCaller(JSContext *cx);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
UnhideScriptedCaller(JSContext *cx);
|
||||
|
||||
class AutoHideScriptedCaller
|
||||
{
|
||||
public:
|
||||
AutoHideScriptedCaller(JSContext *cx
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: mContext(cx)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
HideScriptedCaller(mContext);
|
||||
}
|
||||
~AutoHideScriptedCaller() {
|
||||
UnhideScriptedCaller(mContext);
|
||||
}
|
||||
|
||||
protected:
|
||||
JSContext *mContext;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
} /* namepsace JS */
|
||||
|
||||
/*
|
||||
* Encode/Decode interpreted scripts and functions to/from memory.
|
||||
|
@ -833,6 +833,7 @@ Activation::Activation(JSContext *cx, Kind kind)
|
||||
compartment_(cx->compartment()),
|
||||
prev_(cx->mainThread().activation_),
|
||||
savedFrameChain_(0),
|
||||
hideScriptedCallerCount_(0),
|
||||
kind_(kind)
|
||||
{
|
||||
cx->mainThread().activation_ = this;
|
||||
@ -841,6 +842,7 @@ Activation::Activation(JSContext *cx, Kind kind)
|
||||
Activation::~Activation()
|
||||
{
|
||||
JS_ASSERT(cx_->mainThread().activation_ == this);
|
||||
JS_ASSERT(hideScriptedCallerCount_ == 0);
|
||||
cx_->mainThread().activation_ = prev_;
|
||||
}
|
||||
|
||||
|
@ -1167,6 +1167,13 @@ class Activation
|
||||
// set).
|
||||
size_t savedFrameChain_;
|
||||
|
||||
// Counter incremented by JS::HideScriptedCaller and decremented by
|
||||
// JS::UnhideScriptedCaller. If > 0 for the top activation,
|
||||
// JS_DescribeScriptedCaller will return null instead of querying that
|
||||
// activation, which should prompt the caller to consult embedding-specific
|
||||
// data structures instead.
|
||||
size_t hideScriptedCallerCount_;
|
||||
|
||||
enum Kind { Interpreter, Jit, ForkJoin };
|
||||
Kind kind_;
|
||||
|
||||
@ -1218,6 +1225,17 @@ class Activation
|
||||
return savedFrameChain_ > 0;
|
||||
}
|
||||
|
||||
void hideScriptedCaller() {
|
||||
hideScriptedCallerCount_++;
|
||||
}
|
||||
void unhideScriptedCaller() {
|
||||
JS_ASSERT(hideScriptedCallerCount_ > 0);
|
||||
hideScriptedCallerCount_--;
|
||||
}
|
||||
bool scriptedCallerIsHidden() const {
|
||||
return hideScriptedCallerCount_ > 0;
|
||||
}
|
||||
|
||||
private:
|
||||
Activation(const Activation &other) MOZ_DELETE;
|
||||
void operator=(const Activation &other) MOZ_DELETE;
|
||||
|
Loading…
Reference in New Issue
Block a user