This commit is contained in:
Tim Taubert 2014-05-29 08:32:31 +02:00
Родитель 8fd49b9c7b f634ff5c34
Коммит 96c549d105
233 изменённых файлов: 3219 добавлений и 2328 удалений

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

@ -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);

195
js/ipc/JavaScriptLogging.h Normal file
Просмотреть файл

@ -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;
}

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

@ -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>

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше