зеркало из https://github.com/mozilla/gecko-dev.git
merge m-c to inbound
This commit is contained in:
Коммит
96c549d105
|
@ -464,6 +464,7 @@ function promiseSetupSnippetsMap(aTab, aSetupFn)
|
|||
// The snippets should already be ready by this point. Here we're
|
||||
// just obtaining a reference to the snippets map.
|
||||
cw.ensureSnippetsMapThen(function (aSnippetsMap) {
|
||||
aSnippetsMap = Cu.waiveXrays(aSnippetsMap);
|
||||
info("Got snippets map: " +
|
||||
"{ last-update: " + aSnippetsMap.get("snippets-last-update") +
|
||||
", cached-version: " + aSnippetsMap.get("snippets-cached-version") +
|
||||
|
|
|
@ -36,7 +36,13 @@ function checkState(tab) {
|
|||
}
|
||||
else if (popStateCount == 1) {
|
||||
popStateCount++;
|
||||
is(aEvent.state.obj3.toString(), '/^a$/', "second popstate object.");
|
||||
// When content fires a PopStateEvent and we observe it from a chrome event
|
||||
// listener (as we do here, and, thankfully, nowhere else in the tree), the
|
||||
// state object will be a cross-compartment wrapper to an object that was
|
||||
// deserialized in the content scope. And in this case, since RegExps are
|
||||
// not currently Xrayable (see bug 1014991), trying to pull |obj3| (a RegExp)
|
||||
// off of an Xrayed Object won't work. So we need to waive.
|
||||
is(Cu.waiveXrays(aEvent.state).obj3.toString(), '/^a$/', "second popstate object.");
|
||||
|
||||
// Make sure that the new-elem node is present in the document. If it's
|
||||
// not, then this history entry has a different doc identifier than the
|
||||
|
|
|
@ -635,17 +635,9 @@ this.UITour = {
|
|||
},
|
||||
|
||||
sendPageCallback: function(aDocument, aCallbackID, aData = {}) {
|
||||
let detail = Cu.createObjectIn(aDocument.defaultView);
|
||||
detail.data = Cu.createObjectIn(detail);
|
||||
|
||||
for (let key of Object.keys(aData))
|
||||
detail.data[key] = aData[key];
|
||||
|
||||
Cu.makeObjectPropsNormal(detail.data);
|
||||
Cu.makeObjectPropsNormal(detail);
|
||||
|
||||
detail.callbackID = aCallbackID;
|
||||
|
||||
let detail = {data: aData, callbackID: aCallbackID};
|
||||
detail = Cu.cloneInto(detail, aDocument.defaultView);
|
||||
let event = new aDocument.defaultView.CustomEvent("mozUITourResponse", {
|
||||
bubbles: true,
|
||||
detail: detail
|
||||
|
|
|
@ -11,13 +11,13 @@
|
|||
#include "jsfriendapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsXPCOM.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "nsIURL.h"
|
||||
|
@ -865,15 +865,14 @@ WebSocket::CreateAndDispatchMessageEvent(const nsACString& aData,
|
|||
if (NS_FAILED(rv))
|
||||
return NS_OK;
|
||||
|
||||
// Get the JSContext
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(GetOwner());
|
||||
NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
|
||||
nsCOMPtr<nsIGlobalObject> globalObject = do_QueryInterface(GetOwner());
|
||||
if (NS_WARN_IF(!globalObject)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsIScriptContext* scriptContext = sgo->GetContext();
|
||||
NS_ENSURE_TRUE(scriptContext, NS_ERROR_FAILURE);
|
||||
|
||||
AutoPushJSContext cx(scriptContext->GetNativeContext());
|
||||
NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
|
||||
AutoJSAPI jsapi;
|
||||
JSContext* cx = jsapi.cx();
|
||||
JSAutoCompartment ac(cx, globalObject->GetGlobalJSObject());
|
||||
|
||||
// Create appropriate JS object for message
|
||||
JS::Rooted<JS::Value> jsData(cx);
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "mozilla/dom/HTMLTemplateElement.h"
|
||||
#include "mozilla/dom/HTMLContentElement.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/TextDecoder.h"
|
||||
#include "mozilla/dom/TouchEvent.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
|
@ -5629,6 +5630,8 @@ nsContentUtils::WrapNative(JSContext *cx, nsISupports *native,
|
|||
nsWrapperCache *cache, const nsIID* aIID,
|
||||
JS::MutableHandle<JS::Value> vp, bool aAllowWrapping)
|
||||
{
|
||||
MOZ_ASSERT(cx == GetCurrentJSContext());
|
||||
|
||||
if (!native) {
|
||||
vp.setNull();
|
||||
|
||||
|
@ -5648,8 +5651,7 @@ nsContentUtils::WrapNative(JSContext *cx, nsISupports *native,
|
|||
|
||||
nsresult rv = NS_OK;
|
||||
JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
|
||||
AutoPushJSContext context(cx);
|
||||
rv = sXPConnect->WrapNativeToJSVal(context, scope, native, cache, aIID,
|
||||
rv = sXPConnect->WrapNativeToJSVal(cx, scope, native, cache, aIID,
|
||||
aAllowWrapping, vp);
|
||||
return rv;
|
||||
}
|
||||
|
@ -6111,11 +6113,15 @@ nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern,
|
|||
nsIDocument* aDocument)
|
||||
{
|
||||
NS_ASSERTION(aDocument, "aDocument should be a valid pointer (not null)");
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aDocument->GetWindow());
|
||||
NS_ENSURE_TRUE(sgo, true);
|
||||
nsCOMPtr<nsIGlobalObject> globalObject =
|
||||
do_QueryInterface(aDocument->GetWindow());
|
||||
if (NS_WARN_IF(!globalObject)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
AutoPushJSContext cx(sgo->GetContext()->GetNativeContext());
|
||||
NS_ENSURE_TRUE(cx, true);
|
||||
AutoJSAPI jsapi;
|
||||
JSContext* cx = jsapi.cx();
|
||||
JSAutoCompartment ac(cx, globalObject->GetGlobalJSObject());
|
||||
|
||||
// The pattern has to match the entire value.
|
||||
aPattern.Insert(NS_LITERAL_STRING("^(?:"), 0);
|
||||
|
|
|
@ -26,11 +26,11 @@ extern PRLogModuleInfo* GetDataChannelLog();
|
|||
#include "nsIDOMDataChannel.h"
|
||||
#include "nsIDOMMessageEvent.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
||||
#include "nsError.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
@ -382,14 +382,15 @@ nsDOMDataChannel::DoOnMessageAvailable(const nsACString& aData,
|
|||
if (NS_FAILED(rv)) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(GetOwner());
|
||||
NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
|
||||
|
||||
nsIScriptContext* sc = sgo->GetContext();
|
||||
NS_ENSURE_TRUE(sc, NS_ERROR_FAILURE);
|
||||
nsCOMPtr<nsIGlobalObject> globalObject = do_QueryInterface(GetOwner());
|
||||
if (NS_WARN_IF(!globalObject)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
AutoPushJSContext cx(sc->GetNativeContext());
|
||||
NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
|
||||
AutoJSAPI jsapi;
|
||||
JSContext* cx = jsapi.cx();
|
||||
JSAutoCompartment ac(cx, globalObject->GetGlobalJSObject());
|
||||
|
||||
JS::Rooted<JS::Value> jsData(cx);
|
||||
|
||||
|
|
|
@ -892,8 +892,10 @@ nsScriptLoader::AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
AutoPushJSContext cx(context->GetNativeContext());
|
||||
AutoJSAPIWithErrorsReportedToWindow jsapi(context);
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject());
|
||||
JSAutoCompartment ac(cx, global);
|
||||
|
||||
JS::CompileOptions options(cx);
|
||||
FillCompileOptionsForRequest(aRequest, global, &options);
|
||||
|
|
|
@ -35,8 +35,14 @@
|
|||
function testCpowMessage(message) {
|
||||
ok(message.json.check == "ok", "correct json");
|
||||
|
||||
ok(!Components.utils.isCrossProcessWrapper(message.json), "not everything is a CPOW");
|
||||
|
||||
let data = message.objects.data;
|
||||
let document = message.objects.document;
|
||||
if (test_state == "remote") {
|
||||
ok(Components.utils.isCrossProcessWrapper(data), "got a CPOW");
|
||||
ok(Components.utils.isCrossProcessWrapper(document), "got a CPOW");
|
||||
}
|
||||
ok(data.i === 5, "integer property");
|
||||
ok(data.b === true, "boolean property");
|
||||
ok(data.s === "hello", "string property");
|
||||
|
|
|
@ -983,6 +983,7 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield mask, const bool
|
|||
bool initializeDepthBuffer = 0 != (mask & LOCAL_GL_DEPTH_BUFFER_BIT);
|
||||
bool initializeStencilBuffer = 0 != (mask & LOCAL_GL_STENCIL_BUFFER_BIT);
|
||||
bool drawBuffersIsEnabled = IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers);
|
||||
bool shouldOverrideDrawBuffers = false;
|
||||
|
||||
GLenum currentDrawBuffers[WebGLContext::kMaxColorAttachments];
|
||||
|
||||
|
@ -1008,9 +1009,13 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield mask, const bool
|
|||
if (colorAttachmentsMask[i]) {
|
||||
drawBuffersCommand[i] = LOCAL_GL_COLOR_ATTACHMENT0 + i;
|
||||
}
|
||||
if (currentDrawBuffers[i] != drawBuffersCommand[i])
|
||||
shouldOverrideDrawBuffers = true;
|
||||
}
|
||||
|
||||
gl->fDrawBuffers(mGLMaxDrawBuffers, drawBuffersCommand);
|
||||
// calling draw buffers can cause resolves on adreno drivers so
|
||||
// we try to avoid calling it
|
||||
if (shouldOverrideDrawBuffers)
|
||||
gl->fDrawBuffers(mGLMaxDrawBuffers, drawBuffersCommand);
|
||||
}
|
||||
|
||||
gl->fColorMask(1, 1, 1, 1);
|
||||
|
@ -1047,7 +1052,7 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield mask, const bool
|
|||
|
||||
// Restore GL state after clearing.
|
||||
if (initializeColorBuffer) {
|
||||
if (drawBuffersIsEnabled) {
|
||||
if (shouldOverrideDrawBuffers) {
|
||||
gl->fDrawBuffers(mGLMaxDrawBuffers, currentDrawBuffers);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
#include "WebGLElementArrayCache.h"
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
|
||||
|
@ -88,9 +87,9 @@ UpdateUpperBound(uint32_t* out_upperBound, uint32_t newBound)
|
|||
* We take advantage of the specifics of the situation to avoid generalist tree storage and instead
|
||||
* store the tree entries in a vector, mTreeData.
|
||||
*
|
||||
* The number of leaves is given by mNumLeaves, and mTreeData is always a vector of length
|
||||
* TreeData is always a vector of length
|
||||
*
|
||||
* 2 * mNumLeaves.
|
||||
* 2 * (number of leaves).
|
||||
*
|
||||
* Its data layout is as follows: mTreeData[0] is unused, mTreeData[1] is the root node,
|
||||
* then at offsets 2..3 is the tree level immediately below the root node, then at offsets 4..7
|
||||
|
@ -143,20 +142,21 @@ struct WebGLElementArrayCacheTree
|
|||
static const size_t sElementsPerLeafMask = sElementsPerLeaf - 1; // sElementsPerLeaf is POT
|
||||
|
||||
private:
|
||||
|
||||
// The WebGLElementArrayCache that owns this tree
|
||||
WebGLElementArrayCache& mParent;
|
||||
|
||||
// The tree's internal data storage. Its length is 2 * (number of leaves)
|
||||
// because of its data layout explained in the above class comment.
|
||||
FallibleTArray<T> mTreeData;
|
||||
size_t mNumLeaves;
|
||||
size_t mParentByteSize;
|
||||
|
||||
public:
|
||||
// Constructor. Takes a reference to the WebGLElementArrayCache that is to be
|
||||
// the parent. Does not initialize the tree. Should be followed by a call
|
||||
// to Update() to attempt initializing the tree.
|
||||
WebGLElementArrayCacheTree(WebGLElementArrayCache& p)
|
||||
: mParent(p)
|
||||
, mNumLeaves(0)
|
||||
, mParentByteSize(0)
|
||||
{
|
||||
if (mParent.ByteSize()) {
|
||||
Update(0, mParent.ByteSize() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
T GlobalMaximum() const {
|
||||
|
@ -205,21 +205,26 @@ public:
|
|||
return treeIndex + distance;
|
||||
}
|
||||
|
||||
size_t LeafForElement(size_t element) {
|
||||
size_t NumLeaves() const {
|
||||
// see class comment for why we the tree storage size is 2 * numLeaves
|
||||
return mTreeData.Length() >> 1;
|
||||
}
|
||||
|
||||
size_t LeafForElement(size_t element) const {
|
||||
size_t leaf = element / sElementsPerLeaf;
|
||||
MOZ_ASSERT(leaf < mNumLeaves);
|
||||
MOZ_ASSERT(leaf < NumLeaves());
|
||||
return leaf;
|
||||
}
|
||||
|
||||
size_t LeafForByte(size_t byte) {
|
||||
size_t LeafForByte(size_t byte) const {
|
||||
return LeafForElement(byte / sizeof(T));
|
||||
}
|
||||
|
||||
// Returns the index, into the tree storage, where a given leaf is stored
|
||||
size_t TreeIndexForLeaf(size_t leaf) {
|
||||
// See above class comment. The tree storage is an array of length 2*mNumLeaves.
|
||||
size_t TreeIndexForLeaf(size_t leaf) const {
|
||||
// See above class comment. The tree storage is an array of length 2 * numLeaves.
|
||||
// The leaves are stored in its second half.
|
||||
return leaf + mNumLeaves;
|
||||
return leaf + NumLeaves();
|
||||
}
|
||||
|
||||
static size_t LastElementUnderSameLeaf(size_t element) {
|
||||
|
@ -298,6 +303,8 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
// Updates the tree from the parent's buffer contents. Fallible, as it
|
||||
// may have to resize the tree storage.
|
||||
bool Update(size_t firstByte, size_t lastByte);
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
||||
|
@ -314,19 +321,28 @@ struct TreeForType {};
|
|||
template<>
|
||||
struct TreeForType<uint8_t>
|
||||
{
|
||||
static WebGLElementArrayCacheTree<uint8_t>*& Run(WebGLElementArrayCache *b) { return b->mUint8Tree; }
|
||||
static ScopedDeletePtr<WebGLElementArrayCacheTree<uint8_t>>&
|
||||
Value(WebGLElementArrayCache *b) {
|
||||
return b->mUint8Tree;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct TreeForType<uint16_t>
|
||||
{
|
||||
static WebGLElementArrayCacheTree<uint16_t>*& Run(WebGLElementArrayCache *b) { return b->mUint16Tree; }
|
||||
static ScopedDeletePtr<WebGLElementArrayCacheTree<uint16_t>>&
|
||||
Value(WebGLElementArrayCache *b) {
|
||||
return b->mUint16Tree;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct TreeForType<uint32_t>
|
||||
{
|
||||
static WebGLElementArrayCacheTree<uint32_t>*& Run(WebGLElementArrayCache *b) { return b->mUint32Tree; }
|
||||
static ScopedDeletePtr<WebGLElementArrayCacheTree<uint32_t>>&
|
||||
Value(WebGLElementArrayCache *b) {
|
||||
return b->mUint32Tree;
|
||||
}
|
||||
};
|
||||
|
||||
// Calling this method will 1) update the leaves in this interval
|
||||
|
@ -335,36 +351,46 @@ template<typename T>
|
|||
bool WebGLElementArrayCacheTree<T>::Update(size_t firstByte, size_t lastByte)
|
||||
{
|
||||
MOZ_ASSERT(firstByte <= lastByte);
|
||||
MOZ_ASSERT(lastByte < mParent.ByteSize());
|
||||
MOZ_ASSERT(lastByte < mParent.mBytes.Length());
|
||||
|
||||
size_t numberOfElements = mParent.mBytes.Length() / sizeof(T);
|
||||
size_t requiredNumLeaves = 0;
|
||||
if (numberOfElements > 0) {
|
||||
// If we didn't require the number of leaves to be a power of two, then
|
||||
// it would just be equal to
|
||||
//
|
||||
// ceil(numberOfElements / sElementsPerLeaf)
|
||||
//
|
||||
// The way we implement this (division+ceil) operation in integer arithmetic
|
||||
// is as follows:
|
||||
size_t numLeavesNonPOT = (numberOfElements + sElementsPerLeaf - 1) / sElementsPerLeaf;
|
||||
// It only remains to round that up to the next power of two:
|
||||
requiredNumLeaves = NextPowerOfTwo(numLeavesNonPOT);
|
||||
}
|
||||
|
||||
// Step #0: if needed, resize our tree data storage.
|
||||
if (mParentByteSize != mParent.ByteSize())
|
||||
{
|
||||
size_t numberOfElements = mParent.ByteSize() / sizeof(T);
|
||||
if (numberOfElements == 0) {
|
||||
mParentByteSize = mParent.ByteSize();
|
||||
return true;
|
||||
if (requiredNumLeaves != NumLeaves()) {
|
||||
// see class comment for why we the tree storage size is 2 * numLeaves
|
||||
if (!mTreeData.SetLength(2 * requiredNumLeaves)) {
|
||||
mTreeData.SetLength(0);
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(NumLeaves() == requiredNumLeaves);
|
||||
|
||||
size_t requiredNumLeaves = (numberOfElements + sElementsPerLeaf - 1) / sElementsPerLeaf;
|
||||
size_t oldNumLeaves = mNumLeaves;
|
||||
mNumLeaves = NextPowerOfTwo(requiredNumLeaves);
|
||||
if (mNumLeaves != oldNumLeaves) {
|
||||
// see class comment for why we the tree storage size is 2 * mNumLeaves
|
||||
if (!mTreeData.SetLength(2 * mNumLeaves)) {
|
||||
return false;
|
||||
}
|
||||
if (NumLeaves()) {
|
||||
// when resizing, update the whole tree, not just the subset corresponding
|
||||
// to the part of the buffer being updated.
|
||||
memset(mTreeData.Elements(), 0, mTreeData.Length() * sizeof(T));
|
||||
firstByte = 0;
|
||||
lastByte = mParent.ByteSize() - 1;
|
||||
lastByte = mParent.mBytes.Length() - 1;
|
||||
}
|
||||
|
||||
mParentByteSize = mParent.ByteSize();
|
||||
}
|
||||
|
||||
lastByte = std::min(lastByte, mNumLeaves * sElementsPerLeaf * sizeof(T) - 1);
|
||||
if (NumLeaves() == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
lastByte = std::min(lastByte, NumLeaves() * sElementsPerLeaf * sizeof(T) - 1);
|
||||
if (firstByte > lastByte) {
|
||||
return true;
|
||||
}
|
||||
|
@ -372,7 +398,7 @@ bool WebGLElementArrayCacheTree<T>::Update(size_t firstByte, size_t lastByte)
|
|||
size_t firstLeaf = LeafForByte(firstByte);
|
||||
size_t lastLeaf = LeafForByte(lastByte);
|
||||
|
||||
MOZ_ASSERT(firstLeaf <= lastLeaf && lastLeaf < mNumLeaves);
|
||||
MOZ_ASSERT(firstLeaf <= lastLeaf && lastLeaf < NumLeaves());
|
||||
|
||||
size_t firstTreeIndex = TreeIndexForLeaf(firstLeaf);
|
||||
size_t lastTreeIndex = TreeIndexForLeaf(lastLeaf);
|
||||
|
@ -386,7 +412,6 @@ bool WebGLElementArrayCacheTree<T>::Update(size_t firstByte, size_t lastByte)
|
|||
size_t treeIndex = firstTreeIndex;
|
||||
// srcIndex is the index in the source buffer
|
||||
size_t srcIndex = firstLeaf * sElementsPerLeaf;
|
||||
size_t numberOfElements = mParentByteSize / sizeof(T);
|
||||
while (treeIndex <= lastTreeIndex) {
|
||||
T m = 0;
|
||||
size_t a = srcIndex;
|
||||
|
@ -412,26 +437,8 @@ bool WebGLElementArrayCacheTree<T>::Update(size_t firstByte, size_t lastByte)
|
|||
continue;
|
||||
}
|
||||
|
||||
// initialize local iteration variables: child and parent.
|
||||
size_t child = LeftChildNode(firstTreeIndex);
|
||||
size_t parent = firstTreeIndex;
|
||||
|
||||
// the unrolling makes this look more complicated than it is; the plain non-unrolled
|
||||
// version is in the second while loop below
|
||||
const int unrollSize = 8;
|
||||
while (RightNeighborNode(parent, unrollSize - 1) <= lastTreeIndex)
|
||||
{
|
||||
for (int unroll = 0; unroll < unrollSize; unroll++)
|
||||
{
|
||||
T a = mTreeData[child];
|
||||
child = RightNeighborNode(child);
|
||||
T b = mTreeData[child];
|
||||
child = RightNeighborNode(child);
|
||||
mTreeData[parent] = std::max(a, b);
|
||||
parent = RightNeighborNode(parent);
|
||||
}
|
||||
}
|
||||
// plain non-unrolled version, used to terminate the job after the last unrolled iteration
|
||||
while (parent <= lastTreeIndex)
|
||||
{
|
||||
T a = mTreeData[child];
|
||||
|
@ -446,39 +453,32 @@ bool WebGLElementArrayCacheTree<T>::Update(size_t firstByte, size_t lastByte)
|
|||
return true;
|
||||
}
|
||||
|
||||
WebGLElementArrayCache::WebGLElementArrayCache() {
|
||||
}
|
||||
|
||||
WebGLElementArrayCache::~WebGLElementArrayCache() {
|
||||
delete mUint8Tree;
|
||||
delete mUint16Tree;
|
||||
delete mUint32Tree;
|
||||
free(mUntypedData);
|
||||
}
|
||||
|
||||
bool WebGLElementArrayCache::BufferData(const void* ptr, size_t byteSize) {
|
||||
if (byteSize == 0) {
|
||||
mByteSize = 0;
|
||||
free(mUntypedData);
|
||||
mUntypedData = nullptr;
|
||||
return true;
|
||||
}
|
||||
if (byteSize != mByteSize) {
|
||||
void* newUntypedData = realloc(mUntypedData, byteSize);
|
||||
if (!newUntypedData)
|
||||
bool WebGLElementArrayCache::BufferData(const void* ptr, size_t byteLength) {
|
||||
if (mBytes.Length() != byteLength) {
|
||||
if (!mBytes.SetLength(byteLength)) {
|
||||
mBytes.SetLength(0);
|
||||
return false;
|
||||
mByteSize = byteSize;
|
||||
mUntypedData = newUntypedData;
|
||||
}
|
||||
}
|
||||
|
||||
BufferSubData(0, ptr, byteSize);
|
||||
return true;
|
||||
MOZ_ASSERT(mBytes.Length() == byteLength);
|
||||
return BufferSubData(0, ptr, byteLength);
|
||||
}
|
||||
|
||||
bool WebGLElementArrayCache::BufferSubData(size_t pos, const void* ptr, size_t updateByteSize) {
|
||||
if (!updateByteSize) return true;
|
||||
bool WebGLElementArrayCache::BufferSubData(size_t pos, const void* ptr, size_t updateByteLength) {
|
||||
MOZ_ASSERT(pos + updateByteLength <= mBytes.Length());
|
||||
if (!updateByteLength)
|
||||
return true;
|
||||
if (ptr)
|
||||
memcpy(static_cast<uint8_t*>(mUntypedData) + pos, ptr, updateByteSize);
|
||||
memcpy(mBytes.Elements() + pos, ptr, updateByteLength);
|
||||
else
|
||||
memset(static_cast<uint8_t*>(mUntypedData) + pos, 0, updateByteSize);
|
||||
return UpdateTrees(pos, pos + updateByteSize - 1);
|
||||
memset(mBytes.Elements() + pos, 0, updateByteLength);
|
||||
return UpdateTrees(pos, pos + updateByteLength - 1);
|
||||
}
|
||||
|
||||
bool WebGLElementArrayCache::UpdateTrees(size_t firstByte, size_t lastByte)
|
||||
|
@ -513,12 +513,21 @@ WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
|
|||
// is exactly the max allowed value.
|
||||
MOZ_ASSERT(uint32_t(maxAllowedT) == maxAllowed);
|
||||
|
||||
if (!mByteSize || !countElements)
|
||||
if (!mBytes.Length() || !countElements)
|
||||
return true;
|
||||
|
||||
WebGLElementArrayCacheTree<T>*& tree = TreeForType<T>::Run(this);
|
||||
ScopedDeletePtr<WebGLElementArrayCacheTree<T>>& tree = TreeForType<T>::Value(this);
|
||||
if (!tree) {
|
||||
tree = new WebGLElementArrayCacheTree<T>(*this);
|
||||
if (mBytes.Length()) {
|
||||
bool valid = tree->Update(0, mBytes.Length() - 1);
|
||||
if (!valid) {
|
||||
// Do not assert here. This case would happen if an allocation failed.
|
||||
// We've already settled on fallible allocations around here.
|
||||
tree = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t lastElement = firstElement + countElements - 1;
|
||||
|
@ -537,7 +546,7 @@ WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
|
|||
// before calling tree->Validate, we have to validate ourselves the boundaries of the elements span,
|
||||
// to round them to the nearest multiple of sElementsPerLeaf.
|
||||
size_t firstElementAdjustmentEnd = std::min(lastElement,
|
||||
tree->LastElementUnderSameLeaf(firstElement));
|
||||
tree->LastElementUnderSameLeaf(firstElement));
|
||||
while (firstElement <= firstElementAdjustmentEnd) {
|
||||
const T& curData = elements[firstElement];
|
||||
UpdateUpperBound(out_upperBound, curData);
|
||||
|
@ -546,7 +555,7 @@ WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
|
|||
firstElement++;
|
||||
}
|
||||
size_t lastElementAdjustmentEnd = std::max(firstElement,
|
||||
tree->FirstElementUnderSameLeaf(lastElement));
|
||||
tree->FirstElementUnderSameLeaf(lastElement));
|
||||
while (lastElement >= lastElementAdjustmentEnd) {
|
||||
const T& curData = elements[lastElement];
|
||||
UpdateUpperBound(out_upperBound, curData);
|
||||
|
@ -589,7 +598,7 @@ WebGLElementArrayCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
|||
size_t uint16TreeSize = mUint16Tree ? mUint16Tree->SizeOfIncludingThis(aMallocSizeOf) : 0;
|
||||
size_t uint32TreeSize = mUint32Tree ? mUint32Tree->SizeOfIncludingThis(aMallocSizeOf) : 0;
|
||||
return aMallocSizeOf(this) +
|
||||
mByteSize +
|
||||
mBytes.SizeOfExcludingThis(aMallocSizeOf) +
|
||||
uint8TreeSize +
|
||||
uint16TreeSize +
|
||||
uint32TreeSize;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#define WEBGLELEMENTARRAYCACHE_H
|
||||
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Scoped.h"
|
||||
#include "nsTArray.h"
|
||||
#include <stdint.h>
|
||||
#include "nscore.h"
|
||||
#include "GLDefs.h"
|
||||
|
@ -30,7 +32,7 @@ struct WebGLElementArrayCacheTree;
|
|||
class WebGLElementArrayCache {
|
||||
|
||||
public:
|
||||
bool BufferData(const void* ptr, size_t byteSize);
|
||||
bool BufferData(const void* ptr, size_t byteLength);
|
||||
bool BufferSubData(size_t pos, const void* ptr, size_t updateByteSize);
|
||||
|
||||
bool Validate(GLenum type, uint32_t maxAllowed, size_t first, size_t count,
|
||||
|
@ -39,13 +41,7 @@ public:
|
|||
template<typename T>
|
||||
T Element(size_t i) const { return Elements<T>()[i]; }
|
||||
|
||||
WebGLElementArrayCache()
|
||||
: mUntypedData(nullptr)
|
||||
, mByteSize(0)
|
||||
, mUint8Tree(nullptr)
|
||||
, mUint16Tree(nullptr)
|
||||
, mUint32Tree(nullptr)
|
||||
{}
|
||||
WebGLElementArrayCache();
|
||||
|
||||
~WebGLElementArrayCache();
|
||||
|
||||
|
@ -57,14 +53,10 @@ private:
|
|||
bool Validate(uint32_t maxAllowed, size_t first, size_t count,
|
||||
uint32_t* out_upperBound);
|
||||
|
||||
size_t ByteSize() const {
|
||||
return mByteSize;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T* Elements() const { return static_cast<const T*>(mUntypedData); }
|
||||
const T* Elements() const { return reinterpret_cast<const T*>(mBytes.Elements()); }
|
||||
template<typename T>
|
||||
T* Elements() { return static_cast<T*>(mUntypedData); }
|
||||
T* Elements() { return reinterpret_cast<T*>(mBytes.Elements()); }
|
||||
|
||||
bool UpdateTrees(size_t firstByte, size_t lastByte);
|
||||
|
||||
|
@ -73,11 +65,10 @@ private:
|
|||
template<typename T>
|
||||
friend struct TreeForType;
|
||||
|
||||
void* mUntypedData;
|
||||
size_t mByteSize;
|
||||
WebGLElementArrayCacheTree<uint8_t>* mUint8Tree;
|
||||
WebGLElementArrayCacheTree<uint16_t>* mUint16Tree;
|
||||
WebGLElementArrayCacheTree<uint32_t>* mUint32Tree;
|
||||
FallibleTArray<uint8_t> mBytes;
|
||||
ScopedDeletePtr<WebGLElementArrayCacheTree<uint8_t>> mUint8Tree;
|
||||
ScopedDeletePtr<WebGLElementArrayCacheTree<uint16_t>> mUint16Tree;
|
||||
ScopedDeletePtr<WebGLElementArrayCacheTree<uint32_t>> mUint32Tree;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ SVGPathData::CopyFrom(const SVGPathData& rhs)
|
|||
// Yes, we do want fallible alloc here
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
mCachedPath = nullptr;
|
||||
mData = rhs.mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -72,6 +73,7 @@ SVGPathData::SetValueFromString(const nsAString& aValue)
|
|||
// the first error. We still return any error though so that callers know if
|
||||
// there's a problem.
|
||||
|
||||
mCachedPath = nullptr;
|
||||
nsSVGPathDataParser pathParser(aValue, this);
|
||||
return pathParser.Parse() ? NS_OK : NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
|
@ -84,6 +86,8 @@ SVGPathData::AppendSeg(uint32_t aType, ...)
|
|||
if (!mData.SetLength(newLength)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
mCachedPath = nullptr;
|
||||
|
||||
mData[oldLength] = SVGPathSegUtils::EncodeType(aType);
|
||||
va_list args;
|
||||
va_start(args, aType);
|
||||
|
@ -817,7 +821,11 @@ SVGPathData::ToPathForLengthOrPositionMeasuring() const
|
|||
// pass as aStrokeWidth doesn't matter (since it's only used to determine the
|
||||
// length of those extra little lines).
|
||||
|
||||
return BuildPath(FillRule::FILL_WINDING, NS_STYLE_STROKE_LINECAP_BUTT, 0);
|
||||
if (!mCachedPath) {
|
||||
mCachedPath = BuildPath(FillRule::FILL_WINDING, NS_STYLE_STROKE_LINECAP_BUTT, 0);
|
||||
}
|
||||
|
||||
return mCachedPath;
|
||||
}
|
||||
|
||||
static double
|
||||
|
|
|
@ -195,6 +195,7 @@ protected:
|
|||
nsresult CopyFrom(const SVGPathData& rhs);
|
||||
|
||||
float& operator[](uint32_t aIndex) {
|
||||
mCachedPath = nullptr;
|
||||
return mData[aIndex];
|
||||
}
|
||||
|
||||
|
@ -203,12 +204,14 @@ protected:
|
|||
* increased, in which case the list will be left unmodified.
|
||||
*/
|
||||
bool SetLength(uint32_t aLength) {
|
||||
mCachedPath = nullptr;
|
||||
return mData.SetLength(aLength);
|
||||
}
|
||||
|
||||
nsresult SetValueFromString(const nsAString& aValue);
|
||||
|
||||
void Clear() {
|
||||
mCachedPath = nullptr;
|
||||
mData.Clear();
|
||||
}
|
||||
|
||||
|
@ -222,10 +225,11 @@ protected:
|
|||
|
||||
nsresult AppendSeg(uint32_t aType, ...); // variable number of float args
|
||||
|
||||
iterator begin() { return mData.Elements(); }
|
||||
iterator end() { return mData.Elements() + mData.Length(); }
|
||||
iterator begin() { mCachedPath = nullptr; return mData.Elements(); }
|
||||
iterator end() { mCachedPath = nullptr; return mData.Elements() + mData.Length(); }
|
||||
|
||||
FallibleTArray<float> mData;
|
||||
mutable RefPtr<gfx::Path> mCachedPath;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -26,15 +26,12 @@
|
|||
#include "nsDOMCID.h"
|
||||
#include "nsNodeInfoManager.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "nsCCUncollectableMarker.h"
|
||||
#include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
|
||||
#include "xpcpublic.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
|
||||
using mozilla::dom::DestroyProtoAndIfaceCache;
|
||||
using mozilla::AutoPushJSContext;
|
||||
using mozilla::AutoSafeJSContext;
|
||||
using mozilla::dom::XULDocument;
|
||||
|
||||
uint32_t nsXULPrototypeDocument::gRefCnt;
|
||||
|
|
|
@ -145,8 +145,21 @@ this.PermissionsInstaller = {
|
|||
expandPermissions(permName,
|
||||
newManifest.permissions[permName].access);
|
||||
for (let idx in expandedPermNames) {
|
||||
// We silently upgrade the permission to whatever the permission
|
||||
// is for certified apps (ALLOW or PROMPT) only if the
|
||||
// following holds true:
|
||||
// * The app is preinstalled
|
||||
// * The permission that would be granted is PROMPT
|
||||
// * The app is privileged
|
||||
let permission =
|
||||
aApp.isPreinstalled &&
|
||||
PermissionsTable[permName][appStatus] === PROMPT_ACTION &&
|
||||
appStatus === "privileged"
|
||||
? PermissionsTable[permName]["certified"]
|
||||
: PermissionsTable[permName][appStatus];
|
||||
|
||||
this._setPermission(expandedPermNames[idx],
|
||||
PERM_TO_STRING[PermissionsTable[permName][appStatus]],
|
||||
PERM_TO_STRING[permission],
|
||||
aApp);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -353,7 +353,7 @@ this.DOMApplicationRegistry = {
|
|||
});
|
||||
},
|
||||
|
||||
updatePermissionsForApp: function(aId) {
|
||||
updatePermissionsForApp: function(aId, aIsPreinstalled) {
|
||||
if (!this.webapps[aId]) {
|
||||
return;
|
||||
}
|
||||
|
@ -367,7 +367,8 @@ this.DOMApplicationRegistry = {
|
|||
PermissionsInstaller.installPermissions({
|
||||
manifest: data.manifest,
|
||||
manifestURL: this.webapps[aId].manifestURL,
|
||||
origin: this.webapps[aId].origin
|
||||
origin: this.webapps[aId].origin,
|
||||
isPreinstalled: aIsPreinstalled
|
||||
}, true, function() {
|
||||
debug("Error installing permissions for " + aId);
|
||||
});
|
||||
|
@ -393,20 +394,23 @@ this.DOMApplicationRegistry = {
|
|||
installPreinstalledApp: function installPreinstalledApp(aId) {
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
let app = this.webapps[aId];
|
||||
let baseDir;
|
||||
let baseDir, isPreinstalled = false;
|
||||
try {
|
||||
baseDir = FileUtils.getDir("coreAppsDir", ["webapps", aId], false);
|
||||
if (!baseDir.exists()) {
|
||||
return;
|
||||
return isPreinstalled;
|
||||
} else if (!baseDir.directoryEntries.hasMoreElements()) {
|
||||
debug("Error: Core app in " + baseDir.path + " is empty");
|
||||
return;
|
||||
return isPreinstalled;
|
||||
}
|
||||
} catch(e) {
|
||||
// In ENG builds, we don't have apps in coreAppsDir.
|
||||
return;
|
||||
return isPreinstalled;
|
||||
}
|
||||
|
||||
// Beyond this point we know it's really a preinstalled app.
|
||||
isPreinstalled = true;
|
||||
|
||||
let filesToMove;
|
||||
let isPackage;
|
||||
|
||||
|
@ -418,7 +422,7 @@ this.DOMApplicationRegistry = {
|
|||
let appFile = baseDir.clone();
|
||||
appFile.append("application.zip");
|
||||
if (appFile.exists()) {
|
||||
return;
|
||||
return isPreinstalled;
|
||||
}
|
||||
|
||||
isPackage = false;
|
||||
|
@ -449,7 +453,7 @@ this.DOMApplicationRegistry = {
|
|||
app.basePath = OS.Path.dirname(this.appsFile);
|
||||
|
||||
if (!isPackage) {
|
||||
return;
|
||||
return isPreinstalled;
|
||||
}
|
||||
|
||||
app.origin = "app://" + aId;
|
||||
|
@ -481,6 +485,7 @@ this.DOMApplicationRegistry = {
|
|||
} finally {
|
||||
zipReader.close();
|
||||
}
|
||||
return isPreinstalled;
|
||||
#endif
|
||||
},
|
||||
|
||||
|
@ -589,13 +594,13 @@ this.DOMApplicationRegistry = {
|
|||
|
||||
// At first run, install preloaded apps and set up their permissions.
|
||||
for (let id in this.webapps) {
|
||||
this.installPreinstalledApp(id);
|
||||
let isPreinstalled = this.installPreinstalledApp(id);
|
||||
this.removeIfHttpsDuplicate(id);
|
||||
if (!this.webapps[id]) {
|
||||
continue;
|
||||
}
|
||||
this.updateOfflineCacheForApp(id);
|
||||
this.updatePermissionsForApp(id);
|
||||
this.updatePermissionsForApp(id, isPreinstalled);
|
||||
}
|
||||
// Need to update the persisted list of apps since
|
||||
// installPreinstalledApp() removes the ones failing to install.
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/dom/ArchiveRequestBinding.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
|
@ -131,13 +131,15 @@ ArchiveRequest::ReaderReady(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
|
|||
|
||||
nsresult rv;
|
||||
|
||||
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
|
||||
NS_ENSURE_STATE(sc);
|
||||
nsCOMPtr<nsIGlobalObject> globalObject = do_QueryInterface(GetOwner());
|
||||
if (NS_WARN_IF(!globalObject)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
AutoPushJSContext cx(sc->GetNativeContext());
|
||||
NS_ASSERTION(cx, "Failed to get a context!");
|
||||
AutoJSAPI jsapi;
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
JS::Rooted<JSObject*> global(cx, sc->GetWindowProxy());
|
||||
JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject());
|
||||
NS_ASSERTION(global, "Failed to get global object!");
|
||||
|
||||
JSAutoCompartment ac(cx, global);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
file_url.jsm
|
||||
file_empty.html
|
||||
|
||||
[test_bug715041.xul]
|
||||
[test_bug715041_removal.xul]
|
||||
|
@ -9,3 +10,4 @@ support-files =
|
|||
[test_console.xul]
|
||||
[test_navigator_resolve_identity_xrays.xul]
|
||||
[test_sendQueryContentAndSelectionSetEvent.html]
|
||||
[test_bug1016960.html]
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1016960
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1016960</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1016960 **/
|
||||
|
||||
var chromeWindow = window.open("chrome://mochitests/content/chrome/dom/base/test/file_empty.html", "1016960", "chrome");
|
||||
ok(chromeWindow instanceof ChromeWindow, "A chrome window should return true for |instanceof ChromeWindow|.");
|
||||
chromeWindow.close();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1016960">Mozilla Bug 1016960</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1891,7 +1891,7 @@ InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj,
|
|||
const DOMIfaceAndProtoJSClass* clasp =
|
||||
DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj));
|
||||
|
||||
const DOMClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance));
|
||||
const DOMClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance, /* stopAtOuter = */ false));
|
||||
|
||||
MOZ_ASSERT(!domClass || clasp->mPrototypeID != prototypes::id::_ID_Count,
|
||||
"Why do we have a hasInstance hook if we don't have a prototype "
|
||||
|
|
|
@ -1735,7 +1735,7 @@ class CGClassHasInstanceHook(CGAbstractStaticMethod):
|
|||
// FIXME Limit this to chrome by checking xpc::AccessCheck::isChrome(obj).
|
||||
nsISupports* native =
|
||||
nsContentUtils::XPConnect()->GetNativeOfWrapper(cx,
|
||||
js::UncheckedUnwrap(instance));
|
||||
js::UncheckedUnwrap(instance, /* stopAtOuter = */ false));
|
||||
nsCOMPtr<nsIDOM${name}> qiResult = do_QueryInterface(native);
|
||||
*bp = !!qiResult;
|
||||
return true;
|
||||
|
@ -1746,7 +1746,7 @@ class CGClassHasInstanceHook(CGAbstractStaticMethod):
|
|||
|
||||
hasInstanceCode = dedent("""
|
||||
|
||||
const DOMClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance));
|
||||
const DOMClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance, /* stopAtOuter = */ false));
|
||||
*bp = false;
|
||||
if (!domClass) {
|
||||
// Not a DOM object, so certainly not an instance of this interface
|
||||
|
@ -1754,7 +1754,7 @@ class CGClassHasInstanceHook(CGAbstractStaticMethod):
|
|||
}
|
||||
""")
|
||||
if self.descriptor.interface.identifier.name == "ChromeWindow":
|
||||
setBp = "*bp = UnwrapDOMObject<nsGlobalWindow>(js::UncheckedUnwrap(instance))->IsChromeWindow()"
|
||||
setBp = "*bp = UnwrapDOMObject<nsGlobalWindow>(js::UncheckedUnwrap(instance, /* stopAtOuter = */ false))->IsChromeWindow()"
|
||||
else:
|
||||
setBp = "*bp = true"
|
||||
# Sort interaces implementing self by name so we get stable output.
|
||||
|
|
|
@ -2499,6 +2499,7 @@ TabChild::InitRenderingState()
|
|||
if (!sTabChildren) {
|
||||
sTabChildren = new TabChildMap;
|
||||
}
|
||||
MOZ_ASSERT(!sTabChildren->Get(id));
|
||||
sTabChildren->Put(id, this);
|
||||
mLayersId = id;
|
||||
}
|
||||
|
@ -2708,14 +2709,14 @@ TabChild::GetFrom(uint64_t aLayersId)
|
|||
}
|
||||
|
||||
void
|
||||
TabChild::DidComposite()
|
||||
TabChild::DidComposite(uint64_t aTransactionId)
|
||||
{
|
||||
MOZ_ASSERT(mWidget);
|
||||
MOZ_ASSERT(mWidget->GetLayerManager());
|
||||
MOZ_ASSERT(mWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT);
|
||||
|
||||
ClientLayerManager *manager = static_cast<ClientLayerManager*>(mWidget->GetLayerManager());
|
||||
manager->DidComposite();
|
||||
manager->DidComposite(aTransactionId);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -446,7 +446,7 @@ public:
|
|||
static TabChild* GetFrom(nsIPresShell* aPresShell);
|
||||
static TabChild* GetFrom(uint64_t aLayersId);
|
||||
|
||||
void DidComposite();
|
||||
void DidComposite(uint64_t aTransactionId);
|
||||
|
||||
static inline TabChild*
|
||||
GetFrom(nsIDOMWindow* aWindow)
|
||||
|
|
|
@ -1777,7 +1777,13 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
|
|||
mActiveCallbacks.Clear();
|
||||
mCallIds.Clear();
|
||||
LOG(("Releasing MediaManager singleton and thread"));
|
||||
// Note: won't be released immediately as the Observer has a ref to us
|
||||
sSingleton = nullptr;
|
||||
if (mMediaThread) {
|
||||
mMediaThread->Shutdown();
|
||||
mMediaThread = nullptr;
|
||||
}
|
||||
mBackend = nullptr;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -192,10 +192,11 @@ SettingsDB.prototype = {
|
|||
}
|
||||
|
||||
// Fall-through, we now have a dictionary object.
|
||||
let res = {};
|
||||
for (let prop in aObject) {
|
||||
aObject[prop] = this.prepareValue(aObject[prop]);
|
||||
res[prop] = this.prepareValue(aObject[prop]);
|
||||
}
|
||||
return aObject;
|
||||
return res;
|
||||
},
|
||||
|
||||
init: function init() {
|
||||
|
|
|
@ -772,14 +772,13 @@ void
|
|||
Notification::CloseInternal()
|
||||
{
|
||||
if (!mIsClosed) {
|
||||
nsresult rv;
|
||||
// Don't bail out if notification storage fails, since we still
|
||||
// want to send the close event through the alert service.
|
||||
nsCOMPtr<nsINotificationStorage> notificationStorage =
|
||||
do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID);
|
||||
if (notificationStorage) {
|
||||
nsString origin;
|
||||
rv = GetOrigin(GetOwner(), origin);
|
||||
nsresult rv = GetOrigin(GetOwner(), origin);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
notificationStorage->Delete(origin, mID);
|
||||
}
|
||||
|
@ -788,9 +787,7 @@ Notification::CloseInternal()
|
|||
nsCOMPtr<nsIAlertsService> alertService =
|
||||
do_GetService(NS_ALERTSERVICE_CONTRACTID);
|
||||
if (alertService) {
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
alertService->CloseAlert(mAlertName, GetPrincipal());
|
||||
}
|
||||
alertService->CloseAlert(mAlertName, GetPrincipal());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -169,9 +169,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=821850
|
|||
bound.prop = "someOtherVal";
|
||||
is(bound.prop, "set:someOtherVal", "Can set properties from content");
|
||||
|
||||
// Make sure we can't pass JS objects to the XBL scope.
|
||||
// Make sure that XBL scopes get opaque wrappers.
|
||||
//
|
||||
// Note: Now that we have object Xrays, we have to pass in a more obscure
|
||||
// ES type that we don't Xray to test this.
|
||||
var proto = bound.__proto__;
|
||||
proto.passMeAJSObject({prop: 2});
|
||||
var nonXrayableObject = new WeakMap();
|
||||
nonXrayableObject.prop = 2;
|
||||
proto.passMeAJSObject(nonXrayableObject);
|
||||
|
||||
//
|
||||
// Try sticking a bunch of stuff on the prototype object.
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "VBOArena.h"
|
||||
#include "GLContext.h"
|
||||
|
||||
using namespace mozilla::gl;
|
||||
|
||||
GLuint VBOArena::Allocate(GLContext *aGLContext)
|
||||
{
|
||||
if (!mAvailableVBOs.size()) {
|
||||
GLuint vbo;
|
||||
aGLContext->fGenBuffers(1, &vbo);
|
||||
mAllocatedVBOs.push_back(vbo);
|
||||
return vbo;
|
||||
}
|
||||
GLuint vbo = mAvailableVBOs.back();
|
||||
mAvailableVBOs.pop_back();
|
||||
return vbo;
|
||||
}
|
||||
|
||||
void VBOArena::Reset()
|
||||
{
|
||||
mAvailableVBOs = mAllocatedVBOs;
|
||||
}
|
||||
|
||||
void VBOArena::Flush(GLContext *aGLContext)
|
||||
{
|
||||
if (mAvailableVBOs.size()) {
|
||||
#ifdef DEBUG
|
||||
printf_stderr("VBOArena::Flush for %u VBOs\n", mAvailableVBOs.size());
|
||||
#endif
|
||||
aGLContext->fDeleteBuffers(mAvailableVBOs.size(), &mAvailableVBOs[0]);
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 VBOARENA_H_
|
||||
#define VBOARENA_H_
|
||||
|
||||
#include "GLTypes.h"
|
||||
#include <vector>
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
|
||||
class GLContext;
|
||||
|
||||
class VBOArena {
|
||||
public:
|
||||
// Allocate a new VBO.
|
||||
GLuint Allocate(GLContext *aGLContext);
|
||||
|
||||
// Re-use previously allocated VBOs.
|
||||
void Reset();
|
||||
|
||||
// Throw away all allocated VBOs.
|
||||
void Flush(GLContext *aGLContext);
|
||||
private:
|
||||
std::vector<GLuint> mAllocatedVBOs;
|
||||
std::vector<GLuint> mAvailableVBOs;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -55,7 +55,6 @@ EXPORTS += [
|
|||
'SurfaceStream.h',
|
||||
'SurfaceTypes.h',
|
||||
'TextureGarbageBin.h',
|
||||
'VBOArena.h',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_X11']:
|
||||
|
@ -140,7 +139,6 @@ UNIFIED_SOURCES += [
|
|||
'SurfaceTypes.cpp',
|
||||
'TextureGarbageBin.cpp',
|
||||
'TextureImageEGL.cpp',
|
||||
'VBOArena.cpp',
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GFX_TRANSACTION_ID_ALLOCATOR_H
|
||||
#define GFX_TRANSACTION_ID_ALLOCATOR_H
|
||||
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class TransactionIdAllocator {
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(TransactionIdAllocator)
|
||||
|
||||
virtual ~TransactionIdAllocator() {}
|
||||
|
||||
/**
|
||||
* Allocate a unique id number for the current refresh tick, can
|
||||
* only be called while IsInRefresh().
|
||||
*
|
||||
* If too many id's are allocated without being returned then
|
||||
* the refresh driver will suspend until they catch up.
|
||||
*/
|
||||
virtual uint64_t GetTransactionId() = 0;
|
||||
|
||||
/**
|
||||
* Notify that all work (including asynchronous composites)
|
||||
* for a given transaction id has been completed.
|
||||
*
|
||||
* If the refresh driver has been suspended because
|
||||
* of having too many outstanding id's, then this may
|
||||
* resume it.
|
||||
*/
|
||||
virtual void NotifyTransactionCompleted(uint64_t aTransactionId) = 0;
|
||||
|
||||
/**
|
||||
* Revoke a transaction id that isn't needed to track
|
||||
* completion of asynchronous work. This is similar
|
||||
* to NotifyTransactionCompleted except avoids
|
||||
* return ordering issues.
|
||||
*/
|
||||
virtual void RevokeTransactionId(uint64_t aTransactionId) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* GFX_TRANSACTION_ID_ALLOCATOR_H */
|
|
@ -40,6 +40,7 @@ using namespace mozilla::gfx;
|
|||
ClientLayerManager::ClientLayerManager(nsIWidget* aWidget)
|
||||
: mPhase(PHASE_NONE)
|
||||
, mWidget(aWidget)
|
||||
, mLatestTransactionId(0)
|
||||
, mTargetRotation(ROTATION_0)
|
||||
, mRepeatTransaction(false)
|
||||
, mIsRepeatTransaction(false)
|
||||
|
@ -54,6 +55,9 @@ ClientLayerManager::ClientLayerManager(nsIWidget* aWidget)
|
|||
|
||||
ClientLayerManager::~ClientLayerManager()
|
||||
{
|
||||
if (mTransactionIdAllocator) {
|
||||
DidComposite(mLatestTransactionId);
|
||||
}
|
||||
ClearCachedResources();
|
||||
// Stop receiveing AsyncParentMessage at Forwarder.
|
||||
// After the call, the message is directly handled by LayerTransactionChild.
|
||||
|
@ -285,7 +289,7 @@ ClientLayerManager::Composite()
|
|||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::DidComposite()
|
||||
ClientLayerManager::DidComposite(uint64_t aTransactionId)
|
||||
{
|
||||
MOZ_ASSERT(mWidget);
|
||||
nsIWidgetListener *listener = mWidget->GetWidgetListener();
|
||||
|
@ -296,6 +300,7 @@ ClientLayerManager::DidComposite()
|
|||
if (listener) {
|
||||
listener->DidCompositeWindow();
|
||||
}
|
||||
mTransactionIdAllocator->NotifyTransactionCompleted(aTransactionId);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -421,11 +426,13 @@ ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
|
|||
{
|
||||
mPhase = PHASE_FORWARD;
|
||||
|
||||
mLatestTransactionId = mTransactionIdAllocator->GetTransactionId();
|
||||
|
||||
// forward this transaction's changeset to our LayerManagerComposite
|
||||
bool sent;
|
||||
AutoInfallibleTArray<EditReply, 10> replies;
|
||||
if (HasShadowManager() && mForwarder->EndTransaction(&replies, mRegionToClear,
|
||||
aScheduleComposite, mPaintSequenceNumber, &sent)) {
|
||||
mLatestTransactionId, aScheduleComposite, mPaintSequenceNumber, &sent)) {
|
||||
for (nsTArray<EditReply>::size_type i = 0; i < replies.Length(); ++i) {
|
||||
const EditReply& reply = replies[i];
|
||||
|
||||
|
@ -479,6 +486,12 @@ ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
|
|||
if (sent) {
|
||||
mNeedsComposite = false;
|
||||
}
|
||||
if (!sent || mForwarder->GetShadowManager()->HasNoCompositor()) {
|
||||
// Clear the transaction id so that it doesn't get returned
|
||||
// unless we forwarded to somewhere that doesn't actually
|
||||
// have a compositor.
|
||||
mTransactionIdAllocator->RevokeTransactionId(mLatestTransactionId);
|
||||
}
|
||||
} else if (HasShadowManager()) {
|
||||
NS_WARNING("failed to forward Layers transaction");
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "nsRect.h" // for nsIntRect
|
||||
#include "nsTArray.h" // for nsTArray
|
||||
#include "nscore.h" // for nsAString
|
||||
#include "mozilla/layers/TransactionIdAllocator.h"
|
||||
|
||||
class nsIWidget;
|
||||
|
||||
|
@ -166,7 +167,7 @@ public:
|
|||
virtual bool RequestOverfill(mozilla::dom::OverfillCallback* aCallback) MOZ_OVERRIDE;
|
||||
virtual void RunOverfillCallback(const uint32_t aOverfill) MOZ_OVERRIDE;
|
||||
|
||||
virtual void DidComposite();
|
||||
virtual void DidComposite(uint64_t aTransactionId);
|
||||
|
||||
virtual bool SupportsMixBlendModes(EnumSet<gfx::CompositionOp>& aMixBlendModes) MOZ_OVERRIDE
|
||||
{
|
||||
|
@ -207,6 +208,8 @@ public:
|
|||
// Get a copy of the compositor-side APZ test data for our layers ID.
|
||||
void GetCompositorSideAPZTestData(APZTestData* aData) const;
|
||||
|
||||
void SetTransactionIdAllocator(TransactionIdAllocator* aAllocator) { mTransactionIdAllocator = aAllocator; }
|
||||
|
||||
protected:
|
||||
enum TransactionPhase {
|
||||
PHASE_NONE, PHASE_CONSTRUCTION, PHASE_DRAWING, PHASE_FORWARD
|
||||
|
@ -253,6 +256,9 @@ private:
|
|||
// back to mShadowTarget.
|
||||
nsRefPtr<gfxContext> mShadowTarget;
|
||||
|
||||
nsRefPtr<TransactionIdAllocator> mTransactionIdAllocator;
|
||||
uint64_t mLatestTransactionId;
|
||||
|
||||
// Sometimes we draw to targets that don't natively support
|
||||
// landscape/portrait orientation. When we need to implement that
|
||||
// ourselves, |mTargetRotation| describes the induced transform we
|
||||
|
|
|
@ -418,9 +418,10 @@ TextureClient::ShouldDeallocateInDestructor() const
|
|||
}
|
||||
|
||||
// If we're meant to be deallocated by the host,
|
||||
// but we haven't been shared yet, then we should
|
||||
// but we haven't been shared yet or
|
||||
// TextureFlags::DEALLOCATE_CLIENT is set, then we should
|
||||
// deallocate on the client instead.
|
||||
return !IsSharedWithCompositor();
|
||||
return !IsSharedWithCompositor() || (GetFlags() & TextureFlags::DEALLOCATE_CLIENT);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "mozilla/RefPtr.h" // for TemporaryRef, RefCounted
|
||||
#include "mozilla/TimeStamp.h" // for TimeStamp, TimeDuration
|
||||
#include "nsTArray.h" // for nsAutoTArray, nsTArray_Impl, etc
|
||||
#include "VBOArena.h" // for gl::VBOArena
|
||||
#include "prio.h" // for NSPR file i/o
|
||||
|
||||
namespace mozilla {
|
||||
|
|
|
@ -124,15 +124,15 @@ CompositorChild::RecvInvalidateAll()
|
|||
}
|
||||
|
||||
bool
|
||||
CompositorChild::RecvDidComposite(const uint64_t& aId)
|
||||
CompositorChild::RecvDidComposite(const uint64_t& aId, const uint64_t& aTransactionId)
|
||||
{
|
||||
if (mLayerManager) {
|
||||
MOZ_ASSERT(aId == 0);
|
||||
mLayerManager->DidComposite();
|
||||
mLayerManager->DidComposite(aTransactionId);
|
||||
} else if (aId != 0) {
|
||||
dom::TabChild *child = dom::TabChild::GetFrom(aId);
|
||||
if (child) {
|
||||
child->DidComposite();
|
||||
child->DidComposite(aTransactionId);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -58,7 +58,7 @@ public:
|
|||
virtual bool RecvOverfill(const uint32_t &aOverfill) MOZ_OVERRIDE;
|
||||
void AddOverfillObserver(ClientLayerManager* aLayerManager);
|
||||
|
||||
virtual bool RecvDidComposite(const uint64_t& aId) MOZ_OVERRIDE;
|
||||
virtual bool RecvDidComposite(const uint64_t& aId, const uint64_t& aTransactionId) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
// Private destructor, to discourage deletion outside of Release():
|
||||
|
|
|
@ -66,6 +66,7 @@ CompositorParent::LayerTreeState::LayerTreeState()
|
|||
: mParent(nullptr)
|
||||
, mLayerManager(nullptr)
|
||||
, mCrossProcessParent(nullptr)
|
||||
, mLayerTree(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -193,6 +194,7 @@ CompositorParent::CompositorParent(nsIWidget* aWidget,
|
|||
: mWidget(aWidget)
|
||||
, mCurrentCompositeTask(nullptr)
|
||||
, mIsTesting(false)
|
||||
, mPendingTransaction(0)
|
||||
, mPaused(false)
|
||||
, mUseExternalSurfaceSize(aUseExternalSurfaceSize)
|
||||
, mEGLSurfaceSize(aSurfaceWidth, aSurfaceHeight)
|
||||
|
@ -200,7 +202,6 @@ CompositorParent::CompositorParent(nsIWidget* aWidget,
|
|||
, mResumeCompositionMonitor("ResumeCompositionMonitor")
|
||||
, mOverrideComposeReadiness(false)
|
||||
, mForceCompositionTask(nullptr)
|
||||
, mWantDidCompositeEvent(false)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(sCompositorThread != nullptr || sCompositorThreadID,
|
||||
"The compositor thread must be Initialized before instanciating a COmpositorParent.");
|
||||
|
@ -417,6 +418,7 @@ CompositorParent::PauseComposition()
|
|||
mPaused = true;
|
||||
|
||||
mCompositor->Pause();
|
||||
DidComposite();
|
||||
}
|
||||
|
||||
// if anyone's waiting to make sure that composition really got paused, tell them
|
||||
|
@ -443,7 +445,7 @@ CompositorParent::ResumeComposition()
|
|||
|
||||
mPaused = false;
|
||||
|
||||
Composite();
|
||||
CompositeToTarget(nullptr);
|
||||
|
||||
// if anyone's waiting to make sure that composition really got resumed, tell them
|
||||
lock.NotifyAll();
|
||||
|
@ -541,8 +543,6 @@ CompositorParent::NotifyShadowTreeTransaction(uint64_t aId, bool aIsFirstPaint,
|
|||
if (aScheduleComposite) {
|
||||
ScheduleComposition();
|
||||
}
|
||||
|
||||
mWantDidCompositeEvent = true;
|
||||
}
|
||||
|
||||
// Used when layout.frame_rate is -1. Needs to be kept in sync with
|
||||
|
@ -585,7 +585,7 @@ CompositorParent::ScheduleComposition()
|
|||
rate == 0 ? 0.0 : std::max(0.0, 1000.0 / rate));
|
||||
|
||||
|
||||
mCurrentCompositeTask = NewRunnableMethod(this, &CompositorParent::Composite);
|
||||
mCurrentCompositeTask = NewRunnableMethod(this, &CompositorParent::CompositeCallback);
|
||||
|
||||
if (!initialComposition && delta < minFrameDelta) {
|
||||
TimeDuration delay = minFrameDelta - delta;
|
||||
|
@ -602,8 +602,9 @@ CompositorParent::ScheduleComposition()
|
|||
}
|
||||
|
||||
void
|
||||
CompositorParent::Composite()
|
||||
CompositorParent::CompositeCallback()
|
||||
{
|
||||
mCurrentCompositeTask = nullptr;
|
||||
CompositeToTarget(nullptr);
|
||||
}
|
||||
|
||||
|
@ -624,14 +625,10 @@ CompositorParent::CompositeToTarget(DrawTarget* aTarget, const nsIntRect* aRect)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (mCurrentCompositeTask) {
|
||||
mCurrentCompositeTask->Cancel();
|
||||
mCurrentCompositeTask = nullptr;
|
||||
}
|
||||
|
||||
mLastCompose = TimeStamp::Now();
|
||||
|
||||
if (!CanComposite()) {
|
||||
DidComposite();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -672,9 +669,8 @@ CompositorParent::CompositeToTarget(DrawTarget* aTarget, const nsIntRect* aRect)
|
|||
mLayerManager->SetDebugOverlayWantsNextFrame(false);
|
||||
mLayerManager->EndEmptyTransaction();
|
||||
|
||||
if (!aTarget && mWantDidCompositeEvent) {
|
||||
if (!aTarget) {
|
||||
DidComposite();
|
||||
mWantDidCompositeEvent = false;
|
||||
}
|
||||
|
||||
if (mLayerManager->DebugOverlayWantsNextFrame()) {
|
||||
|
@ -704,20 +700,6 @@ CompositorParent::CompositeToTarget(DrawTarget* aTarget, const nsIntRect* aRect)
|
|||
profiler_tracing("Paint", "Composite", TRACING_INTERVAL_END);
|
||||
}
|
||||
|
||||
void
|
||||
CompositorParent::DidComposite()
|
||||
{
|
||||
unused << SendDidComposite(0);
|
||||
|
||||
for (LayerTreeMap::iterator it = sIndirectLayerTrees.begin();
|
||||
it != sIndirectLayerTrees.end(); it++) {
|
||||
LayerTreeState* lts = &it->second;
|
||||
if (lts->mParent == this && lts->mCrossProcessParent) {
|
||||
unused << lts->mCrossProcessParent->SendDidComposite(it->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CompositorParent::ForceComposeToTarget(DrawTarget* aTarget, const nsIntRect* aRect)
|
||||
{
|
||||
|
@ -773,6 +755,7 @@ CompositorParent::ScheduleRotationOnCompositorThread(const TargetConfig& aTarget
|
|||
|
||||
void
|
||||
CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
|
||||
const uint64_t& aTransactionId,
|
||||
const TargetConfig& aTargetConfig,
|
||||
bool aIsFirstPaint,
|
||||
bool aScheduleComposite,
|
||||
|
@ -796,11 +779,17 @@ CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
|
|||
mRootLayerTreeID, aPaintSequenceNumber);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aTransactionId > mPendingTransaction);
|
||||
mPendingTransaction = aTransactionId;
|
||||
|
||||
if (root) {
|
||||
SetShadowProperties(root);
|
||||
}
|
||||
if (aScheduleComposite) {
|
||||
ScheduleComposition();
|
||||
if (mPaused) {
|
||||
DidComposite();
|
||||
}
|
||||
// When testing we synchronously update the shadow tree with the animated
|
||||
// values to avoid race conditions when calling GetAnimationTransform etc.
|
||||
// (since the above SetShadowProperties will remove animation effects).
|
||||
|
@ -813,11 +802,12 @@ CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
|
|||
mCompositionManager->TransformShadowTree(mTestTime);
|
||||
if (!requestNextFrame) {
|
||||
CancelCurrentCompositeTask();
|
||||
// Pretend we composited in case someone is wating for this event.
|
||||
DidComposite();
|
||||
}
|
||||
}
|
||||
}
|
||||
mLayerManager->NotifyShadowTreeTransaction();
|
||||
mWantDidCompositeEvent = true;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -843,6 +833,8 @@ CompositorParent::SetTestSampleTime(LayerTransactionParent* aLayerTree,
|
|||
bool requestNextFrame = mCompositionManager->TransformShadowTree(aTime);
|
||||
if (!requestNextFrame) {
|
||||
CancelCurrentCompositeTask();
|
||||
// Pretend we composited in case someone is wating for this event.
|
||||
DidComposite();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1151,6 +1143,7 @@ public:
|
|||
virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) MOZ_OVERRIDE;
|
||||
|
||||
virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
|
||||
const uint64_t& aTransactionId,
|
||||
const TargetConfig& aTargetConfig,
|
||||
bool aIsFirstPaint,
|
||||
bool aScheduleComposite,
|
||||
|
@ -1164,6 +1157,7 @@ public:
|
|||
|
||||
virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aParent) MOZ_OVERRIDE;
|
||||
|
||||
void DidComposite(uint64_t aId);
|
||||
private:
|
||||
// Private destructor, to discourage deletion outside of Release():
|
||||
virtual ~CrossProcessCompositorParent();
|
||||
|
@ -1179,6 +1173,23 @@ private:
|
|||
base::ProcessId mChildProcessId;
|
||||
};
|
||||
|
||||
void
|
||||
CompositorParent::DidComposite()
|
||||
{
|
||||
if (mPendingTransaction) {
|
||||
unused << SendDidComposite(0, mPendingTransaction);
|
||||
mPendingTransaction = 0;
|
||||
}
|
||||
|
||||
for (LayerTreeMap::iterator it = sIndirectLayerTrees.begin();
|
||||
it != sIndirectLayerTrees.end(); it++) {
|
||||
LayerTreeState* lts = &it->second;
|
||||
if (lts->mParent == this && lts->mCrossProcessParent) {
|
||||
static_cast<CrossProcessCompositorParent*>(lts->mCrossProcessParent)->DidComposite(it->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
OpenCompositor(CrossProcessCompositorParent* aCompositor,
|
||||
Transport* aTransport, ProcessHandle aHandle,
|
||||
|
@ -1280,6 +1291,7 @@ CrossProcessCompositorParent::AllocPLayerTransactionParent(const nsTArray<Layers
|
|||
*aSuccess = true;
|
||||
LayerTransactionParent* p = new LayerTransactionParent(lm, this, aId, mChildProcessId);
|
||||
p->AddIPDLReference();
|
||||
sIndirectLayerTrees[aId].mLayerTree = p;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -1317,6 +1329,7 @@ CrossProcessCompositorParent::RecvNotifyChildCreated(const uint64_t& child)
|
|||
void
|
||||
CrossProcessCompositorParent::ShadowLayersUpdated(
|
||||
LayerTransactionParent* aLayerTree,
|
||||
const uint64_t& aTransactionId,
|
||||
const TargetConfig& aTargetConfig,
|
||||
bool aIsFirstPaint,
|
||||
bool aScheduleComposite,
|
||||
|
@ -1341,6 +1354,17 @@ CrossProcessCompositorParent::ShadowLayersUpdated(
|
|||
|
||||
state->mParent->NotifyShadowTreeTransaction(id, aIsFirstPaint, aScheduleComposite,
|
||||
aPaintSequenceNumber);
|
||||
aLayerTree->SetPendingTransactionId(aTransactionId);
|
||||
}
|
||||
|
||||
void
|
||||
CrossProcessCompositorParent::DidComposite(uint64_t aId)
|
||||
{
|
||||
LayerTransactionParent *layerTree = sIndirectLayerTrees[aId].mLayerTree;
|
||||
if (layerTree && layerTree->GetPendingTransactionId()) {
|
||||
unused << SendDidComposite(aId, layerTree->GetPendingTransactionId());
|
||||
layerTree->SetPendingTransactionId(0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -96,6 +96,7 @@ public:
|
|||
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
|
||||
|
||||
virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
|
||||
const uint64_t& aTransactionId,
|
||||
const TargetConfig& aTargetConfig,
|
||||
bool aIsFirstPaint,
|
||||
bool aScheduleComposite,
|
||||
|
@ -226,6 +227,7 @@ public:
|
|||
PCompositorParent* mCrossProcessParent;
|
||||
TargetConfig mTargetConfig;
|
||||
APZTestData mApzTestData;
|
||||
LayerTransactionParent* mLayerTree;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -253,7 +255,7 @@ private:
|
|||
bool* aSuccess) MOZ_OVERRIDE;
|
||||
virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) MOZ_OVERRIDE;
|
||||
virtual void ScheduleTask(CancelableTask*, int);
|
||||
void Composite();
|
||||
void CompositeCallback();
|
||||
void CompositeToTarget(gfx::DrawTarget* aTarget, const nsIntRect* aRect = nullptr);
|
||||
void ForceComposeToTarget(gfx::DrawTarget* aTarget, const nsIntRect* aRect = nullptr);
|
||||
|
||||
|
@ -327,6 +329,8 @@ private:
|
|||
TimeStamp mExpectedComposeStartTime;
|
||||
#endif
|
||||
|
||||
uint64_t mPendingTransaction;
|
||||
|
||||
bool mPaused;
|
||||
|
||||
bool mUseExternalSurfaceSize;
|
||||
|
@ -343,8 +347,6 @@ private:
|
|||
|
||||
nsRefPtr<APZCTreeManager> mApzcTreeManager;
|
||||
|
||||
bool mWantDidCompositeEvent;
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(CompositorParent);
|
||||
};
|
||||
|
||||
|
|
|
@ -39,6 +39,9 @@ public:
|
|||
|
||||
bool IPCOpen() const { return mIPCOpen; }
|
||||
|
||||
void SetHasNoCompositor() { mHasNoCompositor = true; }
|
||||
bool HasNoCompositor() { return mHasNoCompositor; }
|
||||
|
||||
void SetForwarder(ShadowLayerForwarder* aForwarder)
|
||||
{
|
||||
mForwarder = aForwarder;
|
||||
|
@ -46,9 +49,10 @@ public:
|
|||
|
||||
protected:
|
||||
LayerTransactionChild()
|
||||
: mIPCOpen(false)
|
||||
: mForwarder(nullptr)
|
||||
, mIPCOpen(false)
|
||||
, mDestroyed(false)
|
||||
, mForwarder(nullptr)
|
||||
, mHasNoCompositor(false)
|
||||
{}
|
||||
~LayerTransactionChild() { }
|
||||
|
||||
|
@ -80,9 +84,10 @@ protected:
|
|||
friend class CompositorChild;
|
||||
friend class layout::RenderFrameChild;
|
||||
|
||||
ShadowLayerForwarder* mForwarder;
|
||||
bool mIPCOpen;
|
||||
bool mDestroyed;
|
||||
ShadowLayerForwarder* mForwarder;
|
||||
bool mHasNoCompositor;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
|
|
@ -148,6 +148,7 @@ LayerTransactionParent::LayerTransactionParent(LayerManagerComposite* aManager,
|
|||
: mLayerManager(aManager)
|
||||
, mShadowLayersManager(aLayersManager)
|
||||
, mId(aId)
|
||||
, mPendingTransaction(0)
|
||||
, mChildProcessId(aOtherProcess)
|
||||
, mDestroyed(false)
|
||||
, mIPCOpen(false)
|
||||
|
@ -179,17 +180,19 @@ LayerTransactionParent::GetCompositorBackendType() const
|
|||
|
||||
bool
|
||||
LayerTransactionParent::RecvUpdateNoSwap(const InfallibleTArray<Edit>& cset,
|
||||
const uint64_t& aTransactionId,
|
||||
const TargetConfig& targetConfig,
|
||||
const bool& isFirstPaint,
|
||||
const bool& scheduleComposite,
|
||||
const uint32_t& paintSequenceNumber)
|
||||
{
|
||||
return RecvUpdate(cset, targetConfig, isFirstPaint, scheduleComposite,
|
||||
paintSequenceNumber, nullptr);
|
||||
return RecvUpdate(cset, aTransactionId, targetConfig, isFirstPaint,
|
||||
scheduleComposite, paintSequenceNumber, nullptr);
|
||||
}
|
||||
|
||||
bool
|
||||
LayerTransactionParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
|
||||
const uint64_t& aTransactionId,
|
||||
const TargetConfig& targetConfig,
|
||||
const bool& isFirstPaint,
|
||||
const bool& scheduleComposite,
|
||||
|
@ -549,8 +552,8 @@ LayerTransactionParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
|
|||
// other's buffer contents.
|
||||
LayerManagerComposite::PlatformSyncBeforeReplyUpdate();
|
||||
|
||||
mShadowLayersManager->ShadowLayersUpdated(this, targetConfig, isFirstPaint,
|
||||
scheduleComposite, paintSequenceNumber);
|
||||
mShadowLayersManager->ShadowLayersUpdated(this, aTransactionId, targetConfig,
|
||||
isFirstPaint, scheduleComposite, paintSequenceNumber);
|
||||
|
||||
#ifdef COMPOSITOR_PERFORMANCE_WARNING
|
||||
int compositeTime = (int)(mozilla::TimeStamp::Now() - updateStart).ToMilliseconds();
|
||||
|
|
|
@ -81,6 +81,9 @@ public:
|
|||
|
||||
virtual bool IsSameProcess() const MOZ_OVERRIDE;
|
||||
|
||||
const uint64_t& GetPendingTransactionId() { return mPendingTransaction; }
|
||||
void SetPendingTransactionId(uint64_t aId) { mPendingTransaction = aId; }
|
||||
|
||||
// CompositableParentManager
|
||||
virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
|
||||
PTextureParent* aTexture,
|
||||
|
@ -95,6 +98,7 @@ public:
|
|||
|
||||
protected:
|
||||
virtual bool RecvUpdate(const EditArray& cset,
|
||||
const uint64_t& aTransactionId,
|
||||
const TargetConfig& targetConfig,
|
||||
const bool& isFirstPaint,
|
||||
const bool& scheduleComposite,
|
||||
|
@ -102,6 +106,7 @@ protected:
|
|||
EditReplyArray* reply) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvUpdateNoSwap(const EditArray& cset,
|
||||
const uint64_t& aTransactionId,
|
||||
const TargetConfig& targetConfig,
|
||||
const bool& isFirstPaint,
|
||||
const bool& scheduleComposite,
|
||||
|
@ -164,6 +169,8 @@ private:
|
|||
// mId != 0 => mRoot == null
|
||||
// because the "real tree" is owned by the compositor.
|
||||
uint64_t mId;
|
||||
|
||||
uint64_t mPendingTransaction;
|
||||
// When the widget/frame/browser stuff in this process begins its
|
||||
// destruction process, we need to Disconnect() all the currently
|
||||
// live shadow layers, because some of them might be orphaned from
|
||||
|
|
|
@ -42,7 +42,7 @@ child:
|
|||
// The compositor completed a layers transaction. id is the layers id
|
||||
// of the child layer tree that was composited (or 0 when notifying
|
||||
// the root layer tree).
|
||||
async DidComposite(uint64_t id);
|
||||
async DidComposite(uint64_t id, uint64_t transactionId);
|
||||
|
||||
// The parent sends the child the requested fill ratio numbers.
|
||||
async Overfill(uint32_t aOverfill);
|
||||
|
|
|
@ -52,9 +52,14 @@ parent:
|
|||
|
||||
// The isFirstPaint flag can be used to indicate that this is the first update
|
||||
// for a particular document.
|
||||
sync Update(Edit[] cset, TargetConfig targetConfig, bool isFirstPaint,
|
||||
sync Update(Edit[] cset, uint64_t id, TargetConfig targetConfig, bool isFirstPaint,
|
||||
bool scheduleComposite, uint32_t paintSequenceNumber)
|
||||
returns (EditReply[] reply);
|
||||
|
||||
// We don't need to send a sync transaction if
|
||||
// no transaction operate require a swap.
|
||||
async UpdateNoSwap(Edit[] cset, uint64_t id, TargetConfig targetConfig, bool isFirstPaint,
|
||||
bool scheduleComposite, uint32_t paintSequenceNumber);
|
||||
|
||||
// Testing APIs
|
||||
|
||||
|
@ -78,11 +83,6 @@ parent:
|
|||
// Useful for testing rendering of async scrolling.
|
||||
async SetAsyncScrollOffset(PLayer layer, int32_t x, int32_t y);
|
||||
|
||||
// We don't need to send a sync transaction if
|
||||
// no transaction operate require a swap.
|
||||
async UpdateNoSwap(Edit[] cset, TargetConfig targetConfig, bool isFirstPaint,
|
||||
bool scheduleComposite, uint32_t paintSequenceNumber);
|
||||
|
||||
// Drop any front buffers that might be retained on the compositor
|
||||
// side.
|
||||
async ClearCachedResources();
|
||||
|
|
|
@ -451,12 +451,15 @@ ShadowLayerForwarder::RemoveTexture(TextureClient* aTexture)
|
|||
bool
|
||||
ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies,
|
||||
const nsIntRegion& aRegionToClear,
|
||||
uint64_t aId,
|
||||
bool aScheduleComposite,
|
||||
uint32_t aPaintSequenceNumber,
|
||||
bool* aSent)
|
||||
{
|
||||
*aSent = false;
|
||||
|
||||
MOZ_ASSERT(aId);
|
||||
|
||||
PROFILER_LABEL("ShadowLayerForwarder", "EndTranscation");
|
||||
RenderTraceScope rendertrace("Foward Transaction", "000091");
|
||||
NS_ABORT_IF_FALSE(HasShadowManager(), "no manager to forward to");
|
||||
|
@ -562,7 +565,7 @@ ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies,
|
|||
RenderTraceScope rendertrace3("Forward Transaction", "000093");
|
||||
if (!HasShadowManager() ||
|
||||
!mShadowManager->IPCOpen() ||
|
||||
!mShadowManager->SendUpdate(cset, targetConfig, mIsFirstPaint,
|
||||
!mShadowManager->SendUpdate(cset, aId, targetConfig, mIsFirstPaint,
|
||||
aScheduleComposite, aPaintSequenceNumber,
|
||||
aReplies)) {
|
||||
MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
|
||||
|
@ -575,7 +578,7 @@ ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies,
|
|||
RenderTraceScope rendertrace3("Forward NoSwap Transaction", "000093");
|
||||
if (!HasShadowManager() ||
|
||||
!mShadowManager->IPCOpen() ||
|
||||
!mShadowManager->SendUpdateNoSwap(cset, targetConfig, mIsFirstPaint,
|
||||
!mShadowManager->SendUpdateNoSwap(cset, aId, targetConfig, mIsFirstPaint,
|
||||
aPaintSequenceNumber, aScheduleComposite)) {
|
||||
MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
|
||||
return false;
|
||||
|
|
|
@ -295,6 +295,7 @@ public:
|
|||
*/
|
||||
bool EndTransaction(InfallibleTArray<EditReply>* aReplies,
|
||||
const nsIntRegion& aRegionToClear,
|
||||
uint64_t aId,
|
||||
bool aScheduleComposite,
|
||||
uint32_t aPaintSequenceNumber,
|
||||
bool* aSent);
|
||||
|
|
|
@ -19,6 +19,7 @@ class ShadowLayersManager
|
|||
{
|
||||
public:
|
||||
virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
|
||||
const uint64_t& aTransactionId,
|
||||
const TargetConfig& aTargetConfig,
|
||||
bool aIsFirstPaint,
|
||||
bool aScheduleComposite,
|
||||
|
|
|
@ -163,6 +163,7 @@ EXPORTS.mozilla.layers += [
|
|||
'opengl/TextureClientOGL.h',
|
||||
'opengl/TextureHostOGL.h',
|
||||
'RenderTrace.h',
|
||||
'TransactionIdAllocator.h',
|
||||
'YCbCrImageDataSerializer.h',
|
||||
]
|
||||
|
||||
|
|
|
@ -127,10 +127,6 @@ CompositorOGL::CreateContext()
|
|||
void
|
||||
CompositorOGL::Destroy()
|
||||
{
|
||||
if (gl() && gl()->MakeCurrent()) {
|
||||
mVBOs.Flush(gl());
|
||||
}
|
||||
|
||||
if (mTexturePool) {
|
||||
mTexturePool->Clear();
|
||||
mTexturePool = nullptr;
|
||||
|
@ -683,8 +679,6 @@ CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
|
|||
|
||||
LayerScope::BeginFrame(mGLContext, PR_Now());
|
||||
|
||||
mVBOs.Reset();
|
||||
|
||||
mFrameInProgress = true;
|
||||
gfx::Rect rect;
|
||||
if (mUseExternalSurfaceSize) {
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include "nsThreadUtils.h" // for nsRunnable
|
||||
#include "nsXULAppAPI.h" // for XRE_GetProcessType
|
||||
#include "nscore.h" // for NS_IMETHOD
|
||||
#include "VBOArena.h" // for gl::VBOArena
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include <ui/GraphicBuffer.h>
|
||||
#endif
|
||||
|
@ -302,11 +301,6 @@ private:
|
|||
*/
|
||||
GLuint mQuadVBO;
|
||||
|
||||
/**
|
||||
* When we can't use mQuadVBO, we allocate VBOs from this arena instead.
|
||||
*/
|
||||
gl::VBOArena mVBOs;
|
||||
|
||||
bool mHasBGRA;
|
||||
|
||||
/**
|
||||
|
|
|
@ -116,18 +116,6 @@ FlagsToGLFlags(TextureFlags aFlags)
|
|||
return static_cast<gl::TextureImage::Flags>(result);
|
||||
}
|
||||
|
||||
static GLenum
|
||||
WrapMode(gl::GLContext *aGl, TextureFlags aFlags)
|
||||
{
|
||||
if ((aFlags & TextureFlags::ALLOW_REPEAT) &&
|
||||
(aGl->IsExtensionSupported(GLContext::ARB_texture_non_power_of_two) ||
|
||||
aGl->IsExtensionSupported(GLContext::OES_texture_npot) ||
|
||||
aGl->IsExtensionSupported(GLContext::IMG_texture_npot))) {
|
||||
return LOCAL_GL_REPEAT;
|
||||
}
|
||||
return LOCAL_GL_CLAMP_TO_EDGE;
|
||||
}
|
||||
|
||||
CompositableDataGonkOGL::CompositableDataGonkOGL()
|
||||
: mTexture(0)
|
||||
, mBoundEGLImage(EGL_NO_IMAGE)
|
||||
|
@ -262,7 +250,7 @@ TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
|
|||
// texture image.
|
||||
mTexImage = CreateBasicTextureImage(mGL, size,
|
||||
gfx::ContentForFormat(aSurface->GetFormat()),
|
||||
WrapMode(mGL, mFlags),
|
||||
LOCAL_GL_CLAMP_TO_EDGE,
|
||||
FlagsToGLFlags(mFlags),
|
||||
SurfaceFormatToImageFormat(aSurface->GetFormat()));
|
||||
} else {
|
||||
|
@ -273,7 +261,7 @@ TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
|
|||
mTexImage = CreateTextureImage(mGL,
|
||||
size,
|
||||
gfx::ContentForFormat(aSurface->GetFormat()),
|
||||
WrapMode(mGL, mFlags),
|
||||
LOCAL_GL_CLAMP_TO_EDGE,
|
||||
FlagsToGLFlags(mFlags),
|
||||
SurfaceFormatToImageFormat(aSurface->GetFormat()));
|
||||
}
|
||||
|
@ -298,7 +286,7 @@ TextureImageTextureSourceOGL::EnsureBuffer(const nsIntSize& aSize,
|
|||
mTexImage = CreateTextureImage(mGL,
|
||||
aSize.ToIntSize(),
|
||||
aContentType,
|
||||
WrapMode(mGL, mFlags),
|
||||
LOCAL_GL_CLAMP_TO_EDGE,
|
||||
FlagsToGLFlags(mFlags));
|
||||
}
|
||||
mTexImage->Resize(aSize.ToIntSize());
|
||||
|
|
|
@ -25,6 +25,9 @@ class JavaScriptChild : public JavaScriptBase<PJavaScriptChild>
|
|||
|
||||
void drop(JSObject *obj);
|
||||
|
||||
protected:
|
||||
virtual bool isParent() { return false; }
|
||||
|
||||
private:
|
||||
bool fail(JSContext *cx, ReturnStatus *rs);
|
||||
bool ok(ReturnStatus *rs);
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
/* -*- 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_JavaScriptLogging__
|
||||
#define mozilla_jsipc_JavaScriptLogging__
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
#define LOG(...) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (LoggingEnabled()) { \
|
||||
Logging log(this, cx); \
|
||||
log.print(__VA_ARGS__); \
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
#define LOG_STACK() \
|
||||
PR_BEGIN_MACRO \
|
||||
if (StackLoggingEnabled()) { \
|
||||
js_DumpBacktrace(cx); \
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
struct ReceiverObj
|
||||
{
|
||||
ObjectId id;
|
||||
ReceiverObj(ObjectId id) : id(id) {}
|
||||
};
|
||||
|
||||
struct InVariant
|
||||
{
|
||||
JSVariant variant;
|
||||
InVariant(const JSVariant &variant) : variant(variant) {}
|
||||
};
|
||||
|
||||
struct OutVariant
|
||||
{
|
||||
JSVariant variant;
|
||||
OutVariant(const JSVariant &variant) : variant(variant) {}
|
||||
};
|
||||
|
||||
class Logging
|
||||
{
|
||||
public:
|
||||
Logging(JavaScriptShared *shared, JSContext *cx) : shared(shared), cx(cx) {}
|
||||
|
||||
void print(const nsCString &str) {
|
||||
const char *side = shared->isParent() ? "from child" : "from parent";
|
||||
printf("CPOW %s: %s\n", side, str.get());
|
||||
}
|
||||
|
||||
void print(const char *str) {
|
||||
print(nsCString(str));
|
||||
}
|
||||
template<typename T1>
|
||||
void print(const char *fmt, const T1 &a1) {
|
||||
nsAutoCString tmp1;
|
||||
format(a1, tmp1);
|
||||
print(nsPrintfCString(fmt, tmp1.get()));
|
||||
}
|
||||
template<typename T1, typename T2>
|
||||
void print(const char *fmt, const T1 &a1, const T2 &a2) {
|
||||
nsAutoCString tmp1;
|
||||
nsAutoCString tmp2;
|
||||
format(a1, tmp1);
|
||||
format(a2, tmp2);
|
||||
print(nsPrintfCString(fmt, tmp1.get(), tmp2.get()));
|
||||
}
|
||||
template<typename T1, typename T2, typename T3>
|
||||
void print(const char *fmt, const T1 &a1, const T2 &a2, const T3 &a3) {
|
||||
nsAutoCString tmp1;
|
||||
nsAutoCString tmp2;
|
||||
nsAutoCString tmp3;
|
||||
format(a1, tmp1);
|
||||
format(a2, tmp2);
|
||||
format(a3, tmp3);
|
||||
print(nsPrintfCString(fmt, tmp1.get(), tmp2.get(), tmp3.get()));
|
||||
}
|
||||
|
||||
void format(const nsString &str, nsCString &out) {
|
||||
out = NS_ConvertUTF16toUTF8(str);
|
||||
}
|
||||
|
||||
void formatObject(bool incoming, bool local, ObjectId id, nsCString &out) {
|
||||
const char *side, *objDesc;
|
||||
|
||||
if (local == incoming) {
|
||||
JS::RootedObject obj(cx);
|
||||
obj = shared->findObjectById(id);
|
||||
if (obj) {
|
||||
JSAutoCompartment ac(cx, obj);
|
||||
objDesc = js_ObjectClassName(cx, obj);
|
||||
} else {
|
||||
objDesc = "<dead object>";
|
||||
}
|
||||
|
||||
side = shared->isParent() ? "parent" : "child";
|
||||
} else {
|
||||
objDesc = "<cpow>";
|
||||
side = shared->isParent() ? "child" : "parent";
|
||||
}
|
||||
|
||||
out = nsPrintfCString("<%s %s:%d>", side, objDesc, id);
|
||||
}
|
||||
|
||||
|
||||
void format(const ReceiverObj &obj, nsCString &out) {
|
||||
formatObject(true, true, obj.id, out);
|
||||
}
|
||||
|
||||
void format(const nsTArray<JSParam> &values, nsCString &out) {
|
||||
nsAutoCString tmp;
|
||||
out.Truncate();
|
||||
for (size_t i = 0; i < values.Length(); i++) {
|
||||
if (i)
|
||||
out.AppendLiteral(", ");
|
||||
if (values[i].type() == JSParam::Tvoid_t) {
|
||||
out.AppendLiteral("<void>");
|
||||
} else {
|
||||
format(InVariant(values[i].get_JSVariant()), tmp);
|
||||
out += tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void format(const InVariant &value, nsCString &out) {
|
||||
format(true, value.variant, out);
|
||||
}
|
||||
|
||||
void format(const OutVariant &value, nsCString &out) {
|
||||
format(false, value.variant, out);
|
||||
}
|
||||
|
||||
void format(bool incoming, const JSVariant &value, nsCString &out) {
|
||||
switch (value.type()) {
|
||||
case JSVariant::TUndefinedVariant: {
|
||||
out = "undefined";
|
||||
break;
|
||||
}
|
||||
case JSVariant::TNullVariant: {
|
||||
out = "null";
|
||||
break;
|
||||
}
|
||||
case JSVariant::TnsString: {
|
||||
nsAutoCString tmp;
|
||||
format(value.get_nsString(), tmp);
|
||||
out = nsPrintfCString("\"%s\"", tmp.get());
|
||||
break;
|
||||
}
|
||||
case JSVariant::TObjectVariant: {
|
||||
const ObjectVariant &ovar = value.get_ObjectVariant();
|
||||
if (ovar.type() == ObjectVariant::TLocalObject)
|
||||
formatObject(incoming, true, ovar.get_LocalObject().id(), out);
|
||||
else
|
||||
formatObject(incoming, false, ovar.get_RemoteObject().id(), out);
|
||||
break;
|
||||
}
|
||||
case JSVariant::Tdouble: {
|
||||
out = nsPrintfCString("%.0f", value.get_double());
|
||||
break;
|
||||
}
|
||||
case JSVariant::Tbool: {
|
||||
out = value.get_bool() ? "true" : "false";
|
||||
break;
|
||||
}
|
||||
case JSVariant::TJSIID: {
|
||||
out = "<JSIID>";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
out = "<JSIID>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
JavaScriptShared *shared;
|
||||
JSContext *cx;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -27,6 +27,9 @@ class JavaScriptParent : public JavaScriptBase<PJavaScriptParent>
|
|||
|
||||
mozilla::ipc::IProtocol*
|
||||
CloneProtocol(Channel* aChannel, ProtocolCloneContext* aCtx) MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
virtual bool isParent() { return true; }
|
||||
};
|
||||
|
||||
} // jsipc
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "mozilla/dom/TabChild.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "xpcprivate.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace JS;
|
||||
|
@ -144,11 +145,22 @@ ObjectToIdMap::remove(JSObject *obj)
|
|||
table_->remove(obj);
|
||||
}
|
||||
|
||||
bool JavaScriptShared::sLoggingInitialized;
|
||||
bool JavaScriptShared::sLoggingEnabled;
|
||||
bool JavaScriptShared::sStackLoggingEnabled;
|
||||
|
||||
JavaScriptShared::JavaScriptShared(JSRuntime *rt)
|
||||
: rt_(rt),
|
||||
refcount_(1),
|
||||
lastId_(0)
|
||||
{
|
||||
if (!sLoggingInitialized) {
|
||||
sLoggingInitialized = true;
|
||||
Preferences::AddBoolVarCache(&sLoggingEnabled,
|
||||
"dom.ipc.cpows.log.enabled", false);
|
||||
Preferences::AddBoolVarCache(&sStackLoggingEnabled,
|
||||
"dom.ipc.cpows.log.stack", false);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -81,6 +81,8 @@ class ObjectToIdMap
|
|||
Table *table_;
|
||||
};
|
||||
|
||||
class Logging;
|
||||
|
||||
class JavaScriptShared
|
||||
{
|
||||
public:
|
||||
|
@ -124,6 +126,13 @@ class JavaScriptShared
|
|||
}
|
||||
JSObject *findObjectById(JSContext *cx, uint32_t objId);
|
||||
|
||||
static bool LoggingEnabled() { return sLoggingEnabled; }
|
||||
static bool StackLoggingEnabled() { return sStackLoggingEnabled; }
|
||||
|
||||
friend class Logging;
|
||||
|
||||
virtual bool isParent() = 0;
|
||||
|
||||
protected:
|
||||
JSRuntime *rt_;
|
||||
uintptr_t refcount_;
|
||||
|
@ -133,6 +142,10 @@ class JavaScriptShared
|
|||
|
||||
ObjectId lastId_;
|
||||
ObjectToIdMap objectIds_;
|
||||
|
||||
static bool sLoggingInitialized;
|
||||
static bool sLoggingEnabled;
|
||||
static bool sStackLoggingEnabled;
|
||||
};
|
||||
|
||||
// Use 47 at most, to be safe, since jsval privates are encoded as doubles.
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WrapperAnswer.h"
|
||||
#include "JavaScriptLogging.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
@ -71,6 +72,8 @@ WrapperAnswer::AnswerPreventExtensions(const ObjectId &objId, ReturnStatus *rs)
|
|||
if (!JS_PreventExtensions(cx, obj))
|
||||
return fail(cx, rs);
|
||||
|
||||
LOG("%s.preventExtensions()", ReceiverObj(objId));
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
|
@ -99,6 +102,8 @@ WrapperAnswer::AnswerGetPropertyDescriptor(const ObjectId &objId, const nsString
|
|||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
LOG("%s.getPropertyDescriptor(%s)", ReceiverObj(objId), id);
|
||||
|
||||
RootedId internedId(cx);
|
||||
if (!convertGeckoStringToId(cx, id, &internedId))
|
||||
return fail(cx, rs);
|
||||
|
@ -131,6 +136,8 @@ WrapperAnswer::AnswerGetOwnPropertyDescriptor(const ObjectId &objId, const nsStr
|
|||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
LOG("%s.getOwnPropertyDescriptor(%s)", ReceiverObj(objId), id);
|
||||
|
||||
RootedId internedId(cx);
|
||||
if (!convertGeckoStringToId(cx, id, &internedId))
|
||||
return fail(cx, rs);
|
||||
|
@ -161,6 +168,8 @@ WrapperAnswer::AnswerDefineProperty(const ObjectId &objId, const nsString &id,
|
|||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
LOG("define %s[%s]", ReceiverObj(objId), id);
|
||||
|
||||
RootedId internedId(cx);
|
||||
if (!convertGeckoStringToId(cx, id, &internedId))
|
||||
return fail(cx, rs);
|
||||
|
@ -199,6 +208,8 @@ WrapperAnswer::AnswerDelete(const ObjectId &objId, const nsString &id, ReturnSta
|
|||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
LOG("delete %s[%s]", ReceiverObj(objId), id);
|
||||
|
||||
RootedId internedId(cx);
|
||||
if (!convertGeckoStringToId(cx, id, &internedId))
|
||||
return fail(cx, rs);
|
||||
|
@ -223,6 +234,8 @@ WrapperAnswer::AnswerHas(const ObjectId &objId, const nsString &id, ReturnStatus
|
|||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
LOG("%s.has(%s)", ReceiverObj(objId), id);
|
||||
|
||||
RootedId internedId(cx);
|
||||
if (!convertGeckoStringToId(cx, id, &internedId))
|
||||
return fail(cx, rs);
|
||||
|
@ -249,6 +262,8 @@ WrapperAnswer::AnswerHasOwn(const ObjectId &objId, const nsString &id, ReturnSta
|
|||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
LOG("%s.hasOwn(%s)", ReceiverObj(objId), id);
|
||||
|
||||
RootedId internedId(cx);
|
||||
if (!convertGeckoStringToId(cx, id, &internedId))
|
||||
return fail(cx, rs);
|
||||
|
@ -293,6 +308,8 @@ WrapperAnswer::AnswerGet(const ObjectId &objId, const ObjectId &receiverId, cons
|
|||
if (!toVariant(cx, val, result))
|
||||
return fail(cx, rs);
|
||||
|
||||
LOG("get %s.%s = %s", ReceiverObj(objId), id, OutVariant(*result));
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
|
@ -318,6 +335,8 @@ WrapperAnswer::AnswerSet(const ObjectId &objId, const ObjectId &receiverId, cons
|
|||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
LOG("set %s[%s] = %s", ReceiverObj(objId), id, InVariant(value));
|
||||
|
||||
RootedId internedId(cx);
|
||||
if (!convertGeckoStringToId(cx, id, &internedId))
|
||||
return fail(cx, rs);
|
||||
|
@ -351,6 +370,8 @@ WrapperAnswer::AnswerIsExtensible(const ObjectId &objId, ReturnStatus *rs, bool
|
|||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
LOG("%s.isExtensible()", ReceiverObj(objId));
|
||||
|
||||
bool extensible;
|
||||
if (!JS_IsExtensible(cx, obj, &extensible))
|
||||
return fail(cx, rs);
|
||||
|
@ -453,6 +474,8 @@ WrapperAnswer::AnswerCall(const ObjectId &objId, const nsTArray<JSParam> &argv,
|
|||
outparams->ReplaceElementAt(i, JSParam(variant));
|
||||
}
|
||||
|
||||
LOG("%s.call(%s) = %s", ReceiverObj(objId), argv, OutVariant(*result));
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
|
@ -472,6 +495,8 @@ WrapperAnswer::AnswerObjectClassIs(const ObjectId &objId, const uint32_t &classV
|
|||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
LOG("%s.objectClassIs()", ReceiverObj(objId));
|
||||
|
||||
*result = js_ObjectClassIs(cx, obj, (js::ESClassValue)classValue);
|
||||
return true;
|
||||
}
|
||||
|
@ -490,6 +515,8 @@ WrapperAnswer::AnswerClassName(const ObjectId &objId, nsString *name)
|
|||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
LOG("%s.className()", ReceiverObj(objId));
|
||||
|
||||
*name = NS_ConvertASCIItoUTF16(js_ObjectClassName(cx, obj));
|
||||
return true;
|
||||
}
|
||||
|
@ -507,6 +534,8 @@ WrapperAnswer::AnswerGetPropertyNames(const ObjectId &objId, const uint32_t &fla
|
|||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
LOG("%s.getPropertyNames()", ReceiverObj(objId));
|
||||
|
||||
AutoIdVector props(cx);
|
||||
if (!js::GetPropertyNames(cx, obj, flags, &props))
|
||||
return fail(cx, rs);
|
||||
|
@ -537,6 +566,8 @@ WrapperAnswer::AnswerInstanceOf(const ObjectId &objId, const JSIID &iid, ReturnS
|
|||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
LOG("%s.instanceOf()", ReceiverObj(objId));
|
||||
|
||||
nsID nsiid;
|
||||
ConvertID(iid, &nsiid);
|
||||
|
||||
|
@ -563,6 +594,8 @@ WrapperAnswer::AnswerDOMInstanceOf(const ObjectId &objId, const int &prototypeID
|
|||
|
||||
JSAutoCompartment comp(cx, obj);
|
||||
|
||||
LOG("%s.domInstanceOf()", ReceiverObj(objId));
|
||||
|
||||
bool tmp;
|
||||
if (!mozilla::dom::InterfaceHasInstance(cx, prototypeID, depth, obj, &tmp))
|
||||
return fail(cx, rs);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WrapperOwner.h"
|
||||
#include "JavaScriptLogging.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
@ -111,6 +112,8 @@ WrapperOwner::preventExtensions(JSContext *cx, HandleObject proxy)
|
|||
if (!CallPreventExtensions(objId, &status))
|
||||
return ipcfail(cx);
|
||||
|
||||
LOG_STACK();
|
||||
|
||||
return ok(cx, status);
|
||||
}
|
||||
|
||||
|
@ -135,6 +138,9 @@ WrapperOwner::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId
|
|||
PPropertyDescriptor result;
|
||||
if (!CallGetPropertyDescriptor(objId, idstr, &status, &result))
|
||||
return ipcfail(cx);
|
||||
|
||||
LOG_STACK();
|
||||
|
||||
if (!ok(cx, status))
|
||||
return false;
|
||||
|
||||
|
@ -162,6 +168,9 @@ WrapperOwner::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, Handle
|
|||
PPropertyDescriptor result;
|
||||
if (!CallGetOwnPropertyDescriptor(objId, idstr, &status, &result))
|
||||
return ipcfail(cx);
|
||||
|
||||
LOG_STACK();
|
||||
|
||||
if (!ok(cx, status))
|
||||
return false;
|
||||
|
||||
|
@ -193,6 +202,8 @@ WrapperOwner::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
|
|||
if (!CallDefineProperty(objId, idstr, descriptor, &status))
|
||||
return ipcfail(cx);
|
||||
|
||||
LOG_STACK();
|
||||
|
||||
return ok(cx, status);
|
||||
}
|
||||
|
||||
|
@ -227,6 +238,8 @@ WrapperOwner::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
|
|||
if (!CallDelete(objId, idstr, &status, bp))
|
||||
return ipcfail(cx);
|
||||
|
||||
LOG_STACK();
|
||||
|
||||
return ok(cx, status);
|
||||
}
|
||||
|
||||
|
@ -261,6 +274,8 @@ WrapperOwner::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
|
|||
if (!CallHas(objId, idstr, &status, bp))
|
||||
return ipcfail(cx);
|
||||
|
||||
LOG_STACK();
|
||||
|
||||
return ok(cx, status);
|
||||
}
|
||||
|
||||
|
@ -283,6 +298,8 @@ WrapperOwner::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
|
|||
if (!CallHasOwn(objId, idstr, &status, bp))
|
||||
return ipcfail(cx);
|
||||
|
||||
LOG_STACK();
|
||||
|
||||
return !!ok(cx, status);
|
||||
}
|
||||
|
||||
|
@ -293,6 +310,60 @@ CPOWProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
|
|||
FORWARD(get, (cx, proxy, receiver, id, vp));
|
||||
}
|
||||
|
||||
static bool
|
||||
CPOWToString(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
RootedObject callee(cx, &args.callee());
|
||||
RootedValue cpowValue(cx);
|
||||
if (!JS_LookupProperty(cx, callee, "__cpow__", &cpowValue))
|
||||
return false;
|
||||
|
||||
if (!cpowValue.isObject() || !IsCPOW(&cpowValue.toObject())) {
|
||||
JS_ReportError(cx, "CPOWToString called on an incompatible object");
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject proxy(cx, &cpowValue.toObject());
|
||||
FORWARD(toString, (cx, proxy, args));
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperOwner::toString(JSContext *cx, HandleObject cpow, JS::CallArgs &args)
|
||||
{
|
||||
// Ask the other side to call its toString method. Update the callee so that
|
||||
// it points to the CPOW and not to the synthesized CPOWToString function.
|
||||
args.setCallee(ObjectValue(*cpow));
|
||||
if (!call(cx, cpow, args))
|
||||
return false;
|
||||
|
||||
if (!args.rval().isString())
|
||||
return true;
|
||||
|
||||
RootedString cpowResult(cx, args.rval().toString());
|
||||
nsDependentJSString toStringResult;
|
||||
if (!toStringResult.init(cx, cpowResult))
|
||||
return false;
|
||||
|
||||
// We don't want to wrap toString() results for things like the location
|
||||
// object, where toString() is supposed to return a URL and nothing else.
|
||||
nsAutoString result;
|
||||
if (toStringResult[0] == '[') {
|
||||
result.AppendLiteral("[object CPOW ");
|
||||
result += toStringResult;
|
||||
result.AppendLiteral("]");
|
||||
} else {
|
||||
result += toStringResult;
|
||||
}
|
||||
|
||||
JSString *str = JS_NewUCStringCopyN(cx, result.get(), result.Length());
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
args.rval().setString(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperOwner::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
|
||||
HandleId id, MutableHandleValue vp)
|
||||
|
@ -309,10 +380,28 @@ WrapperOwner::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
|
|||
if (!CallGet(objId, receiverId, idstr, &status, &val))
|
||||
return ipcfail(cx);
|
||||
|
||||
LOG_STACK();
|
||||
|
||||
if (!ok(cx, status))
|
||||
return false;
|
||||
|
||||
return fromVariant(cx, val, vp);
|
||||
if (!fromVariant(cx, val, vp))
|
||||
return false;
|
||||
|
||||
if (idstr.EqualsLiteral("toString")) {
|
||||
RootedFunction toString(cx, JS_NewFunction(cx, CPOWToString, 0, 0, proxy, "toString"));
|
||||
if (!toString)
|
||||
return false;
|
||||
|
||||
RootedObject toStringObj(cx, JS_GetFunctionObject(toString));
|
||||
|
||||
if (!JS_DefineProperty(cx, toStringObj, "__cpow__", vp, JSPROP_PERMANENT | JSPROP_READONLY))
|
||||
return false;
|
||||
|
||||
vp.set(ObjectValue(*toStringObj));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -342,6 +431,8 @@ WrapperOwner::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiv
|
|||
if (!CallSet(objId, receiverId, idstr, strict, val, &status, &result))
|
||||
return ipcfail(cx);
|
||||
|
||||
LOG_STACK();
|
||||
|
||||
if (!ok(cx, status))
|
||||
return false;
|
||||
|
||||
|
@ -375,6 +466,8 @@ WrapperOwner::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible)
|
|||
if (!CallIsExtensible(objId, &status, extensible))
|
||||
return ipcfail(cx);
|
||||
|
||||
LOG_STACK();
|
||||
|
||||
return ok(cx, status);
|
||||
}
|
||||
|
||||
|
@ -424,6 +517,9 @@ WrapperOwner::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
|
|||
InfallibleTArray<JSParam> outparams;
|
||||
if (!CallCall(objId, vals, &status, &result, &outparams))
|
||||
return ipcfail(cx);
|
||||
|
||||
LOG_STACK();
|
||||
|
||||
if (!ok(cx, status))
|
||||
return false;
|
||||
|
||||
|
@ -470,6 +566,8 @@ WrapperOwner::objectClassIs(JSContext *cx, HandleObject proxy, js::ESClassValue
|
|||
if (!CallObjectClassIs(objId, classValue, &result))
|
||||
return false;
|
||||
|
||||
LOG_STACK();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -491,6 +589,8 @@ WrapperOwner::className(JSContext *cx, HandleObject proxy)
|
|||
if (!CallClassName(objId, &name))
|
||||
return "<error>";
|
||||
|
||||
LOG_STACK();
|
||||
|
||||
return ToNewCString(name);
|
||||
}
|
||||
|
||||
|
@ -529,6 +629,9 @@ WrapperOwner::getPropertyNames(JSContext *cx, HandleObject proxy, uint32_t flags
|
|||
InfallibleTArray<nsString> names;
|
||||
if (!CallGetPropertyNames(objId, flags, &status, &names))
|
||||
return ipcfail(cx);
|
||||
|
||||
LOG_STACK();
|
||||
|
||||
if (!ok(cx, status))
|
||||
return false;
|
||||
|
||||
|
@ -597,6 +700,8 @@ WrapperOwner::domInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int d
|
|||
if (!CallDOMInstanceOf(objId, prototypeID, depth, &status, bp))
|
||||
return ipcfail(cx);
|
||||
|
||||
LOG_STACK();
|
||||
|
||||
return ok(cx, status);
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,8 @@ class WrapperOwner : public virtual JavaScriptShared
|
|||
|
||||
nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp);
|
||||
|
||||
bool toString(JSContext *cx, JS::HandleObject callee, JS::CallArgs &args);
|
||||
|
||||
/*
|
||||
* Check that |obj| is a DOM wrapper whose prototype chain contains
|
||||
* |prototypeID| at depth |depth|.
|
||||
|
|
|
@ -144,18 +144,30 @@ class GCRuntime
|
|||
#ifdef JS_THREADSAFE
|
||||
void notifyRequestEnd() { conservativeGC.updateForRequestEnd(); }
|
||||
#endif
|
||||
bool isBackgroundSweeping() { return helperThread.sweeping(); }
|
||||
void waitBackgroundSweepEnd() { helperThread.waitBackgroundSweepEnd(); }
|
||||
void waitBackgroundSweepOrAllocEnd() { helperThread.waitBackgroundSweepOrAllocEnd(); }
|
||||
void startBackgroundShrink() { helperThread.startBackgroundShrink(); }
|
||||
void freeLater(void *p) { helperThread.freeLater(p); }
|
||||
bool isBackgroundSweeping() { return helperState.isBackgroundSweeping(); }
|
||||
void waitBackgroundSweepEnd() { helperState.waitBackgroundSweepEnd(); }
|
||||
void waitBackgroundSweepOrAllocEnd() { helperState.waitBackgroundSweepOrAllocEnd(); }
|
||||
void startBackgroundShrink() { helperState.startBackgroundShrink(); }
|
||||
void startBackgroundAllocationIfIdle() { helperState.startBackgroundAllocationIfIdle(); }
|
||||
void freeLater(void *p) { helperState.freeLater(p); }
|
||||
|
||||
#ifdef DEBUG
|
||||
bool onBackgroundThread() { return helperThread.onBackgroundThread(); }
|
||||
|
||||
bool onBackgroundThread() { return helperState.onBackgroundThread(); }
|
||||
|
||||
bool currentThreadOwnsGCLock() {
|
||||
#ifdef JS_THREADSAFE
|
||||
return lockOwner == PR_GetCurrentThread();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
void assertCanLock() {
|
||||
JS_ASSERT(lockOwner != PR_GetCurrentThread());
|
||||
JS_ASSERT(!currentThreadOwnsGCLock());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -203,7 +215,7 @@ class GCRuntime
|
|||
private:
|
||||
// For ArenaLists::allocateFromArenaInline()
|
||||
friend class ArenaLists;
|
||||
Chunk *pickChunk(Zone *zone);
|
||||
Chunk *pickChunk(Zone *zone, AutoMaybeStartBackgroundAllocation &maybeStartBackgroundAllocation);
|
||||
|
||||
inline bool wantBackgroundAllocation() const;
|
||||
|
||||
|
@ -533,16 +545,16 @@ class GCRuntime
|
|||
size_t noGCOrAllocationCheck;
|
||||
#endif
|
||||
|
||||
/* Synchronize GC heap access between main thread and GCHelperThread. */
|
||||
/* Synchronize GC heap access between main thread and GCHelperState. */
|
||||
PRLock *lock;
|
||||
mozilla::DebugOnly<PRThread *> lockOwner;
|
||||
|
||||
js::GCHelperThread helperThread;
|
||||
GCHelperState helperState;
|
||||
|
||||
ConservativeGCData conservativeGC;
|
||||
|
||||
//friend class js::gc::Chunk; // todo: remove
|
||||
friend class js::GCHelperThread;
|
||||
friend class js::GCHelperState;
|
||||
friend class js::gc::MarkingValidator;
|
||||
};
|
||||
|
||||
|
|
|
@ -544,99 +544,34 @@ assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'var i=
|
|||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'var i=0; function f() { var x = 0, y = 0; u8[0] = 1; u8[1] = 2; x = 0|u8[i]; y = 0|u8[i]; return (x+y)|0;} return f'), this, null, buf)(),2);
|
||||
|
||||
// Heap length constraints
|
||||
var buf = new ArrayBuffer(0x0fff);
|
||||
assertAsmLinkAlwaysFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
|
||||
var buf = new ArrayBuffer(0x1000);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
|
||||
var buf = new ArrayBuffer(0x1010);
|
||||
assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
|
||||
var buf = new ArrayBuffer(0x2000);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
|
||||
var buf = new ArrayBuffer(0xfe000);
|
||||
new Uint8Array(buf)[0xfdfff] = 0xAA;
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xfdfff),0xAA);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xfe000),0);
|
||||
var buf = new ArrayBuffer(0xfe010);
|
||||
assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
|
||||
var buf = new ArrayBuffer(0xff000);
|
||||
new Uint8Array(buf)[0xfefff] = 0xAA;
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xfefff),0xAA);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xff000),0);
|
||||
var buf = new ArrayBuffer(0xff800);
|
||||
assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
|
||||
var m = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f');
|
||||
assertAsmLinkAlwaysFail(m, this, null, new ArrayBuffer(0x0fff));
|
||||
assertEq(asmLink(m, this, null, new ArrayBuffer(0x1000))(0),0);
|
||||
assertAsmLinkFail(m, this, null, new ArrayBuffer(0x1010));
|
||||
assertEq(asmLink(m, this, null, new ArrayBuffer(0x2000))(0),0);
|
||||
assertAsmLinkFail(m, this, null, new ArrayBuffer(0xfe000));
|
||||
assertAsmLinkFail(m, this, null, new ArrayBuffer(0xfe010));
|
||||
assertAsmLinkFail(m, this, null, new ArrayBuffer(0xfe000));
|
||||
assertAsmLinkFail(m, this, null, new ArrayBuffer(0xff800));
|
||||
var buf = new ArrayBuffer(0x100000);
|
||||
new Uint8Array(buf)[0xfffff] = 0xAA;
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xfffff),0xAA);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x100000),0);
|
||||
var buf = new ArrayBuffer(0x104000);
|
||||
new Uint8Array(buf)[0x103fff] = 0xAA;
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x103fff]|0; } return f'), this, null, buf)(),0xAA);
|
||||
var buf = new ArrayBuffer(0x3f8000);
|
||||
new Uint8Array(buf)[0x3f7fff] = 0xAA;
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3f7fff),0xAA);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3f8000),0);
|
||||
var buf = new ArrayBuffer(0x3fc000); // 4080K
|
||||
new Uint8Array(buf)[0x3fbfff] = 0xAA;
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fbfff),0xAA);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fc000),0);
|
||||
var buf = new ArrayBuffer(0x3fe000);
|
||||
assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
|
||||
var buf = new ArrayBuffer(0x410000);
|
||||
new Uint8Array(buf)[0x40ffff] = 0xAA;
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x40ffff]|0; } return f'), this, null, buf)(),0xAA);
|
||||
// The rest are getting too large for regular testing.
|
||||
//var buf = new ArrayBuffer(0xfe8000);
|
||||
//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
|
||||
//var buf = new ArrayBuffer(0xff0000); // 16302K
|
||||
//new Uint8Array(buf)[0xfeffff] = 0xAA;
|
||||
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
|
||||
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xfeffff),0xAA);
|
||||
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xff0000),0);
|
||||
//var buf = new ArrayBuffer(0xff8000);
|
||||
//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
|
||||
//var buf = new ArrayBuffer(0x3fb0000);
|
||||
//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
|
||||
//var buf = new ArrayBuffer(0x3fc0000); // 65280K
|
||||
//new Uint8Array(buf)[0x3fbffff] = 0xAA;
|
||||
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
|
||||
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fbffff),0xAA);
|
||||
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fc0000),0);
|
||||
//var buf = new ArrayBuffer(0x3fe0000);
|
||||
//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
|
||||
//var buf = new ArrayBuffer(0xfe80000);
|
||||
//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
|
||||
//var buf = new ArrayBuffer(0xff00000); // 255M
|
||||
//new Uint8Array(buf)[0xfeffff] = 0xAA;
|
||||
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
|
||||
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xfeffff),0xAA);
|
||||
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xff00000),0);
|
||||
//var buf = new ArrayBuffer(0xff80000);
|
||||
//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
|
||||
//var buf = new ArrayBuffer(0x10400000);
|
||||
//new Uint8Array(buf)[0x103fffff] = 0xAA;
|
||||
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x103fffff]|0; } return f'), this, null, buf)(),0xAA);
|
||||
//var buf = new ArrayBuffer(0x3fa00000);
|
||||
//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
|
||||
//var buf = new ArrayBuffer(0x3fc00000); // 1020M
|
||||
//new Uint8Array(buf)[0x3fbfffff] = 0xAA;
|
||||
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
|
||||
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fbfffff),0xAA);
|
||||
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fc00000),0);
|
||||
//var buf = new ArrayBuffer(0x3fe00000);
|
||||
//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
|
||||
//var buf = new ArrayBuffer(0x40000000); // 1024M
|
||||
//new Uint8Array(buf)[0x3fffffff] = 0xAA;
|
||||
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
|
||||
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fffffff),0xAA);
|
||||
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x40000000),0);
|
||||
//var buf = new ArrayBuffer(0x4f000000); // 1264M - currently the largest possible heap length.
|
||||
//new Uint8Array(buf)[0x4effffff] = 0xAA;
|
||||
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
|
||||
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x4effffff),0xAA);
|
||||
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x4f000000),0);
|
||||
|
||||
new Uint8Array(buf)[0x4242] = 0xAA;
|
||||
var f = asmLink(m, this, null, buf);
|
||||
assertEq(f(0),0);
|
||||
assertEq(f(0x4242),0xAA);
|
||||
assertEq(f(0x100000),0);
|
||||
assertAsmLinkFail(m, this, null, new ArrayBuffer(0x104000));
|
||||
assertEq(asmLink(m, this, null, new ArrayBuffer(0x200000))(0),0);
|
||||
assertAsmLinkFail(m, this, null, new ArrayBuffer(0x3f8000));
|
||||
assertAsmLinkFail(m, this, null, new ArrayBuffer(0x3fe000));
|
||||
assertAsmLinkFail(m, this, null, new ArrayBuffer(0x3fc000));
|
||||
assertEq(asmLink(m, this, null, new ArrayBuffer(0x400000))(0),0);
|
||||
assertAsmLinkFail(m, this, null, new ArrayBuffer(0x410000));
|
||||
assertEq(asmLink(m, this, null, new ArrayBuffer(0x800000))(0),0);
|
||||
var buf = new ArrayBuffer(0x1000000);
|
||||
new Uint8Array(buf)[0x424242] = 0xAA;
|
||||
var f = asmLink(m, this, null, buf);
|
||||
assertEq(f(0),0);
|
||||
assertEq(f(0x424242),0xAA);
|
||||
assertEq(f(0x1000000),0);
|
||||
assertEq(asmLink(m, this, null, new ArrayBuffer(0x2000000))(0),0);
|
||||
assertEq(asmLink(m, this, null, new ArrayBuffer(0x3000000))(0),0);
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
if (getBuildConfiguration().parallelJS) {
|
||||
Array.buildPar(6763, function() {
|
||||
return Math.fround(Math.round(Math.fround(-0)));
|
||||
});
|
||||
}
|
|
@ -7,8 +7,12 @@
|
|||
#ifndef jit_AsmJS_h
|
||||
#define jit_AsmJS_h
|
||||
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "jsutil.h"
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "vm/ObjectImpl.h"
|
||||
|
||||
|
@ -88,77 +92,33 @@ IsAsmJSCompilationAvailable(JSContext *cx, unsigned argc, Value *vp)
|
|||
|
||||
#endif // JS_ION
|
||||
|
||||
// The Asm.js heap length is constrained by the x64 backend heap access scheme
|
||||
// to be a multiple of the page size which is 4096 bytes, and also constrained
|
||||
// by the limits of ARM backends 'cmp immediate' instruction which supports a
|
||||
// complex range for the immediate argument.
|
||||
//
|
||||
// ARMv7 mode supports the following immediate constants, and the Thumb T2
|
||||
// instruction encoding also supports the subset of immediate constants used.
|
||||
// abcdefgh 00000000 00000000 00000000
|
||||
// 00abcdef gh000000 00000000 00000000
|
||||
// 0000abcd efgh0000 00000000 00000000
|
||||
// 000000ab cdefgh00 00000000 00000000
|
||||
// 00000000 abcdefgh 00000000 00000000
|
||||
// 00000000 00abcdef gh000000 00000000
|
||||
// 00000000 0000abcd efgh0000 00000000
|
||||
// ...
|
||||
//
|
||||
// The 4096 page size constraint restricts the length to:
|
||||
// xxxxxxxx xxxxxxxx xxxx0000 00000000
|
||||
//
|
||||
// Intersecting all the above constraints gives:
|
||||
// Heap length 0x40000000 to 0xff000000 quanta 0x01000000
|
||||
// Heap length 0x10000000 to 0x3fc00000 quanta 0x00400000
|
||||
// Heap length 0x04000000 to 0x0ff00000 quanta 0x00100000
|
||||
// Heap length 0x01000000 to 0x03fc0000 quanta 0x00040000
|
||||
// Heap length 0x00400000 to 0x00ff0000 quanta 0x00010000
|
||||
// Heap length 0x00100000 to 0x003fc000 quanta 0x00004000
|
||||
// Heap length 0x00001000 to 0x000ff000 quanta 0x00001000
|
||||
//
|
||||
inline uint32_t
|
||||
RoundUpToNextValidAsmJSHeapLength(uint32_t length)
|
||||
{
|
||||
if (length < 0x00001000u) // Minimum length is the pages size of 4096.
|
||||
return 0x1000u;
|
||||
if (length < 0x00100000u) // < 1M quanta 4K
|
||||
return (length + 0x00000fff) & ~0x00000fff;
|
||||
if (length < 0x00400000u) // < 4M quanta 16K
|
||||
return (length + 0x00003fff) & ~0x00003fff;
|
||||
if (length < 0x01000000u) // < 16M quanta 64K
|
||||
return (length + 0x0000ffff) & ~0x0000ffff;
|
||||
if (length < 0x04000000u) // < 64M quanta 256K
|
||||
return (length + 0x0003ffff) & ~0x0003ffff;
|
||||
if (length < 0x10000000u) // < 256M quanta 1M
|
||||
return (length + 0x000fffff) & ~0x000fffff;
|
||||
if (length < 0x40000000u) // < 1024M quanta 4M
|
||||
return (length + 0x003fffff) & ~0x003fffff;
|
||||
// < 4096M quanta 16M. Note zero is returned if over 0xff000000 but such
|
||||
// lengths are not currently valid.
|
||||
JS_ASSERT(length <= 0xff000000);
|
||||
return (length + 0x00ffffff) & ~0x00ffffff;
|
||||
}
|
||||
|
||||
// To succesfully link an asm.js module to an ArrayBuffer heap, the
|
||||
// ArrayBuffer's byteLength must be:
|
||||
// - greater or equal to 4096
|
||||
// - either a power of 2 OR a multiple of 16MB
|
||||
inline bool
|
||||
IsValidAsmJSHeapLength(uint32_t length)
|
||||
{
|
||||
if (length < AsmJSAllocationGranularity)
|
||||
if (length < 4096)
|
||||
return false;
|
||||
if (length <= 0x00100000u)
|
||||
return (length & 0x00000fff) == 0;
|
||||
if (length <= 0x00400000u)
|
||||
return (length & 0x00003fff) == 0;
|
||||
if (length <= 0x01000000u)
|
||||
return (length & 0x0000ffff) == 0;
|
||||
if (length <= 0x04000000u)
|
||||
return (length & 0x0003ffff) == 0;
|
||||
if (length <= 0x10000000u)
|
||||
return (length & 0x000fffff) == 0;
|
||||
if (length <= 0x40000000u)
|
||||
return (length & 0x003fffff) == 0;
|
||||
if (length <= 0xff000000u)
|
||||
return (length & 0x00ffffff) == 0;
|
||||
return false;
|
||||
|
||||
if (IsPowerOfTwo(length))
|
||||
return true;
|
||||
|
||||
return (length & 0x00ffffff) == 0;
|
||||
}
|
||||
|
||||
inline uint32_t
|
||||
RoundUpToNextValidAsmJSHeapLength(uint32_t length)
|
||||
{
|
||||
if (length < 4096)
|
||||
return 4096;
|
||||
|
||||
if (length < 16 * 1024 * 1024)
|
||||
return mozilla::RoundUpPow2(length);
|
||||
|
||||
JS_ASSERT(length <= 0xff000000);
|
||||
return (length + 0x00ffffff) & ~0x00ffffff;
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
|
|
@ -1338,8 +1338,7 @@ bool
|
|||
LIRGenerator::visitMathFunction(MMathFunction *ins)
|
||||
{
|
||||
JS_ASSERT(IsFloatingPointType(ins->type()));
|
||||
JS_ASSERT_IF(ins->type() == MIRType_Double, ins->input()->type() == MIRType_Double);
|
||||
JS_ASSERT_IF(ins->type() == MIRType_Float32, ins->input()->type() == MIRType_Float32);
|
||||
JS_ASSERT(ins->type() == ins->input()->type());
|
||||
|
||||
if (ins->type() == MIRType_Double) {
|
||||
// Note: useRegisterAtStart is safe here, the temp is not a FP register.
|
||||
|
|
|
@ -610,6 +610,19 @@ ParallelSafetyVisitor::replace(MInstruction *oldInstruction,
|
|||
block->insertBefore(oldInstruction, replacementInstruction);
|
||||
oldInstruction->replaceAllUsesWith(replacementInstruction);
|
||||
block->discard(oldInstruction);
|
||||
|
||||
// We may have replaced a specialized Float32 instruction by its
|
||||
// non-specialized version, so just retry to specialize it. This relies on
|
||||
// the fact that Phis' types don't change during the ParallelSafetyAnalysis;
|
||||
// otherwise we'd have to run the entire TypeAnalyzer Float32 analysis once
|
||||
// instructions have been replaced.
|
||||
if (replacementInstruction->isFloat32Commutative() &&
|
||||
replacementInstruction->type() != MIRType_Float32)
|
||||
{
|
||||
replacementInstruction->trySpecializeFloat32(alloc());
|
||||
}
|
||||
JS_ASSERT(oldInstruction->type() == replacementInstruction->type());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
321
js/src/jsgc.cpp
321
js/src/jsgc.cpp
|
@ -960,14 +960,40 @@ GCRuntime::wantBackgroundAllocation() const
|
|||
* allocation if we have empty chunks or when the runtime needs just few
|
||||
* of them.
|
||||
*/
|
||||
return helperThread.canBackgroundAllocate() &&
|
||||
return helperState.canBackgroundAllocate() &&
|
||||
chunkPool.getEmptyCount() == 0 &&
|
||||
chunkSet.count() >= 4;
|
||||
}
|
||||
|
||||
class js::gc::AutoMaybeStartBackgroundAllocation
|
||||
{
|
||||
private:
|
||||
JSRuntime *runtime;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
||||
public:
|
||||
AutoMaybeStartBackgroundAllocation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
|
||||
: runtime(nullptr)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
void tryToStartBackgroundAllocation(JSRuntime *rt) {
|
||||
runtime = rt;
|
||||
}
|
||||
|
||||
~AutoMaybeStartBackgroundAllocation() {
|
||||
if (runtime && !runtime->currentThreadOwnsInterruptLock()) {
|
||||
AutoLockWorkerThreadState workerLock;
|
||||
AutoLockGC lock(runtime);
|
||||
runtime->gc.startBackgroundAllocationIfIdle();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* The caller must hold the GC lock. */
|
||||
Chunk *
|
||||
GCRuntime::pickChunk(Zone *zone)
|
||||
GCRuntime::pickChunk(Zone *zone, AutoMaybeStartBackgroundAllocation &maybeStartBackgroundAllocation)
|
||||
{
|
||||
Chunk **listHeadp = GetAvailableChunkList(zone);
|
||||
Chunk *chunk = *listHeadp;
|
||||
|
@ -986,7 +1012,7 @@ GCRuntime::pickChunk(Zone *zone)
|
|||
JS_ASSERT(!chunkSet.has(chunk));
|
||||
|
||||
if (wantBackgroundAllocation())
|
||||
helperThread.startBackgroundAllocationIfIdle();
|
||||
maybeStartBackgroundAllocation.tryToStartBackgroundAllocation(rt);
|
||||
|
||||
chunkAllocationSinceLastGC = true;
|
||||
|
||||
|
@ -1094,7 +1120,7 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
|
|||
#endif
|
||||
lock(nullptr),
|
||||
lockOwner(nullptr),
|
||||
helperThread(rt)
|
||||
helperState(rt)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1191,7 +1217,7 @@ GCRuntime::init(uint32_t maxbytes)
|
|||
if (!rootsHash.init(256))
|
||||
return false;
|
||||
|
||||
if (!helperThread.init())
|
||||
if (!helperState.init())
|
||||
return false;
|
||||
|
||||
/*
|
||||
|
@ -1242,7 +1268,7 @@ GCRuntime::finish()
|
|||
* Wait until the background finalization stops and the helper thread
|
||||
* shuts down before we forcefully release any remaining GC memory.
|
||||
*/
|
||||
helperThread.finish();
|
||||
helperState.finish();
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
/* Free memory associated with GC verification. */
|
||||
|
@ -1502,7 +1528,8 @@ PushArenaAllocatedDuringSweep(JSRuntime *runtime, ArenaHeader *arena)
|
|||
}
|
||||
|
||||
inline void *
|
||||
ArenaLists::allocateFromArenaInline(Zone *zone, AllocKind thingKind)
|
||||
ArenaLists::allocateFromArenaInline(Zone *zone, AllocKind thingKind,
|
||||
AutoMaybeStartBackgroundAllocation &maybeStartBackgroundAllocation)
|
||||
{
|
||||
/*
|
||||
* Parallel JS Note:
|
||||
|
@ -1575,7 +1602,7 @@ ArenaLists::allocateFromArenaInline(Zone *zone, AllocKind thingKind)
|
|||
JSRuntime *rt = zone->runtimeFromAnyThread();
|
||||
if (!maybeLock.locked())
|
||||
maybeLock.lock(rt);
|
||||
Chunk *chunk = rt->gc.pickChunk(zone);
|
||||
Chunk *chunk = rt->gc.pickChunk(zone, maybeStartBackgroundAllocation);
|
||||
if (!chunk)
|
||||
return nullptr;
|
||||
|
||||
|
@ -1620,7 +1647,8 @@ ArenaLists::allocateFromArenaInline(Zone *zone, AllocKind thingKind)
|
|||
void *
|
||||
ArenaLists::allocateFromArena(JS::Zone *zone, AllocKind thingKind)
|
||||
{
|
||||
return allocateFromArenaInline(zone, thingKind);
|
||||
AutoMaybeStartBackgroundAllocation maybeStartBackgroundAllocation;
|
||||
return allocateFromArenaInline(zone, thingKind, maybeStartBackgroundAllocation);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1695,7 +1723,7 @@ ArenaLists::queueForBackgroundSweep(FreeOp *fop, AllocKind thingKind)
|
|||
JS_ASSERT(IsBackgroundFinalized(thingKind));
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ASSERT(!fop->runtime()->gc.helperThread.sweeping());
|
||||
JS_ASSERT(!fop->runtime()->gc.isBackgroundSweeping());
|
||||
#endif
|
||||
|
||||
ArenaList *al = &arenaLists[thingKind];
|
||||
|
@ -1867,6 +1895,8 @@ ArenaLists::refillFreeList(ThreadSafeContext *cx, AllocKind thingKind)
|
|||
return thing;
|
||||
}
|
||||
|
||||
AutoMaybeStartBackgroundAllocation maybeStartBackgroundAllocation;
|
||||
|
||||
if (cx->isJSContext()) {
|
||||
/*
|
||||
* allocateFromArena may fail while the background finalization still
|
||||
|
@ -1877,13 +1907,14 @@ ArenaLists::refillFreeList(ThreadSafeContext *cx, AllocKind thingKind)
|
|||
* this race we always try to allocate twice.
|
||||
*/
|
||||
for (bool secondAttempt = false; ; secondAttempt = true) {
|
||||
void *thing = cx->allocator()->arenas.allocateFromArenaInline(zone, thingKind);
|
||||
void *thing = cx->allocator()->arenas.allocateFromArenaInline(zone, thingKind,
|
||||
maybeStartBackgroundAllocation);
|
||||
if (MOZ_LIKELY(!!thing))
|
||||
return thing;
|
||||
if (secondAttempt)
|
||||
break;
|
||||
|
||||
cx->asJSContext()->runtime()->gc.helperThread.waitBackgroundSweepEnd();
|
||||
cx->asJSContext()->runtime()->gc.waitBackgroundSweepEnd();
|
||||
}
|
||||
} else {
|
||||
#ifdef JS_THREADSAFE
|
||||
|
@ -1902,7 +1933,8 @@ ArenaLists::refillFreeList(ThreadSafeContext *cx, AllocKind thingKind)
|
|||
WorkerThreadState().wait(GlobalWorkerThreadState::PRODUCER);
|
||||
}
|
||||
|
||||
void *thing = cx->allocator()->arenas.allocateFromArenaInline(zone, thingKind);
|
||||
void *thing = cx->allocator()->arenas.allocateFromArenaInline(zone, thingKind,
|
||||
maybeStartBackgroundAllocation);
|
||||
if (thing)
|
||||
return thing;
|
||||
#else
|
||||
|
@ -2102,7 +2134,7 @@ GCRuntime::maybeGC(Zone *zone)
|
|||
if (zone->gcBytes > 1024 * 1024 &&
|
||||
zone->gcBytes >= factor * zone->gcTriggerBytes &&
|
||||
incrementalState == NO_INCREMENTAL &&
|
||||
!helperThread.sweeping())
|
||||
!isBackgroundSweeping())
|
||||
{
|
||||
PrepareZoneForGC(zone);
|
||||
GCSlice(rt, GC_NORMAL, JS::gcreason::MAYBEGC);
|
||||
|
@ -2284,6 +2316,7 @@ SweepBackgroundThings(JSRuntime* rt, bool onBackgroundThread)
|
|||
static void
|
||||
AssertBackgroundSweepingFinished(JSRuntime *rt)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
JS_ASSERT(!rt->gc.sweepingZones);
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
for (unsigned i = 0; i < FINALIZE_LIMIT; ++i) {
|
||||
|
@ -2291,6 +2324,7 @@ AssertBackgroundSweepingFinished(JSRuntime *rt)
|
|||
JS_ASSERT(zone->allocator.arenas.doneBackgroundFinalize(AllocKind(i)));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned
|
||||
|
@ -2312,7 +2346,7 @@ js::GetCPUCount()
|
|||
#endif /* JS_THREADSAFE */
|
||||
|
||||
bool
|
||||
GCHelperThread::init()
|
||||
GCHelperState::init()
|
||||
{
|
||||
if (!rt->useHelperThreads()) {
|
||||
backgroundAllocation = false;
|
||||
|
@ -2320,174 +2354,172 @@ GCHelperThread::init()
|
|||
}
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
if (!(wakeup = PR_NewCondVar(rt->gc.lock)))
|
||||
return false;
|
||||
if (!(done = PR_NewCondVar(rt->gc.lock)))
|
||||
return false;
|
||||
|
||||
thread = PR_CreateThread(PR_USER_THREAD, threadMain, this, PR_PRIORITY_NORMAL,
|
||||
PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
|
||||
if (!thread)
|
||||
return false;
|
||||
|
||||
backgroundAllocation = (GetCPUCount() >= 2);
|
||||
|
||||
WorkerThreadState().ensureInitialized();
|
||||
#endif /* JS_THREADSAFE */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
GCHelperThread::finish()
|
||||
GCHelperState::finish()
|
||||
{
|
||||
if (!rt->useHelperThreads() || !rt->gc.lock) {
|
||||
JS_ASSERT(state == IDLE);
|
||||
JS_ASSERT(state_ == IDLE);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
PRThread *join = nullptr;
|
||||
{
|
||||
AutoLockGC lock(rt);
|
||||
if (thread && state != SHUTDOWN) {
|
||||
/*
|
||||
* We cannot be in the ALLOCATING or CANCEL_ALLOCATION states as
|
||||
* the allocations should have been stopped during the last GC.
|
||||
*/
|
||||
JS_ASSERT(state == IDLE || state == SWEEPING);
|
||||
if (state == IDLE)
|
||||
PR_NotifyCondVar(wakeup);
|
||||
state = SHUTDOWN;
|
||||
join = thread;
|
||||
}
|
||||
}
|
||||
if (join) {
|
||||
/* PR_DestroyThread is not necessary. */
|
||||
PR_JoinThread(join);
|
||||
}
|
||||
if (wakeup)
|
||||
PR_DestroyCondVar(wakeup);
|
||||
// Wait for any lingering background sweeping to finish.
|
||||
waitBackgroundSweepEnd();
|
||||
|
||||
if (done)
|
||||
PR_DestroyCondVar(done);
|
||||
#else
|
||||
MOZ_CRASH();
|
||||
#endif /* JS_THREADSAFE */
|
||||
}
|
||||
|
||||
GCHelperState::State
|
||||
GCHelperState::state()
|
||||
{
|
||||
JS_ASSERT(rt->gc.currentThreadOwnsGCLock());
|
||||
return state_;
|
||||
}
|
||||
|
||||
void
|
||||
GCHelperState::setState(State state)
|
||||
{
|
||||
JS_ASSERT(rt->gc.currentThreadOwnsGCLock());
|
||||
state_ = state;
|
||||
}
|
||||
|
||||
void
|
||||
GCHelperState::startBackgroundThread(State newState)
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
extern "C" {
|
||||
MFBT_API bool IsNuwaProcess();
|
||||
MFBT_API void NuwaMarkCurrentThread(void (*recreate)(void *), void *arg);
|
||||
}
|
||||
JS_ASSERT(!thread && state() == IDLE && newState != IDLE);
|
||||
setState(newState);
|
||||
|
||||
if (!WorkerThreadState().gcHelperWorklist().append(this))
|
||||
CrashAtUnhandlableOOM("Could not add to pending GC helpers list");
|
||||
WorkerThreadState().notifyAll(GlobalWorkerThreadState::PRODUCER);
|
||||
#else
|
||||
MOZ_CRASH();
|
||||
#endif
|
||||
|
||||
/* static */
|
||||
void
|
||||
GCHelperThread::threadMain(void *arg)
|
||||
{
|
||||
PR_SetCurrentThreadName("JS GC Helper");
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (IsNuwaProcess && IsNuwaProcess()) {
|
||||
JS_ASSERT(NuwaMarkCurrentThread != nullptr);
|
||||
NuwaMarkCurrentThread(nullptr, nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
static_cast<GCHelperThread *>(arg)->threadLoop();
|
||||
}
|
||||
|
||||
void
|
||||
GCHelperThread::wait(PRCondVar *which)
|
||||
GCHelperState::waitForBackgroundThread()
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ASSERT(CurrentThreadCanAccessRuntime(rt));
|
||||
|
||||
rt->gc.lockOwner = nullptr;
|
||||
PR_WaitCondVar(which, PR_INTERVAL_NO_TIMEOUT);
|
||||
PR_WaitCondVar(done, PR_INTERVAL_NO_TIMEOUT);
|
||||
#ifdef DEBUG
|
||||
rt->gc.lockOwner = PR_GetCurrentThread();
|
||||
#endif
|
||||
#else
|
||||
MOZ_CRASH();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
GCHelperThread::threadLoop()
|
||||
GCHelperState::work()
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
AutoLockGC lock(rt);
|
||||
|
||||
TraceLogger *logger = TraceLoggerForCurrentThread();
|
||||
JS_ASSERT(!thread);
|
||||
thread = PR_GetCurrentThread();
|
||||
|
||||
/*
|
||||
* Even on the first iteration the state can be SHUTDOWN or SWEEPING if
|
||||
* the stop request or the GC and the corresponding startBackgroundSweep call
|
||||
* happen before this thread has a chance to run.
|
||||
*/
|
||||
for (;;) {
|
||||
switch (state) {
|
||||
case SHUTDOWN:
|
||||
return;
|
||||
case IDLE:
|
||||
wait(wakeup);
|
||||
break;
|
||||
case SWEEPING: {
|
||||
AutoTraceLog logSweeping(logger, TraceLogger::GCSweeping);
|
||||
doSweep();
|
||||
if (state == SWEEPING)
|
||||
state = IDLE;
|
||||
PR_NotifyAllCondVar(done);
|
||||
break;
|
||||
}
|
||||
case ALLOCATING: {
|
||||
AutoTraceLog logAllocating(logger, TraceLogger::GCAllocation);
|
||||
do {
|
||||
Chunk *chunk;
|
||||
{
|
||||
AutoUnlockGC unlock(rt);
|
||||
chunk = Chunk::allocate(rt);
|
||||
}
|
||||
switch (state()) {
|
||||
|
||||
/* OOM stops the background allocation. */
|
||||
if (!chunk)
|
||||
break;
|
||||
JS_ASSERT(chunk->info.numArenasFreeCommitted == 0);
|
||||
rt->gc.chunkPool.put(chunk);
|
||||
} while (state == ALLOCATING && rt->gc.wantBackgroundAllocation());
|
||||
if (state == ALLOCATING)
|
||||
state = IDLE;
|
||||
break;
|
||||
}
|
||||
case CANCEL_ALLOCATION:
|
||||
state = IDLE;
|
||||
PR_NotifyAllCondVar(done);
|
||||
break;
|
||||
}
|
||||
case IDLE:
|
||||
MOZ_ASSUME_UNREACHABLE("GC helper triggered on idle state");
|
||||
break;
|
||||
|
||||
case SWEEPING: {
|
||||
#if JS_TRACE_LOGGING
|
||||
AutoTraceLog logger(TraceLogging::getLogger(TraceLogging::GC_BACKGROUND),
|
||||
TraceLogging::GC_SWEEPING_START,
|
||||
TraceLogging::GC_SWEEPING_STOP);
|
||||
#endif
|
||||
doSweep();
|
||||
JS_ASSERT(state() == SWEEPING);
|
||||
break;
|
||||
}
|
||||
|
||||
case ALLOCATING: {
|
||||
#if JS_TRACE_LOGGING
|
||||
AutoTraceLog logger(TraceLogging::getLogger(TraceLogging::GC_BACKGROUND),
|
||||
TraceLogging::GC_ALLOCATING_START,
|
||||
TraceLogging::GC_ALLOCATING_STOP);
|
||||
#endif
|
||||
do {
|
||||
Chunk *chunk;
|
||||
{
|
||||
AutoUnlockGC unlock(rt);
|
||||
chunk = Chunk::allocate(rt);
|
||||
}
|
||||
|
||||
/* OOM stops the background allocation. */
|
||||
if (!chunk)
|
||||
break;
|
||||
JS_ASSERT(chunk->info.numArenasFreeCommitted == 0);
|
||||
rt->gc.chunkPool.put(chunk);
|
||||
} while (state() == ALLOCATING && rt->gc.wantBackgroundAllocation());
|
||||
|
||||
JS_ASSERT(state() == ALLOCATING || state() == CANCEL_ALLOCATION);
|
||||
break;
|
||||
}
|
||||
|
||||
case CANCEL_ALLOCATION:
|
||||
break;
|
||||
}
|
||||
|
||||
setState(IDLE);
|
||||
thread = nullptr;
|
||||
|
||||
PR_NotifyAllCondVar(done);
|
||||
#else
|
||||
MOZ_CRASH();
|
||||
#endif
|
||||
}
|
||||
#endif /* JS_THREADSAFE */
|
||||
|
||||
void
|
||||
GCHelperThread::startBackgroundSweep(bool shouldShrink)
|
||||
GCHelperState::startBackgroundSweep(bool shouldShrink)
|
||||
{
|
||||
JS_ASSERT(rt->useHelperThreads());
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
AutoLockWorkerThreadState workerLock;
|
||||
AutoLockGC lock(rt);
|
||||
JS_ASSERT(state == IDLE);
|
||||
JS_ASSERT(state() == IDLE);
|
||||
JS_ASSERT(!sweepFlag);
|
||||
sweepFlag = true;
|
||||
shrinkFlag = shouldShrink;
|
||||
state = SWEEPING;
|
||||
PR_NotifyCondVar(wakeup);
|
||||
startBackgroundThread(SWEEPING);
|
||||
#endif /* JS_THREADSAFE */
|
||||
}
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
void
|
||||
GCHelperThread::startBackgroundShrink()
|
||||
GCHelperState::startBackgroundShrink()
|
||||
{
|
||||
JS_ASSERT(rt->useHelperThreads());
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
switch (state) {
|
||||
switch (state()) {
|
||||
case IDLE:
|
||||
JS_ASSERT(!sweepFlag);
|
||||
shrinkFlag = true;
|
||||
state = SWEEPING;
|
||||
PR_NotifyCondVar(wakeup);
|
||||
startBackgroundThread(SWEEPING);
|
||||
break;
|
||||
case SWEEPING:
|
||||
shrinkFlag = true;
|
||||
|
@ -2499,43 +2531,41 @@ GCHelperThread::startBackgroundShrink()
|
|||
* shrink.
|
||||
*/
|
||||
break;
|
||||
case SHUTDOWN:
|
||||
MOZ_ASSUME_UNREACHABLE("No shrink on shutdown");
|
||||
}
|
||||
#endif /* JS_THREADSAFE */
|
||||
}
|
||||
|
||||
void
|
||||
GCHelperThread::waitBackgroundSweepEnd()
|
||||
GCHelperState::waitBackgroundSweepEnd()
|
||||
{
|
||||
if (!rt->useHelperThreads()) {
|
||||
JS_ASSERT(state == IDLE);
|
||||
JS_ASSERT(state_ == IDLE);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
AutoLockGC lock(rt);
|
||||
while (state == SWEEPING)
|
||||
wait(done);
|
||||
while (state() == SWEEPING)
|
||||
waitForBackgroundThread();
|
||||
if (rt->gc.incrementalState == NO_INCREMENTAL)
|
||||
AssertBackgroundSweepingFinished(rt);
|
||||
#endif /* JS_THREADSAFE */
|
||||
}
|
||||
|
||||
void
|
||||
GCHelperThread::waitBackgroundSweepOrAllocEnd()
|
||||
GCHelperState::waitBackgroundSweepOrAllocEnd()
|
||||
{
|
||||
if (!rt->useHelperThreads()) {
|
||||
JS_ASSERT(state == IDLE);
|
||||
JS_ASSERT(state_ == IDLE);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
AutoLockGC lock(rt);
|
||||
if (state == ALLOCATING)
|
||||
state = CANCEL_ALLOCATION;
|
||||
while (state == SWEEPING || state == CANCEL_ALLOCATION)
|
||||
wait(done);
|
||||
if (state() == ALLOCATING)
|
||||
setState(CANCEL_ALLOCATION);
|
||||
while (state() == SWEEPING || state() == CANCEL_ALLOCATION)
|
||||
waitForBackgroundThread();
|
||||
if (rt->gc.incrementalState == NO_INCREMENTAL)
|
||||
AssertBackgroundSweepingFinished(rt);
|
||||
#endif /* JS_THREADSAFE */
|
||||
|
@ -2543,20 +2573,18 @@ GCHelperThread::waitBackgroundSweepOrAllocEnd()
|
|||
|
||||
/* Must be called with the GC lock taken. */
|
||||
inline void
|
||||
GCHelperThread::startBackgroundAllocationIfIdle()
|
||||
GCHelperState::startBackgroundAllocationIfIdle()
|
||||
{
|
||||
JS_ASSERT(rt->useHelperThreads());
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
if (state == IDLE) {
|
||||
state = ALLOCATING;
|
||||
PR_NotifyCondVar(wakeup);
|
||||
}
|
||||
if (state_ == IDLE)
|
||||
startBackgroundThread(ALLOCATING);
|
||||
#endif /* JS_THREADSAFE */
|
||||
}
|
||||
|
||||
void
|
||||
GCHelperThread::replenishAndFreeLater(void *ptr)
|
||||
GCHelperState::replenishAndFreeLater(void *ptr)
|
||||
{
|
||||
JS_ASSERT(freeCursor == freeCursorEnd);
|
||||
do {
|
||||
|
@ -2577,7 +2605,7 @@ GCHelperThread::replenishAndFreeLater(void *ptr)
|
|||
#ifdef JS_THREADSAFE
|
||||
/* Must be called with the GC lock taken. */
|
||||
void
|
||||
GCHelperThread::doSweep()
|
||||
GCHelperState::doSweep()
|
||||
{
|
||||
if (sweepFlag) {
|
||||
sweepFlag = false;
|
||||
|
@ -2617,10 +2645,10 @@ GCHelperThread::doSweep()
|
|||
#endif /* JS_THREADSAFE */
|
||||
|
||||
bool
|
||||
GCHelperThread::onBackgroundThread()
|
||||
GCHelperState::onBackgroundThread()
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
return PR_GetCurrentThread() == getThread();
|
||||
return PR_GetCurrentThread() == thread;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
@ -4143,7 +4171,7 @@ GCRuntime::endSweepPhase(JSGCInvocationKind gckind, bool lastGC)
|
|||
/*
|
||||
* Destroy arenas after we finished the sweeping so finalizers can
|
||||
* safely use IsAboutToBeFinalized(). This is done on the
|
||||
* GCHelperThread if possible. We acquire the lock only because
|
||||
* GCHelperState if possible. We acquire the lock only because
|
||||
* Expire needs to unlock it for other callers.
|
||||
*/
|
||||
AutoLockGC lock(rt);
|
||||
|
@ -4407,7 +4435,7 @@ GCRuntime::resetIncrementalGC(const char *reason)
|
|||
|
||||
{
|
||||
gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD);
|
||||
helperThread.waitBackgroundSweepOrAllocEnd();
|
||||
rt->gc.waitBackgroundSweepOrAllocEnd();
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -4618,7 +4646,7 @@ GCRuntime::incrementalCollectSlice(int64_t budget,
|
|||
endSweepPhase(gckind, lastGC);
|
||||
|
||||
if (sweepOnBackgroundThread)
|
||||
helperThread.startBackgroundSweep(gckind == GC_SHRINK);
|
||||
helperState.startBackgroundSweep(gckind == GC_SHRINK);
|
||||
|
||||
incrementalState = NO_INCREMENTAL;
|
||||
break;
|
||||
|
@ -4712,7 +4740,7 @@ GCRuntime::gcCycle(bool incremental, int64_t budget, JSGCInvocationKind gckind,
|
|||
*/
|
||||
{
|
||||
gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD);
|
||||
helperThread.waitBackgroundSweepOrAllocEnd();
|
||||
waitBackgroundSweepOrAllocEnd();
|
||||
}
|
||||
|
||||
State prevState = incrementalState;
|
||||
|
@ -4959,6 +4987,7 @@ js::PrepareForDebugGC(JSRuntime *rt)
|
|||
JS_FRIEND_API(void)
|
||||
JS::ShrinkGCBuffers(JSRuntime *rt)
|
||||
{
|
||||
AutoLockWorkerThreadState workerLock;
|
||||
AutoLockGC lock(rt);
|
||||
JS_ASSERT(!rt->isHeapBusy());
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ class ArrayBufferViewObject;
|
|||
class SharedArrayBufferObject;
|
||||
class BaseShape;
|
||||
class DebugScopeObject;
|
||||
class GCHelperThread;
|
||||
class GlobalObject;
|
||||
class LazyScript;
|
||||
class Nursery;
|
||||
|
@ -355,6 +354,12 @@ GetGCKindSlots(AllocKind thingKind, const Class *clasp)
|
|||
return nslots;
|
||||
}
|
||||
|
||||
// Class to assist in triggering background chunk allocation. This cannot be done
|
||||
// while holding the GC or worker thread state lock due to lock ordering issues.
|
||||
// As a result, the triggering is delayed using this class until neither of the
|
||||
// above locks is held.
|
||||
class AutoMaybeStartBackgroundAllocation;
|
||||
|
||||
/*
|
||||
* Arena lists have a head and a cursor. The cursor conceptually lies on arena
|
||||
* boundaries, i.e. before the first arena, between two arenas, or after the
|
||||
|
@ -771,7 +776,8 @@ class ArenaLists
|
|||
inline void queueForBackgroundSweep(FreeOp *fop, AllocKind thingKind);
|
||||
|
||||
void *allocateFromArena(JS::Zone *zone, AllocKind thingKind);
|
||||
inline void *allocateFromArenaInline(JS::Zone *zone, AllocKind thingKind);
|
||||
inline void *allocateFromArenaInline(JS::Zone *zone, AllocKind thingKind,
|
||||
AutoMaybeStartBackgroundAllocation &maybeStartBackgroundAllocation);
|
||||
|
||||
inline void normalizeBackgroundFinalizeState(AllocKind thingKind);
|
||||
|
||||
|
@ -914,20 +920,20 @@ extern void
|
|||
NotifyGCPostSwap(JSObject *a, JSObject *b, unsigned preResult);
|
||||
|
||||
/*
|
||||
* Helper that implements sweeping and allocation for kinds that can be swept
|
||||
* and allocated off the main thread.
|
||||
* Helper state for use when JS helper threads sweep and allocate GC thing kinds
|
||||
* that can be swept and allocated off the main thread.
|
||||
*
|
||||
* In non-threadsafe builds, all actual sweeping and allocation is performed
|
||||
* on the main thread, but GCHelperThread encapsulates this from clients as
|
||||
* on the main thread, but GCHelperState encapsulates this from clients as
|
||||
* much as possible.
|
||||
*/
|
||||
class GCHelperThread {
|
||||
class GCHelperState
|
||||
{
|
||||
enum State {
|
||||
IDLE,
|
||||
SWEEPING,
|
||||
ALLOCATING,
|
||||
CANCEL_ALLOCATION,
|
||||
SHUTDOWN
|
||||
CANCEL_ALLOCATION
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -943,13 +949,25 @@ class GCHelperThread {
|
|||
static const size_t FREE_ARRAY_SIZE = size_t(1) << 16;
|
||||
static const size_t FREE_ARRAY_LENGTH = FREE_ARRAY_SIZE / sizeof(void *);
|
||||
|
||||
JSRuntime *const rt;
|
||||
PRThread *thread;
|
||||
PRCondVar *wakeup;
|
||||
PRCondVar *done;
|
||||
volatile State state;
|
||||
// Associated runtime.
|
||||
JSRuntime *const rt;
|
||||
|
||||
void wait(PRCondVar *which);
|
||||
// Condvar for notifying the main thread when work has finished. This is
|
||||
// associated with the runtime's GC lock --- the worker thread state
|
||||
// condvars can't be used here due to lock ordering issues.
|
||||
PRCondVar *done;
|
||||
|
||||
// Activity for the helper to do, protected by the GC lock.
|
||||
State state_;
|
||||
|
||||
// Thread which work is being performed on, or null.
|
||||
PRThread *thread;
|
||||
|
||||
void startBackgroundThread(State newState);
|
||||
void waitForBackgroundThread();
|
||||
|
||||
State state();
|
||||
void setState(State state);
|
||||
|
||||
bool sweepFlag;
|
||||
bool shrinkFlag;
|
||||
|
@ -972,19 +990,15 @@ class GCHelperThread {
|
|||
js_free(array);
|
||||
}
|
||||
|
||||
static void threadMain(void* arg);
|
||||
void threadLoop();
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
void doSweep();
|
||||
|
||||
public:
|
||||
explicit GCHelperThread(JSRuntime *rt)
|
||||
explicit GCHelperState(JSRuntime *rt)
|
||||
: rt(rt),
|
||||
thread(nullptr),
|
||||
wakeup(nullptr),
|
||||
done(nullptr),
|
||||
state(IDLE),
|
||||
state_(IDLE),
|
||||
thread(nullptr),
|
||||
sweepFlag(false),
|
||||
shrinkFlag(false),
|
||||
freeCursor(nullptr),
|
||||
|
@ -995,6 +1009,8 @@ class GCHelperThread {
|
|||
bool init();
|
||||
void finish();
|
||||
|
||||
void work();
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
void startBackgroundSweep(bool shouldShrink);
|
||||
|
||||
|
@ -1008,7 +1024,7 @@ class GCHelperThread {
|
|||
void waitBackgroundSweepOrAllocEnd();
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
inline void startBackgroundAllocationIfIdle();
|
||||
void startBackgroundAllocationIfIdle();
|
||||
|
||||
bool canBackgroundAllocate() const {
|
||||
return backgroundAllocation;
|
||||
|
@ -1018,27 +1034,23 @@ class GCHelperThread {
|
|||
backgroundAllocation = false;
|
||||
}
|
||||
|
||||
PRThread *getThread() const {
|
||||
return thread;
|
||||
}
|
||||
|
||||
bool onBackgroundThread();
|
||||
|
||||
/*
|
||||
* Outside the GC lock may give true answer when in fact the sweeping has
|
||||
* been done.
|
||||
*/
|
||||
bool sweeping() const {
|
||||
return state == SWEEPING;
|
||||
bool isBackgroundSweeping() const {
|
||||
return state_ == SWEEPING;
|
||||
}
|
||||
|
||||
bool shouldShrink() const {
|
||||
JS_ASSERT(sweeping());
|
||||
JS_ASSERT(isBackgroundSweeping());
|
||||
return shrinkFlag;
|
||||
}
|
||||
|
||||
void freeLater(void *ptr) {
|
||||
JS_ASSERT(!sweeping());
|
||||
JS_ASSERT(!isBackgroundSweeping());
|
||||
if (freeCursor != freeCursorEnd)
|
||||
*freeCursor++ = ptr;
|
||||
else
|
||||
|
|
|
@ -733,7 +733,7 @@ TypeScript::MonitorAssign(JSContext *cx, HandleObject obj, jsid id)
|
|||
// idea here is that normal object initialization should not trigger
|
||||
// deoptimization in most cases, while actual usage as a hashmap should.
|
||||
TypeObject* type = obj->type();
|
||||
if (type->getPropertyCount() < 8)
|
||||
if (type->getPropertyCount() < 128)
|
||||
return;
|
||||
MarkTypeObjectUnknownProperties(cx, type);
|
||||
}
|
||||
|
|
|
@ -578,6 +578,12 @@ GlobalWorkerThreadState::canStartCompressionTask()
|
|||
return !compressionWorklist().empty();
|
||||
}
|
||||
|
||||
bool
|
||||
GlobalWorkerThreadState::canStartGCHelperTask()
|
||||
{
|
||||
return !gcHelperWorklist().empty();
|
||||
}
|
||||
|
||||
static void
|
||||
CallNewScriptHookForAllScripts(JSContext *cx, HandleScript script)
|
||||
{
|
||||
|
@ -1020,6 +1026,24 @@ GlobalWorkerThreadState::compressionTaskForSource(ScriptSource *ss)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
WorkerThread::handleGCHelperWorkload()
|
||||
{
|
||||
JS_ASSERT(WorkerThreadState().isLocked());
|
||||
JS_ASSERT(WorkerThreadState().canStartGCHelperTask());
|
||||
JS_ASSERT(idle());
|
||||
|
||||
JS_ASSERT(!gcHelperState);
|
||||
gcHelperState = WorkerThreadState().gcHelperWorklist().popCopy();
|
||||
|
||||
{
|
||||
AutoUnlockWorkerThreadState unlock;
|
||||
gcHelperState->work();
|
||||
}
|
||||
|
||||
gcHelperState = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
WorkerThread::threadLoop()
|
||||
{
|
||||
|
@ -1048,7 +1072,8 @@ WorkerThread::threadLoop()
|
|||
if (WorkerThreadState().canStartIonCompile() ||
|
||||
WorkerThreadState().canStartAsmJSCompile() ||
|
||||
WorkerThreadState().canStartParseTask() ||
|
||||
WorkerThreadState().canStartCompressionTask())
|
||||
WorkerThreadState().canStartCompressionTask() ||
|
||||
WorkerThreadState().canStartGCHelperTask())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -1064,6 +1089,8 @@ WorkerThread::threadLoop()
|
|||
handleParseWorkload();
|
||||
else if (WorkerThreadState().canStartCompressionTask())
|
||||
handleCompressionWorkload();
|
||||
else if (WorkerThreadState().canStartGCHelperTask())
|
||||
handleGCHelperWorkload();
|
||||
else
|
||||
MOZ_ASSUME_UNREACHABLE("No task to perform");
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ class GlobalWorkerThreadState
|
|||
typedef Vector<AsmJSParallelTask*, 0, SystemAllocPolicy> AsmJSParallelTaskVector;
|
||||
typedef Vector<ParseTask*, 0, SystemAllocPolicy> ParseTaskVector;
|
||||
typedef Vector<SourceCompressionTask*, 0, SystemAllocPolicy> SourceCompressionTaskVector;
|
||||
typedef Vector<GCHelperState *, 0, SystemAllocPolicy> GCHelperStateVector;
|
||||
|
||||
// List of available threads, or null if the thread state has not been initialized.
|
||||
WorkerThread *threads;
|
||||
|
@ -81,6 +82,9 @@ class GlobalWorkerThreadState
|
|||
// Source compression worklist.
|
||||
SourceCompressionTaskVector compressionWorklist_;
|
||||
|
||||
// Runtimes which have sweeping / allocating work to do.
|
||||
GCHelperStateVector gcHelperWorklist_;
|
||||
|
||||
public:
|
||||
GlobalWorkerThreadState();
|
||||
|
||||
|
@ -150,10 +154,16 @@ class GlobalWorkerThreadState
|
|||
return compressionWorklist_;
|
||||
}
|
||||
|
||||
GCHelperStateVector &gcHelperWorklist() {
|
||||
JS_ASSERT(isLocked());
|
||||
return gcHelperWorklist_;
|
||||
}
|
||||
|
||||
bool canStartAsmJSCompile();
|
||||
bool canStartIonCompile();
|
||||
bool canStartParseTask();
|
||||
bool canStartCompressionTask();
|
||||
bool canStartGCHelperTask();
|
||||
|
||||
uint32_t harvestFailedAsmJSJobs() {
|
||||
JS_ASSERT(isLocked());
|
||||
|
@ -240,8 +250,11 @@ struct WorkerThread
|
|||
/* Any source being compressed on this thread. */
|
||||
SourceCompressionTask *compressionTask;
|
||||
|
||||
/* Any GC state for background sweeping or allocating being performed. */
|
||||
GCHelperState *gcHelperState;
|
||||
|
||||
bool idle() const {
|
||||
return !ionBuilder && !asmData && !parseTask && !compressionTask;
|
||||
return !ionBuilder && !asmData && !parseTask && !compressionTask && !gcHelperState;
|
||||
}
|
||||
|
||||
void destroy();
|
||||
|
@ -250,6 +263,7 @@ struct WorkerThread
|
|||
void handleIonWorkload();
|
||||
void handleParseWorkload();
|
||||
void handleCompressionWorkload();
|
||||
void handleGCHelperWorkload();
|
||||
|
||||
static void ThreadMain(void *arg);
|
||||
void threadLoop();
|
||||
|
|
|
@ -102,14 +102,6 @@ RegExpObjectBuilder::build(HandleAtom source, RegExpFlag flags)
|
|||
return reobj_->init(cx, source, flags) ? reobj_.get() : nullptr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
MaybeTraceRegExpShared(JSContext *cx, RegExpShared *shared)
|
||||
{
|
||||
Zone *zone = cx->zone();
|
||||
if (zone->needsBarrier())
|
||||
shared->trace(zone->barrierTracer());
|
||||
}
|
||||
|
||||
RegExpObject *
|
||||
RegExpObjectBuilder::clone(Handle<RegExpObject *> other)
|
||||
{
|
||||
|
@ -138,10 +130,6 @@ RegExpObjectBuilder::clone(Handle<RegExpObject *> other)
|
|||
if (!other->getShared(cx->asJSContext(), &g))
|
||||
return nullptr;
|
||||
|
||||
// Copying a RegExpShared from one object to another requires a read
|
||||
// barrier, as the shared pointer in an object may be weak.
|
||||
MaybeTraceRegExpShared(cx->asJSContext(), g.re());
|
||||
|
||||
Rooted<JSAtom *> source(cx, other->getSource());
|
||||
return build(source, *g);
|
||||
}
|
||||
|
@ -228,6 +216,29 @@ VectorMatchPairs::allocOrExpandArray(size_t pairCount)
|
|||
|
||||
/* RegExpObject */
|
||||
|
||||
static inline void
|
||||
MaybeTraceRegExpShared(JSContext *cx, RegExpShared *shared)
|
||||
{
|
||||
Zone *zone = cx->zone();
|
||||
if (zone->needsBarrier())
|
||||
shared->trace(zone->barrierTracer());
|
||||
}
|
||||
|
||||
bool
|
||||
RegExpObject::getShared(JSContext *cx, RegExpGuard *g)
|
||||
{
|
||||
if (RegExpShared *shared = maybeShared()) {
|
||||
// Fetching a RegExpShared from an object requires a read
|
||||
// barrier, as the shared pointer might be weak.
|
||||
MaybeTraceRegExpShared(cx, shared);
|
||||
|
||||
g->init(*shared);
|
||||
return true;
|
||||
}
|
||||
|
||||
return createShared(cx, g);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
RegExpObject::trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
|
|
|
@ -453,18 +453,7 @@ class RegExpObject : public JSObject
|
|||
bool multiline() const { return getFixedSlot(MULTILINE_FLAG_SLOT).toBoolean(); }
|
||||
bool sticky() const { return getFixedSlot(STICKY_FLAG_SLOT).toBoolean(); }
|
||||
|
||||
void shared(RegExpGuard *g) const {
|
||||
JS_ASSERT(maybeShared() != nullptr);
|
||||
g->init(*maybeShared());
|
||||
}
|
||||
|
||||
bool getShared(JSContext *cx, RegExpGuard *g) {
|
||||
if (RegExpShared *shared = maybeShared()) {
|
||||
g->init(*shared);
|
||||
return true;
|
||||
}
|
||||
return createShared(cx, g);
|
||||
}
|
||||
bool getShared(JSContext *cx, RegExpGuard *g);
|
||||
|
||||
void setShared(RegExpShared &shared) {
|
||||
JS_ASSERT(!maybeShared());
|
||||
|
|
|
@ -121,7 +121,7 @@ interface ScheduledGCCallback : nsISupports
|
|||
/**
|
||||
* interface of Components.utils
|
||||
*/
|
||||
[scriptable, uuid(c9b6f5a0-cfe8-11e3-9c1a-0800200c9a66)]
|
||||
[scriptable, uuid(a485ba50-e208-11e3-8b68-0800200c9a66)]
|
||||
interface nsIXPCComponents_Utils : nsISupports
|
||||
{
|
||||
|
||||
|
@ -410,6 +410,11 @@ interface nsIXPCComponents_Utils : nsISupports
|
|||
*/
|
||||
bool isDeadWrapper(in jsval obj);
|
||||
|
||||
/**
|
||||
* Determines whether this object is a cross-process wrapper.
|
||||
*/
|
||||
bool isCrossProcessWrapper(in jsval obj);
|
||||
|
||||
/*
|
||||
* To be called from JS only. This is for Gecko internal use only, and may
|
||||
* disappear at any moment.
|
||||
|
@ -574,7 +579,7 @@ interface nsIXPCComponents_Utils : nsISupports
|
|||
/*
|
||||
* Clone an object into a scope.
|
||||
* The 3rd argument is an optional options object:
|
||||
* - cloneFunction: boolean. If true, any function in the value is are
|
||||
* - cloneFunctions: boolean. If true, functions in the value are
|
||||
* wrapped in a function forwarder that appears to be a native function in
|
||||
* the content scope.
|
||||
*/
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "nsJSUtils.h"
|
||||
#include "mozJSComponentLoader.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "JavaScriptParent.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
@ -3110,6 +3111,17 @@ nsXPCComponents_Utils::IsDeadWrapper(HandleValue obj, bool *out)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCComponents_Utils::IsCrossProcessWrapper(HandleValue obj, bool *out)
|
||||
{
|
||||
*out = false;
|
||||
if (obj.isPrimitive())
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
*out = jsipc::IsCPOW(js::CheckedUnwrap(&obj.toObject()));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void recomputerWrappers(jsval vobj); */
|
||||
NS_IMETHODIMP
|
||||
nsXPCComponents_Utils::RecomputeWrappers(HandleValue vobj, JSContext *cx)
|
||||
|
|
|
@ -324,16 +324,14 @@ XPCWrappedNative::GetNewOrUsed(xpcObjectHelper& helper,
|
|||
// It is possible that we will then end up forwarding this entire call
|
||||
// to this same function but with a different scope.
|
||||
|
||||
// If we are making a wrapper for the nsIClassInfo interface then
|
||||
// If we are making a wrapper for an nsIClassInfo singleton then
|
||||
// We *don't* want to have it use the prototype meant for instances
|
||||
// of that class.
|
||||
bool iidIsClassInfo = Interface->GetIID()->Equals(NS_GET_IID(nsIClassInfo));
|
||||
uint32_t classInfoFlags;
|
||||
bool isClassInfoSingleton = helper.GetClassInfo() == helper.Object() &&
|
||||
NS_SUCCEEDED(helper.GetClassInfo()
|
||||
->GetFlags(&classInfoFlags)) &&
|
||||
(classInfoFlags & nsIClassInfo::SINGLETON_CLASSINFO);
|
||||
bool isClassInfo = iidIsClassInfo || isClassInfoSingleton;
|
||||
|
||||
nsIClassInfo *info = helper.GetClassInfo();
|
||||
|
||||
|
@ -348,7 +346,7 @@ XPCWrappedNative::GetNewOrUsed(xpcObjectHelper& helper,
|
|||
// described by the nsIClassInfo, not for the class info object
|
||||
// itself.
|
||||
const XPCNativeScriptableCreateInfo& sciWrapper =
|
||||
isClassInfo ? sci :
|
||||
isClassInfoSingleton ? sci :
|
||||
GatherScriptableCreateInfo(identity, info, sciProto, sci);
|
||||
|
||||
RootedObject parent(cx, Scope->GetGlobalJSObject());
|
||||
|
@ -413,7 +411,7 @@ XPCWrappedNative::GetNewOrUsed(xpcObjectHelper& helper,
|
|||
// Note that the security check happens inside FindTearOff - after the
|
||||
// wrapper is actually created, but before JS code can see it.
|
||||
|
||||
if (info && !isClassInfo) {
|
||||
if (info && !isClassInfoSingleton) {
|
||||
proto = XPCWrappedNativeProto::GetNewOrUsed(Scope, info, &sciProto);
|
||||
if (!proto)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
|
|
@ -22,7 +22,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=658560
|
|||
const Cu = Components.utils;
|
||||
var sandbox = new Cu.Sandbox("about:blank");
|
||||
var contentObj = Cu.evalInSandbox("({ get foo() { return 42 } })", sandbox);
|
||||
var propdesc = Object.getOwnPropertyDescriptor(contentObj, "foo");
|
||||
var propdesc = Object.getOwnPropertyDescriptor(Cu.waiveXrays(contentObj), "foo");
|
||||
is(typeof propdesc, "object", "got a property descriptor back");
|
||||
ok("get" in propdesc, "getter exists");
|
||||
|
||||
|
|
|
@ -112,15 +112,23 @@
|
|||
var sandbox2 = new Cu.Sandbox("http://example.com", sandboxOptions);
|
||||
sandbox.sandbox2 = sandbox2;
|
||||
|
||||
function cloneAndTest(test, cloneOptions) {
|
||||
var output = sandbox.test = Cu.cloneInto(test, sandbox, cloneOptions);
|
||||
function cloneAndTest(test) {
|
||||
var output = sandbox.test = Cu.cloneInto(test, sandbox);
|
||||
compare(test, output);
|
||||
|
||||
sandbox.cloneOptions = cloneOptions;
|
||||
output = Cu.evalInSandbox('cloneInto(test, sandbox2, cloneOptions)', sandbox);
|
||||
output = Cu.evalInSandbox('cloneInto(test, sandbox2)', sandbox);
|
||||
compare(test, output);
|
||||
}
|
||||
|
||||
function cloneAndTestWithFunctions(test) {
|
||||
var output = sandbox.test = Cu.cloneInto(test, sandbox, { cloneFunctions: true });
|
||||
compare(test, output);
|
||||
|
||||
output = Cu.evalInSandbox('cloneInto(test, sandbox2, { cloneFunctions: true })', sandbox);
|
||||
// Note - We need to waive here, because functions are filtered out by object Xrays.
|
||||
compare(test, Cu.waiveXrays(output));
|
||||
}
|
||||
|
||||
var tests = [
|
||||
1,
|
||||
null,
|
||||
|
@ -154,7 +162,7 @@
|
|||
}
|
||||
|
||||
var test = { a: function() { return 42; } }
|
||||
cloneAndTest(test, { cloneFunctions: true });
|
||||
cloneAndTestWithFunctions(test);
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
||||
|
|
|
@ -29,6 +29,7 @@ var test_utils = window.QueryInterface(Ci.nsIInterfaceRequestor).
|
|||
function getCOW(x) {
|
||||
if (typeof x != 'object' && typeof x != 'function')
|
||||
return x;
|
||||
x = Cu.waiveXrays(x);
|
||||
var rval = {};
|
||||
if (typeof x == "function")
|
||||
rval = eval(uneval(x));
|
||||
|
|
|
@ -55,7 +55,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
|
|||
obj.foo = 2;
|
||||
var withProto = iwin.Object.create(obj);
|
||||
is(global(withProto), iwin, "correct global for withProto");
|
||||
is(withProto.foo, 2, "Inherits properly");
|
||||
is(Cu.waiveXrays(withProto).foo, 2, "Inherits properly");
|
||||
|
||||
// Test Function.
|
||||
var primitiveFun = new iwin.Function('return 2');
|
||||
|
@ -99,7 +99,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
|
|||
var toEval = "({a: 2, b: {foo: 'bar'}, f: function() { return window; }})";
|
||||
is(global(iwin.eval(toEval)), iwin, "eval creates objects in the correct global");
|
||||
is(iwin.eval(toEval).b.foo, 'bar', "eval-ed object looks right");
|
||||
is(iwin.eval(toEval).f(), iwin, "evaled function works right");
|
||||
is(Cu.waiveXrays(iwin.eval(toEval)).f(), Cu.waiveXrays(iwin), "evaled function works right");
|
||||
|
||||
testDate();
|
||||
|
||||
|
|
|
@ -452,17 +452,11 @@ SplitInlineAncestors(nsContainerFrame* aParent,
|
|||
}
|
||||
|
||||
// The parent's continuation adopts the siblings after the split.
|
||||
rv = newParent->InsertFrames(nsIFrame::kNoReflowPrincipalList, nullptr, tail);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
newParent->InsertFrames(nsIFrame::kNoReflowPrincipalList, nullptr, tail);
|
||||
|
||||
// The list name kNoReflowPrincipalList would indicate we don't want reflow
|
||||
nsFrameList temp(newParent, newParent);
|
||||
rv = grandparent->InsertFrames(nsIFrame::kNoReflowPrincipalList, parent, temp);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
grandparent->InsertFrames(nsIFrame::kNoReflowPrincipalList, parent, temp);
|
||||
}
|
||||
|
||||
frame = parent;
|
||||
|
@ -561,10 +555,7 @@ CreateContinuation(nsIFrame* aFrame,
|
|||
// The list name kNoReflowPrincipalList would indicate we don't want reflow
|
||||
// XXXbz this needs higher-level framelist love
|
||||
nsFrameList temp(*aNewFrame, *aNewFrame);
|
||||
rv = parent->InsertFrames(nsIFrame::kNoReflowPrincipalList, aFrame, temp);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
parent->InsertFrames(nsIFrame::kNoReflowPrincipalList, aFrame, temp);
|
||||
|
||||
if (!aIsFluid) {
|
||||
// Split inline ancestor frames
|
||||
|
|
|
@ -319,6 +319,15 @@ IsAnonymousFlexOrGridItem(const nsIFrame* aFrame)
|
|||
pseudoType == nsCSSAnonBoxes::anonymousGridItem;
|
||||
}
|
||||
|
||||
// Returns true if aFrame is a flex/grid container.
|
||||
static inline bool
|
||||
IsFlexOrGridContainer(const nsIFrame* aFrame)
|
||||
{
|
||||
const nsIAtom* t = aFrame->GetType();
|
||||
return t == nsGkAtoms::flexContainerFrame ||
|
||||
t == nsGkAtoms::gridContainerFrame;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
static void
|
||||
AssertAnonymousFlexOrGridItemParent(const nsIFrame* aChild,
|
||||
|
@ -395,8 +404,7 @@ ShouldSuppressFloatingOfDescendants(nsIFrame* aFrame)
|
|||
{
|
||||
return aFrame->IsFrameOfType(nsIFrame::eMathML) ||
|
||||
aFrame->IsBoxFrame() ||
|
||||
aFrame->GetType() == nsGkAtoms::flexContainerFrame ||
|
||||
aFrame->GetType() == nsGkAtoms::gridContainerFrame;
|
||||
::IsFlexOrGridContainer(aFrame);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1269,16 +1277,15 @@ nsFrameConstructorState::ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
|
|||
// if the containing block hasn't been reflowed yet (so NS_FRAME_FIRST_REFLOW
|
||||
// is set) and doesn't have any frames in the aChildListID child list yet.
|
||||
const nsFrameList& childList = containingBlock->GetChildList(aChildListID);
|
||||
DebugOnly<nsresult> rv = NS_OK;
|
||||
if (childList.IsEmpty() &&
|
||||
(containingBlock->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
|
||||
// If we're injecting absolutely positioned frames, inject them on the
|
||||
// absolute containing block
|
||||
if (aChildListID == containingBlock->GetAbsoluteListID()) {
|
||||
rv = containingBlock->GetAbsoluteContainingBlock()->
|
||||
SetInitialChildList(containingBlock, aChildListID, aFrameItems);
|
||||
containingBlock->GetAbsoluteContainingBlock()->
|
||||
SetInitialChildList(containingBlock, aChildListID, aFrameItems);
|
||||
} else {
|
||||
rv = containingBlock->SetInitialChildList(aChildListID, aFrameItems);
|
||||
containingBlock->SetInitialChildList(aChildListID, aFrameItems);
|
||||
}
|
||||
} else {
|
||||
// Note that whether the frame construction context is doing an append or
|
||||
|
@ -1310,7 +1317,7 @@ nsFrameConstructorState::ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
|
|||
notCommonAncestor ?
|
||||
containingBlock : nullptr) < 0) {
|
||||
// no lastChild, or lastChild comes before the new children, so just append
|
||||
rv = mFrameManager->AppendFrames(containingBlock, aChildListID, aFrameItems);
|
||||
mFrameManager->AppendFrames(containingBlock, aChildListID, aFrameItems);
|
||||
} else {
|
||||
// Try the other children. First collect them to an array so that a
|
||||
// reasonable fast binary search can be used to find the insertion point.
|
||||
|
@ -1356,17 +1363,12 @@ nsFrameConstructorState::ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
|
|||
break;
|
||||
}
|
||||
}
|
||||
rv = mFrameManager->InsertFrames(containingBlock, aChildListID,
|
||||
insertionPoint, aFrameItems);
|
||||
mFrameManager->InsertFrames(containingBlock, aChildListID,
|
||||
insertionPoint, aFrameItems);
|
||||
}
|
||||
}
|
||||
|
||||
NS_POSTCONDITION(aFrameItems.IsEmpty(), "How did that happen?");
|
||||
|
||||
// XXXbz And if NS_FAILED(rv), what? I guess we need to clean up the list
|
||||
// and deal with all the placeholders... but what if the placeholders aren't
|
||||
// in the document yet? Could that happen?
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Frames getting lost!");
|
||||
}
|
||||
|
||||
|
||||
|
@ -5964,7 +5966,8 @@ nsCSSFrameConstructor::AppendFramesToParent(nsFrameConstructorState& aStat
|
|||
}
|
||||
|
||||
// Insert the frames after our aPrevSibling
|
||||
return InsertFrames(aParentFrame, kPrincipalList, aPrevSibling, aFrameList);
|
||||
InsertFrames(aParentFrame, kPrincipalList, aPrevSibling, aFrameList);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#define UNSET_DISPLAY 255
|
||||
|
@ -7722,9 +7725,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
|
|||
NS_ASSERTION(childFrame, "Missing placeholder frame for out of flow.");
|
||||
parentFrame = childFrame->GetParent();
|
||||
}
|
||||
rv = RemoveFrame(nsLayoutUtils::GetChildListNameFor(childFrame),
|
||||
childFrame);
|
||||
//XXXfr NS_ENSURE_SUCCESS(rv, rv) ?
|
||||
RemoveFrame(nsLayoutUtils::GetChildListNameFor(childFrame), childFrame);
|
||||
|
||||
if (isRoot) {
|
||||
mRootElementFrame = nullptr;
|
||||
|
@ -8933,15 +8934,12 @@ nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
|
|||
FrameConstructionItemList& aItems,
|
||||
nsIFrame* aParentFrame)
|
||||
{
|
||||
if (aItems.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
nsIAtom* containerType = aParentFrame->GetType();
|
||||
if (containerType != nsGkAtoms::flexContainerFrame &&
|
||||
containerType != nsGkAtoms::gridContainerFrame) {
|
||||
if (aItems.IsEmpty() ||
|
||||
!::IsFlexOrGridContainer(aParentFrame)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIAtom* containerType = aParentFrame->GetType();
|
||||
FCItemIterator iter(aItems);
|
||||
do {
|
||||
// Advance iter past children that don't want to be wrapped
|
||||
|
@ -10835,9 +10833,10 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
|
|||
|
||||
nsIFrame* nextSibling = ::GetInsertNextSibling(aFrame, aPrevSibling);
|
||||
|
||||
// Situation #2 is a flex container frame into which we're inserting new
|
||||
// inline non-replaced children, adjacent to an existing anonymous flex item.
|
||||
if (aFrame->GetType() == nsGkAtoms::flexContainerFrame) {
|
||||
// Situation #2 is a flex or grid container frame into which we're inserting
|
||||
// new inline non-replaced children, adjacent to an existing anonymous
|
||||
// flex or grid item.
|
||||
if (::IsFlexOrGridContainer(aFrame)) {
|
||||
FCItemIterator iter(aItems);
|
||||
|
||||
// Check if we're adding to-be-wrapped content right *after* an existing
|
||||
|
|
|
@ -62,6 +62,7 @@ using namespace mozilla;
|
|||
using namespace mozilla::css;
|
||||
using namespace mozilla::layers;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::layout;
|
||||
typedef FrameMetrics::ViewID ViewID;
|
||||
|
||||
static inline nsIFrame*
|
||||
|
@ -1365,6 +1366,8 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
|
|||
}
|
||||
}
|
||||
|
||||
MaybeSetupTransactionIdAllocator(layerManager, view);
|
||||
|
||||
layerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer,
|
||||
aBuilder, flags);
|
||||
aBuilder->SetIsCompositingCheap(temp);
|
||||
|
|
|
@ -348,21 +348,21 @@ nsFrameManager::ClearAllUndisplayedContentIn(nsIContent* aParentContent)
|
|||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
nsresult
|
||||
void
|
||||
nsFrameManager::AppendFrames(nsContainerFrame* aParentFrame,
|
||||
ChildListID aListID,
|
||||
nsFrameList& aFrameList)
|
||||
{
|
||||
if (aParentFrame->IsAbsoluteContainer() &&
|
||||
aListID == aParentFrame->GetAbsoluteListID()) {
|
||||
return aParentFrame->GetAbsoluteContainingBlock()->
|
||||
AppendFrames(aParentFrame, aListID, aFrameList);
|
||||
aParentFrame->GetAbsoluteContainingBlock()->
|
||||
AppendFrames(aParentFrame, aListID, aFrameList);
|
||||
} else {
|
||||
return aParentFrame->AppendFrames(aListID, aFrameList);
|
||||
aParentFrame->AppendFrames(aListID, aFrameList);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
void
|
||||
nsFrameManager::InsertFrames(nsContainerFrame* aParentFrame,
|
||||
ChildListID aListID,
|
||||
nsIFrame* aPrevFrame,
|
||||
|
@ -375,14 +375,14 @@ nsFrameManager::InsertFrames(nsContainerFrame* aParentFrame,
|
|||
|
||||
if (aParentFrame->IsAbsoluteContainer() &&
|
||||
aListID == aParentFrame->GetAbsoluteListID()) {
|
||||
return aParentFrame->GetAbsoluteContainingBlock()->
|
||||
InsertFrames(aParentFrame, aListID, aPrevFrame, aFrameList);
|
||||
aParentFrame->GetAbsoluteContainingBlock()->
|
||||
InsertFrames(aParentFrame, aListID, aPrevFrame, aFrameList);
|
||||
} else {
|
||||
return aParentFrame->InsertFrames(aListID, aPrevFrame, aFrameList);
|
||||
aParentFrame->InsertFrames(aListID, aPrevFrame, aFrameList);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
void
|
||||
nsFrameManager::RemoveFrame(ChildListID aListID,
|
||||
nsIFrame* aOldFrame)
|
||||
{
|
||||
|
@ -404,19 +404,16 @@ nsFrameManager::RemoveFrame(ChildListID aListID,
|
|||
NS_ASSERTION(!(aOldFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW &&
|
||||
GetPlaceholderFrameFor(aOldFrame)),
|
||||
"Must call RemoveFrame on placeholder for out-of-flows.");
|
||||
nsresult rv = NS_OK;
|
||||
nsContainerFrame* parentFrame = aOldFrame->GetParent();
|
||||
if (parentFrame->IsAbsoluteContainer() &&
|
||||
aListID == parentFrame->GetAbsoluteListID()) {
|
||||
parentFrame->GetAbsoluteContainingBlock()->
|
||||
RemoveFrame(parentFrame, aListID, aOldFrame);
|
||||
} else {
|
||||
rv = parentFrame->RemoveFrame(aListID, aOldFrame);
|
||||
parentFrame->RemoveFrame(aListID, aOldFrame);
|
||||
}
|
||||
|
||||
mIsDestroyingFrames = wasDestroyingFrames;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
|
|
@ -114,17 +114,17 @@ public:
|
|||
NS_HIDDEN_(void) ClearAllUndisplayedContentIn(nsIContent* aParentContent);
|
||||
|
||||
// Functions for manipulating the frame model
|
||||
NS_HIDDEN_(nsresult) AppendFrames(nsContainerFrame* aParentFrame,
|
||||
ChildListID aListID,
|
||||
nsFrameList& aFrameList);
|
||||
NS_HIDDEN_(void) AppendFrames(nsContainerFrame* aParentFrame,
|
||||
ChildListID aListID,
|
||||
nsFrameList& aFrameList);
|
||||
|
||||
NS_HIDDEN_(nsresult) InsertFrames(nsContainerFrame* aParentFrame,
|
||||
ChildListID aListID,
|
||||
nsIFrame* aPrevFrame,
|
||||
nsFrameList& aFrameList);
|
||||
NS_HIDDEN_(void) InsertFrames(nsContainerFrame* aParentFrame,
|
||||
ChildListID aListID,
|
||||
nsIFrame* aPrevFrame,
|
||||
nsFrameList& aFrameList);
|
||||
|
||||
NS_HIDDEN_(nsresult) RemoveFrame(ChildListID aListID,
|
||||
nsIFrame* aOldFrame);
|
||||
NS_HIDDEN_(void) RemoveFrame(ChildListID aListID,
|
||||
nsIFrame* aOldFrame);
|
||||
|
||||
/*
|
||||
* Notification that a frame is about to be destroyed. This allows any
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "nsCSSAnonBoxes.h"
|
||||
#include "nsCSSColorUtils.h"
|
||||
#include "nsView.h"
|
||||
#include "nsViewManager.h"
|
||||
#include "nsPlaceholderFrame.h"
|
||||
#include "nsIScrollableFrame.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
|
@ -78,6 +79,7 @@
|
|||
#include "UnitTransforms.h"
|
||||
#include "TiledLayerBuffer.h" // For TILEDLAYERBUFFER_TILE_SIZE
|
||||
#include "ClientLayerManager.h"
|
||||
#include "nsRefreshDriver.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
|
@ -6635,3 +6637,19 @@ AutoMaybeDisableFontInflation::~AutoMaybeDisableFontInflation()
|
|||
mPresContext->mInflationDisabledForShrinkWrap = mOldValue;
|
||||
}
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace layout {
|
||||
|
||||
void
|
||||
MaybeSetupTransactionIdAllocator(layers::LayerManager* aManager, nsView* aView)
|
||||
{
|
||||
if (aManager->GetBackendType() == layers::LayersBackend::LAYERS_CLIENT) {
|
||||
layers::ClientLayerManager *manager = static_cast<layers::ClientLayerManager*>(aManager);
|
||||
nsRefreshDriver *refresh = aView->GetViewManager()->GetPresShell()->GetPresContext()->RefreshDriver();
|
||||
manager->SetTransactionIdAllocator(refresh);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ class HTMLVideoElement;
|
|||
} // namespace dom
|
||||
namespace layers {
|
||||
class Layer;
|
||||
class ClientLayerManager;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2295,6 +2296,8 @@ namespace mozilla {
|
|||
bool mOldValue;
|
||||
};
|
||||
|
||||
void MaybeSetupTransactionIdAllocator(layers::LayerManager* aManager, nsView* aView);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -189,6 +189,7 @@ using namespace mozilla::dom;
|
|||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::layers;
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::layout;
|
||||
|
||||
CapturingContentInfo nsIPresShell::gCaptureInfo =
|
||||
{ false /* mAllowed */, false /* mPointerLock */, false /* mRetargetToElement */,
|
||||
|
@ -4037,12 +4038,15 @@ PresShell::FlushPendingNotifications(mozilla::ChangesToFlush aFlush)
|
|||
}
|
||||
|
||||
if (aFlush.mFlushAnimations &&
|
||||
nsLayoutUtils::AreAsyncAnimationsEnabled() &&
|
||||
!mPresContext->StyleUpdateForAllAnimationsIsUpToDate()) {
|
||||
mPresContext->AnimationManager()->
|
||||
FlushAnimations(CommonAnimationManager::Cannot_Throttle);
|
||||
mPresContext->TransitionManager()->
|
||||
FlushTransitions(CommonAnimationManager::Cannot_Throttle);
|
||||
if (mPresContext->AnimationManager()) {
|
||||
mPresContext->AnimationManager()->
|
||||
FlushAnimations(CommonAnimationManager::Cannot_Throttle);
|
||||
}
|
||||
if (mPresContext->TransitionManager()) {
|
||||
mPresContext->TransitionManager()->
|
||||
FlushTransitions(CommonAnimationManager::Cannot_Throttle);
|
||||
}
|
||||
mPresContext->TickLastStyleUpdateForAllAnimations();
|
||||
}
|
||||
|
||||
|
@ -5871,6 +5875,8 @@ PresShell::Paint(nsView* aViewToPaint,
|
|||
LayerProperties::CloneFrom(layerManager->GetRoot()) :
|
||||
nullptr);
|
||||
|
||||
MaybeSetupTransactionIdAllocator(layerManager, aViewToPaint);
|
||||
|
||||
if (layerManager->EndEmptyTransaction((aFlags & PAINT_COMPOSITE) ?
|
||||
LayerManager::END_DEFAULT : LayerManager::END_NO_COMPOSITE)) {
|
||||
nsIntRegion invalid;
|
||||
|
@ -5931,6 +5937,7 @@ PresShell::Paint(nsView* aViewToPaint,
|
|||
root->SetVisibleRegion(bounds);
|
||||
layerManager->SetRoot(root);
|
||||
}
|
||||
MaybeSetupTransactionIdAllocator(layerManager, aViewToPaint);
|
||||
layerManager->EndTransaction(nullptr, nullptr, (aFlags & PAINT_COMPOSITE) ?
|
||||
LayerManager::END_DEFAULT : LayerManager::END_NO_COMPOSITE);
|
||||
}
|
||||
|
|
|
@ -686,12 +686,17 @@ nsRefreshDriver::nsRefreshDriver(nsPresContext* aPresContext)
|
|||
mReflowCause(nullptr),
|
||||
mStyleCause(nullptr),
|
||||
mPresContext(aPresContext),
|
||||
mRootRefresh(nullptr),
|
||||
mPendingTransaction(0),
|
||||
mCompletedTransaction(0),
|
||||
mFreezeCount(0),
|
||||
mThrottled(false),
|
||||
mTestControllingRefreshes(false),
|
||||
mViewManagerFlushIsPending(false),
|
||||
mRequestedHighPrecision(false),
|
||||
mInRefresh(false)
|
||||
mInRefresh(false),
|
||||
mWaitingForTransaction(false),
|
||||
mSkippedPaints(0)
|
||||
{
|
||||
mMostRecentRefreshEpochTime = JS_Now();
|
||||
mMostRecentRefresh = TimeStamp::Now();
|
||||
|
@ -703,6 +708,10 @@ nsRefreshDriver::~nsRefreshDriver()
|
|||
"observers should have unregistered");
|
||||
NS_ABORT_IF_FALSE(!mActiveTimer, "timer should be gone");
|
||||
|
||||
if (mRootRefresh) {
|
||||
mRootRefresh->RemoveRefreshObserver(this, Flush_Style);
|
||||
mRootRefresh = nullptr;
|
||||
}
|
||||
for (uint32_t i = 0; i < mPresShellsToInvalidateIfHidden.Length(); i++) {
|
||||
mPresShellsToInvalidateIfHidden[i]->InvalidatePresShellIfHidden();
|
||||
}
|
||||
|
@ -725,6 +734,11 @@ nsRefreshDriver::AdvanceTimeAndRefresh(int64_t aMilliseconds)
|
|||
mMostRecentRefresh = TimeStamp::Now();
|
||||
|
||||
mTestControllingRefreshes = true;
|
||||
if (mWaitingForTransaction) {
|
||||
// Disable any refresh driver throttling when entering test mode
|
||||
mWaitingForTransaction = false;
|
||||
mSkippedPaints = 0;
|
||||
}
|
||||
}
|
||||
|
||||
mMostRecentRefreshEpochTime += aMilliseconds * 1000;
|
||||
|
@ -739,6 +753,7 @@ nsRefreshDriver::RestoreNormalRefresh()
|
|||
{
|
||||
mTestControllingRefreshes = false;
|
||||
EnsureTimerStarted(false);
|
||||
mCompletedTransaction = mPendingTransaction;
|
||||
}
|
||||
|
||||
TimeStamp
|
||||
|
@ -1001,12 +1016,6 @@ nsRefreshDriver::ArrayFor(mozFlushType aFlushType)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* nsISupports implementation
|
||||
*/
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsRefreshDriver, nsISupports)
|
||||
|
||||
/*
|
||||
* nsITimerCallback implementation
|
||||
*/
|
||||
|
@ -1061,6 +1070,18 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
|||
mMostRecentRefresh = aNowTime;
|
||||
mMostRecentRefreshEpochTime = aNowEpoch;
|
||||
|
||||
if (IsWaitingForPaint()) {
|
||||
// We're currently suspended waiting for earlier Tick's to
|
||||
// be completed (on the Compositor). Mark that we missed the paint
|
||||
// and keep waiting.
|
||||
return;
|
||||
}
|
||||
if (mRootRefresh) {
|
||||
mRootRefresh->RemoveRefreshObserver(this, Flush_Style);
|
||||
mRootRefresh = nullptr;
|
||||
}
|
||||
mSkippedPaints = 0;
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
|
||||
if (!presShell || (ObserverCount() == 0 && ImageRequestCount() == 0)) {
|
||||
// Things are being destroyed, or we no longer have any observers.
|
||||
|
@ -1096,6 +1117,8 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
|||
}
|
||||
|
||||
if (i == 0) {
|
||||
// This is the Flush_Style case.
|
||||
|
||||
// Grab all of our frame request callbacks up front.
|
||||
nsTArray<DocumentFrameCallbacks>
|
||||
frameRequestCallbacks(mFrameRequestCallbackDocs.Length());
|
||||
|
@ -1137,7 +1160,6 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
|||
}
|
||||
profiler_tracing("Paint", "Scripts", TRACING_INTERVAL_END);
|
||||
|
||||
// This is the Flush_Style case.
|
||||
if (mPresContext && mPresContext->GetPresShell()) {
|
||||
bool tracingStyleFlush = false;
|
||||
nsAutoTArray<nsIPresShell*, 16> observers;
|
||||
|
@ -1167,6 +1189,10 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
|||
profiler_tracing("Paint", "Styles", TRACING_INTERVAL_END);
|
||||
}
|
||||
}
|
||||
|
||||
if (!nsLayoutUtils::AreAsyncAnimationsEnabled()) {
|
||||
mPresContext->TickLastStyleUpdateForAllAnimations();
|
||||
}
|
||||
} else if (i == 1) {
|
||||
// This is the Flush_Layout case.
|
||||
if (mPresContext && mPresContext->GetPresShell()) {
|
||||
|
@ -1355,6 +1381,114 @@ nsRefreshDriver::Thaw()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsRefreshDriver::FinishedWaitingForTransaction()
|
||||
{
|
||||
mWaitingForTransaction = false;
|
||||
if (mSkippedPaints &&
|
||||
!IsInRefresh() &&
|
||||
(ObserverCount() || ImageRequestCount())) {
|
||||
DoRefresh();
|
||||
}
|
||||
mSkippedPaints = 0;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
nsRefreshDriver::GetTransactionId()
|
||||
{
|
||||
++mPendingTransaction;
|
||||
|
||||
if (mPendingTransaction == mCompletedTransaction + 2 &&
|
||||
!mWaitingForTransaction &&
|
||||
!mTestControllingRefreshes) {
|
||||
mWaitingForTransaction = true;
|
||||
mSkippedPaints = 0;
|
||||
}
|
||||
|
||||
return mPendingTransaction;
|
||||
}
|
||||
|
||||
void
|
||||
nsRefreshDriver::RevokeTransactionId(uint64_t aTransactionId)
|
||||
{
|
||||
MOZ_ASSERT(aTransactionId == mPendingTransaction);
|
||||
if (mPendingTransaction == mCompletedTransaction + 2 &&
|
||||
mWaitingForTransaction) {
|
||||
MOZ_ASSERT(!mSkippedPaints, "How did we skip a paint when we're in the middle of one?");
|
||||
FinishedWaitingForTransaction();
|
||||
}
|
||||
mPendingTransaction--;
|
||||
}
|
||||
|
||||
void
|
||||
nsRefreshDriver::NotifyTransactionCompleted(uint64_t aTransactionId)
|
||||
{
|
||||
if (aTransactionId > mCompletedTransaction) {
|
||||
if (mPendingTransaction > mCompletedTransaction + 1 &&
|
||||
mWaitingForTransaction) {
|
||||
mCompletedTransaction = aTransactionId;
|
||||
FinishedWaitingForTransaction();
|
||||
} else {
|
||||
mCompletedTransaction = aTransactionId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsRefreshDriver::WillRefresh(mozilla::TimeStamp aTime)
|
||||
{
|
||||
mRootRefresh->RemoveRefreshObserver(this, Flush_Style);
|
||||
mRootRefresh = nullptr;
|
||||
if (mSkippedPaints) {
|
||||
DoRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsRefreshDriver::IsWaitingForPaint()
|
||||
{
|
||||
if (mTestControllingRefreshes) {
|
||||
return false;
|
||||
}
|
||||
// If we've skipped too many ticks then it's possible
|
||||
// that something went wrong and we're waiting on
|
||||
// a notification that will never arrive.
|
||||
static const uint32_t kMaxSkippedPaints = 10;
|
||||
if (mSkippedPaints > kMaxSkippedPaints) {
|
||||
mSkippedPaints = 0;
|
||||
mWaitingForTransaction = false;
|
||||
if (mRootRefresh) {
|
||||
mRootRefresh->RemoveRefreshObserver(this, Flush_Style);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (mWaitingForTransaction) {
|
||||
mSkippedPaints++;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try find the 'root' refresh driver for the current window and check
|
||||
// if that is waiting for a paint.
|
||||
nsPresContext *displayRoot = PresContext()->GetDisplayRootPresContext();
|
||||
if (displayRoot) {
|
||||
nsRefreshDriver *rootRefresh = displayRoot->GetRootPresContext()->RefreshDriver();
|
||||
if (rootRefresh && rootRefresh != this) {
|
||||
if (rootRefresh->IsWaitingForPaint()) {
|
||||
if (mRootRefresh != rootRefresh) {
|
||||
if (mRootRefresh) {
|
||||
mRootRefresh->RemoveRefreshObserver(this, Flush_Style);
|
||||
}
|
||||
rootRefresh->AddRefreshObserver(this, Flush_Style);
|
||||
mRootRefresh = rootRefresh;
|
||||
}
|
||||
mSkippedPaints++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
nsRefreshDriver::SetThrottled(bool aThrottled)
|
||||
{
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#include "mozilla/layers/TransactionIdAllocator.h"
|
||||
|
||||
class nsPresContext;
|
||||
class nsIPresShell;
|
||||
|
@ -62,7 +63,8 @@ public:
|
|||
virtual void DidRefresh() = 0;
|
||||
};
|
||||
|
||||
class nsRefreshDriver MOZ_FINAL : public nsISupports {
|
||||
class nsRefreshDriver MOZ_FINAL : public mozilla::layers::TransactionIdAllocator,
|
||||
public nsARefreshObserver {
|
||||
public:
|
||||
nsRefreshDriver(nsPresContext *aPresContext);
|
||||
~nsRefreshDriver();
|
||||
|
@ -70,9 +72,6 @@ public:
|
|||
static void InitializeStatics();
|
||||
static void Shutdown();
|
||||
|
||||
// nsISupports implementation
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
/**
|
||||
* Methods for testing, exposed via nsIDOMWindowUtils. See
|
||||
* nsIDOMWindowUtils.advanceTimeAndRefresh for description.
|
||||
|
@ -272,6 +271,17 @@ public:
|
|||
|
||||
bool IsInRefresh() { return mInRefresh; }
|
||||
|
||||
// mozilla::layers::TransactionIdAllocator
|
||||
virtual uint64_t GetTransactionId() MOZ_OVERRIDE;
|
||||
void NotifyTransactionCompleted(uint64_t aTransactionId) MOZ_OVERRIDE;
|
||||
void RevokeTransactionId(uint64_t aTransactionId) MOZ_OVERRIDE;
|
||||
|
||||
bool IsWaitingForPaint();
|
||||
|
||||
// nsARefreshObserver
|
||||
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) { return TransactionIdAllocator::AddRef(); }
|
||||
NS_IMETHOD_(MozExternalRefCountType) Release(void) { return TransactionIdAllocator::Release(); }
|
||||
virtual void WillRefresh(mozilla::TimeStamp aTime);
|
||||
private:
|
||||
typedef nsTObserverArray<nsARefreshObserver*> ObserverArray;
|
||||
typedef nsTHashtable<nsISupportsHashKey> RequestTable;
|
||||
|
@ -314,6 +324,8 @@ private:
|
|||
return mFrameRequestCallbackDocs.Length() != 0;
|
||||
}
|
||||
|
||||
void FinishedWaitingForTransaction();
|
||||
|
||||
mozilla::RefreshDriverTimer* ChooseTimer() const;
|
||||
mozilla::RefreshDriverTimer *mActiveTimer;
|
||||
|
||||
|
@ -323,6 +335,13 @@ private:
|
|||
nsPresContext *mPresContext; // weak; pres context passed in constructor
|
||||
// and unset in Disconnect
|
||||
|
||||
nsRefPtr<nsRefreshDriver> mRootRefresh;
|
||||
|
||||
// The most recently allocated transaction id.
|
||||
uint64_t mPendingTransaction;
|
||||
// The most recently completed transaction id.
|
||||
uint64_t mCompletedTransaction;
|
||||
|
||||
uint32_t mFreezeCount;
|
||||
bool mThrottled;
|
||||
bool mTestControllingRefreshes;
|
||||
|
@ -330,6 +349,14 @@ private:
|
|||
bool mRequestedHighPrecision;
|
||||
bool mInRefresh;
|
||||
|
||||
// True if the refresh driver is suspended waiting for transaction
|
||||
// id's to be returned and shouldn't do any work during Tick().
|
||||
bool mWaitingForTransaction;
|
||||
// True if Tick() was skipped because of mWaitingForTransaction and
|
||||
// we should schedule a new Tick immediately when resumed instead
|
||||
// of waiting until the next interval.
|
||||
uint32_t mSkippedPaints;
|
||||
|
||||
int64_t mMostRecentRefreshEpochTime;
|
||||
mozilla::TimeStamp mMostRecentRefresh;
|
||||
|
||||
|
|
|
@ -1350,11 +1350,10 @@ nsComboboxControlFrame::GetChildLists(nsTArray<ChildList>* aLists) const
|
|||
mPopupFrames.AppendIfNonempty(aLists, kSelectPopupList);
|
||||
}
|
||||
|
||||
nsresult
|
||||
void
|
||||
nsComboboxControlFrame::SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
if (kSelectPopupList == aListID) {
|
||||
mPopupFrames.SetFrames(aChildList);
|
||||
} else {
|
||||
|
@ -1367,9 +1366,8 @@ nsComboboxControlFrame::SetInitialChildList(ChildListID aListID,
|
|||
}
|
||||
}
|
||||
NS_ASSERTION(mButtonFrame, "missing button frame in initial child list");
|
||||
rv = nsBlockFrame::SetInitialChildList(aListID, aChildList);
|
||||
nsBlockFrame::SetInitialChildList(aListID, aChildList);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
|
|
@ -105,8 +105,8 @@ public:
|
|||
virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
|
||||
#endif
|
||||
virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE;
|
||||
virtual nsresult SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList) MOZ_OVERRIDE;
|
||||
virtual void SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList) MOZ_OVERRIDE;
|
||||
virtual const nsFrameList& GetChildList(ChildListID aListID) const MOZ_OVERRIDE;
|
||||
virtual void GetChildLists(nsTArray<ChildList>* aLists) const MOZ_OVERRIDE;
|
||||
|
||||
|
|
|
@ -43,17 +43,6 @@ nsFieldSetFrame::GetType() const
|
|||
return nsGkAtoms::fieldSetFrame;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
nsresult
|
||||
nsFieldSetFrame::SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList)
|
||||
{
|
||||
nsresult rv = nsContainerFrame::SetInitialChildList(kPrincipalList, aChildList);
|
||||
MOZ_ASSERT(GetInner());
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsRect
|
||||
nsFieldSetFrame::VisualBorderRectRelativeToSelf() const
|
||||
{
|
||||
|
@ -556,30 +545,36 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
|
|||
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
|
||||
}
|
||||
|
||||
nsresult
|
||||
#ifdef DEBUG
|
||||
void
|
||||
nsFieldSetFrame::SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList)
|
||||
{
|
||||
nsContainerFrame::SetInitialChildList(kPrincipalList, aChildList);
|
||||
MOZ_ASSERT(GetInner());
|
||||
}
|
||||
void
|
||||
nsFieldSetFrame::AppendFrames(ChildListID aListID,
|
||||
nsFrameList& aFrameList)
|
||||
{
|
||||
MOZ_CRASH("nsFieldSetFrame::AppendFrames not supported");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
void
|
||||
nsFieldSetFrame::InsertFrames(ChildListID aListID,
|
||||
nsIFrame* aPrevFrame,
|
||||
nsFrameList& aFrameList)
|
||||
{
|
||||
MOZ_CRASH("nsFieldSetFrame::InsertFrames not supported");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
void
|
||||
nsFieldSetFrame::RemoveFrame(ChildListID aListID,
|
||||
nsIFrame* aOldFrame)
|
||||
{
|
||||
MOZ_CRASH("nsFieldSetFrame::RemoveFrame not supported");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
a11y::AccType
|
||||
|
|
|
@ -45,13 +45,17 @@ public:
|
|||
void PaintBorderBackground(nsRenderingContext& aRenderingContext,
|
||||
nsPoint aPt, const nsRect& aDirtyRect, uint32_t aBGFlags);
|
||||
|
||||
virtual nsresult AppendFrames(ChildListID aListID,
|
||||
nsFrameList& aFrameList) MOZ_OVERRIDE;
|
||||
virtual nsresult InsertFrames(ChildListID aListID,
|
||||
nsIFrame* aPrevFrame,
|
||||
nsFrameList& aFrameList) MOZ_OVERRIDE;
|
||||
virtual nsresult RemoveFrame(ChildListID aListID,
|
||||
nsIFrame* aOldFrame) MOZ_OVERRIDE;
|
||||
#ifdef DEBUG
|
||||
virtual void SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList) MOZ_OVERRIDE;
|
||||
virtual void AppendFrames(ChildListID aListID,
|
||||
nsFrameList& aFrameList) MOZ_OVERRIDE;
|
||||
virtual void InsertFrames(ChildListID aListID,
|
||||
nsIFrame* aPrevFrame,
|
||||
nsFrameList& aFrameList) MOZ_OVERRIDE;
|
||||
virtual void RemoveFrame(ChildListID aListID,
|
||||
nsIFrame* aOldFrame) MOZ_OVERRIDE;
|
||||
#endif
|
||||
|
||||
virtual nsIAtom* GetType() const MOZ_OVERRIDE;
|
||||
virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE
|
||||
|
@ -68,11 +72,6 @@ public:
|
|||
virtual mozilla::a11y::AccType AccessibleType() MOZ_OVERRIDE;
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual nsresult SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList) MOZ_OVERRIDE;
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE {
|
||||
return MakeFrameName(NS_LITERAL_STRING("FieldSet"), aResult);
|
||||
|
|
|
@ -373,27 +373,26 @@ nsHTMLButtonControlFrame::SetAdditionalStyleContext(int32_t aIndex,
|
|||
mRenderer.SetStyleContext(aIndex, aStyleContext);
|
||||
}
|
||||
|
||||
nsresult
|
||||
#ifdef DEBUG
|
||||
void
|
||||
nsHTMLButtonControlFrame::AppendFrames(ChildListID aListID,
|
||||
nsFrameList& aFrameList)
|
||||
{
|
||||
NS_NOTREACHED("unsupported operation");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
MOZ_CRASH("unsupported operation");
|
||||
}
|
||||
|
||||
nsresult
|
||||
void
|
||||
nsHTMLButtonControlFrame::InsertFrames(ChildListID aListID,
|
||||
nsIFrame* aPrevFrame,
|
||||
nsFrameList& aFrameList)
|
||||
{
|
||||
NS_NOTREACHED("unsupported operation");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
MOZ_CRASH("unsupported operation");
|
||||
}
|
||||
|
||||
nsresult
|
||||
void
|
||||
nsHTMLButtonControlFrame::RemoveFrame(ChildListID aListID,
|
||||
nsIFrame* aOldFrame)
|
||||
{
|
||||
NS_NOTREACHED("unsupported operation");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
MOZ_CRASH("unsupported operation");
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -51,15 +51,15 @@ public:
|
|||
virtual void SetAdditionalStyleContext(int32_t aIndex,
|
||||
nsStyleContext* aStyleContext) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult AppendFrames(ChildListID aListID,
|
||||
nsFrameList& aFrameList) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult InsertFrames(ChildListID aListID,
|
||||
nsIFrame* aPrevFrame,
|
||||
nsFrameList& aFrameList) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult RemoveFrame(ChildListID aListID,
|
||||
nsIFrame* aOldFrame) MOZ_OVERRIDE;
|
||||
#ifdef DEBUG
|
||||
virtual void AppendFrames(ChildListID aListID,
|
||||
nsFrameList& aFrameList) MOZ_OVERRIDE;
|
||||
virtual void InsertFrames(ChildListID aListID,
|
||||
nsIFrame* aPrevFrame,
|
||||
nsFrameList& aFrameList) MOZ_OVERRIDE;
|
||||
virtual void RemoveFrame(ChildListID aListID,
|
||||
nsIFrame* aOldFrame) MOZ_OVERRIDE;
|
||||
#endif
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
virtual mozilla::a11y::AccType AccessibleType() MOZ_OVERRIDE;
|
||||
|
|
|
@ -895,7 +895,7 @@ nsListControlFrame::HandleEvent(nsPresContext* aPresContext,
|
|||
|
||||
|
||||
//---------------------------------------------------------
|
||||
nsresult
|
||||
void
|
||||
nsListControlFrame::SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList)
|
||||
{
|
||||
|
@ -905,7 +905,7 @@ nsListControlFrame::SetInitialChildList(ChildListID aListID,
|
|||
mIsAllFramesHere = false;
|
||||
mHasBeenInitialized = false;
|
||||
}
|
||||
nsresult rv = nsHTMLScrollFrame::SetInitialChildList(aListID, aChildList);
|
||||
nsHTMLScrollFrame::SetInitialChildList(aListID, aChildList);
|
||||
|
||||
// If all the content is here now check
|
||||
// to see if all the frames have been created
|
||||
|
@ -917,8 +917,6 @@ nsListControlFrame::SetInitialChildList(ChildListID aListID,
|
|||
mHasBeenInitialized = true;
|
||||
}
|
||||
}*/
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
|
|
@ -63,8 +63,8 @@ public:
|
|||
mozilla::WidgetGUIEvent* aEvent,
|
||||
nsEventStatus* aEventStatus) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList) MOZ_OVERRIDE;
|
||||
virtual void SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList) MOZ_OVERRIDE;
|
||||
|
||||
virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
|
||||
virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
|
||||
|
|
|
@ -1184,11 +1184,11 @@ nsTextControlFrame::GetMaxLength(int32_t* aSize)
|
|||
|
||||
// END IMPLEMENTING NS_IFORMCONTROLFRAME
|
||||
|
||||
nsresult
|
||||
void
|
||||
nsTextControlFrame::SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList)
|
||||
{
|
||||
nsresult rv = nsContainerFrame::SetInitialChildList(aListID, aChildList);
|
||||
nsContainerFrame::SetInitialChildList(aListID, aChildList);
|
||||
|
||||
nsIFrame* first = GetFirstPrincipalChild();
|
||||
|
||||
|
@ -1216,7 +1216,6 @@ nsTextControlFrame::SetInitialChildList(ChildListID aListID,
|
|||
delete contentScrollPos;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -85,10 +85,8 @@ public:
|
|||
virtual void AppendAnonymousContentTo(nsBaseContentList& aElements,
|
||||
uint32_t aFilter) MOZ_OVERRIDE;
|
||||
|
||||
// Utility methods to set current widget state
|
||||
|
||||
virtual nsresult SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList) MOZ_OVERRIDE;
|
||||
virtual void SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList) MOZ_OVERRIDE;
|
||||
|
||||
virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
|
||||
/*
|
||||
user_pref("layout.css.grid.enabled", true);
|
||||
*/
|
||||
|
||||
function boom()
|
||||
{
|
||||
document.getElementById("r").appendChild(document.createTextNode("B"));
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="boom();">
|
||||
<div id="r" style="display: grid;">A</div>
|
||||
</body>
|
||||
</html>
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче