Merge inbound to m-c on a CLOSED TREE.

This commit is contained in:
Ryan VanderMeulen 2013-08-29 16:04:45 -04:00
commit 51102e8743
80 changed files with 948 additions and 489 deletions

View File

@ -57,6 +57,13 @@ struct ImageValue;
/**
* A class used to construct a nsString from a nsStringBuffer (we might
* want to move this to nsString at some point).
*
* WARNING: Note that nsCheapString doesn't take an explicit length -- it
* assumes the string is maximally large, given the nsStringBuffer's storage
* size. This means the given string buffer *must* be sized exactly correctly
* for the string it contains (including one byte for a null terminator). If
* it has any unused storage space, then that will result in bogus characters
* at the end of our nsCheapString.
*/
class nsCheapString : public nsString {
public:

View File

@ -99,6 +99,19 @@ nsDOMTokenList::CheckToken(const nsAString& aStr)
return NS_OK;
}
nsresult
nsDOMTokenList::CheckTokens(const nsTArray<nsString>& aTokens)
{
for (uint32_t i = 0, l = aTokens.Length(); i < l; ++i) {
nsresult rv = CheckToken(aTokens[i]);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
}
bool
nsDOMTokenList::Contains(const nsAString& aToken, ErrorResult& aError)
{
@ -113,7 +126,7 @@ nsDOMTokenList::Contains(const nsAString& aToken, ErrorResult& aError)
void
nsDOMTokenList::AddInternal(const nsAttrValue* aAttr,
const nsAString& aToken)
const nsTArray<nsString>& aTokens)
{
if (!mElement) {
return;
@ -125,36 +138,56 @@ nsDOMTokenList::AddInternal(const nsAttrValue* aAttr,
aAttr->ToString(resultStr);
}
if (!resultStr.IsEmpty() &&
!nsContentUtils::IsHTMLWhitespace(
resultStr.CharAt(resultStr.Length() - 1))) {
resultStr.Append(NS_LITERAL_STRING(" ") + aToken);
} else {
resultStr.Append(aToken);
bool oneWasAdded = false;
nsAutoTArray<nsString, 10> addedClasses;
addedClasses.SetCapacity(aTokens.Length());
for (uint32_t i = 0, l = aTokens.Length(); i < l; ++i) {
const nsString& aToken = aTokens[i];
if ((aAttr && aAttr->Contains(aToken)) ||
addedClasses.Contains(aToken)) {
continue;
}
if (oneWasAdded ||
(!resultStr.IsEmpty() &&
!nsContentUtils::IsHTMLWhitespace(resultStr.Last()))) {
resultStr.Append(NS_LITERAL_STRING(" ") + aToken);
} else {
resultStr.Append(aToken);
}
oneWasAdded = true;
addedClasses.AppendElement(aToken);
}
mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true);
}
void
nsDOMTokenList::Add(const nsAString& aToken, ErrorResult& aError)
nsDOMTokenList::Add(const nsTArray<nsString>& aTokens, ErrorResult& aError)
{
aError = CheckToken(aToken);
aError = CheckTokens(aTokens);
if (aError.Failed()) {
return;
}
const nsAttrValue* attr = GetParsedAttr();
AddInternal(attr, aTokens);
}
if (attr && attr->Contains(aToken)) {
return;
}
AddInternal(attr, aToken);
void
nsDOMTokenList::Add(const nsAString& aToken, mozilla::ErrorResult& aError)
{
nsAutoTArray<nsString, 1> aTokens;
aTokens.AppendElement(aToken);
Add(aTokens, aError);
}
void
nsDOMTokenList::RemoveInternal(const nsAttrValue* aAttr,
const nsAString& aToken)
const nsTArray<nsString>& aTokens)
{
NS_ABORT_IF_FALSE(aAttr, "Need an attribute");
@ -189,7 +222,7 @@ nsDOMTokenList::RemoveInternal(const nsAttrValue* aAttr,
++iter;
} while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter));
if (Substring(tokenStart, iter).Equals(aToken)) {
if (aTokens.Contains(Substring(tokenStart, iter))) {
// Skip whitespace after the token, it will be collapsed.
while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
@ -202,7 +235,7 @@ nsDOMTokenList::RemoveInternal(const nsAttrValue* aAttr,
if (lastTokenRemoved && !output.IsEmpty()) {
NS_ABORT_IF_FALSE(!nsContentUtils::IsHTMLWhitespace(
output.CharAt(output.Length() - 1)), "Invalid last output token");
output.Last()), "Invalid last output token");
output.Append(PRUnichar(' '));
}
lastTokenRemoved = false;
@ -215,19 +248,27 @@ nsDOMTokenList::RemoveInternal(const nsAttrValue* aAttr,
}
void
nsDOMTokenList::Remove(const nsAString& aToken, ErrorResult& aError)
nsDOMTokenList::Remove(const nsTArray<nsString>& aTokens, ErrorResult& aError)
{
aError = CheckToken(aToken);
aError = CheckTokens(aTokens);
if (aError.Failed()) {
return;
}
const nsAttrValue* attr = GetParsedAttr();
if (!attr || !attr->Contains(aToken)) {
if (!attr) {
return;
}
RemoveInternal(attr, aToken);
RemoveInternal(attr, aTokens);
}
void
nsDOMTokenList::Remove(const nsAString& aToken, mozilla::ErrorResult& aError)
{
nsAutoTArray<nsString, 1> aTokens;
aTokens.AppendElement(aToken);
Remove(aTokens, aError);
}
bool
@ -245,15 +286,17 @@ nsDOMTokenList::Toggle(const nsAString& aToken,
const bool forceOff = aForce.WasPassed() && !aForce.Value();
bool isPresent = attr && attr->Contains(aToken);
nsAutoTArray<nsString, 1> aTokens;
aTokens.AppendElement(aToken);
if (isPresent) {
if (!forceOn) {
RemoveInternal(attr, aToken);
RemoveInternal(attr, aTokens);
isPresent = false;
}
} else {
if (!forceOff) {
AddInternal(attr, aToken);
AddInternal(attr, aTokens);
isPresent = true;
}
}

View File

@ -59,7 +59,11 @@ public:
void IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aResult);
bool Contains(const nsAString& aToken, mozilla::ErrorResult& aError);
void Add(const nsAString& aToken, mozilla::ErrorResult& aError);
void Add(const nsTArray<nsString>& aTokens,
mozilla::ErrorResult& aError);
void Remove(const nsAString& aToken, mozilla::ErrorResult& aError);
void Remove(const nsTArray<nsString>& aTokens,
mozilla::ErrorResult& aError);
bool Toggle(const nsAString& aToken,
const mozilla::dom::Optional<bool>& force,
mozilla::ErrorResult& aError);
@ -69,8 +73,11 @@ protected:
virtual ~nsDOMTokenList();
nsresult CheckToken(const nsAString& aStr);
void AddInternal(const nsAttrValue* aAttr, const nsAString& aToken);
void RemoveInternal(const nsAttrValue* aAttr, const nsAString& aToken);
nsresult CheckTokens(const nsTArray<nsString>& aStr);
void AddInternal(const nsAttrValue* aAttr,
const nsTArray<nsString>& aTokens);
void RemoveInternal(const nsAttrValue* aAttr,
const nsTArray<nsString>& aTokens);
inline const nsAttrValue* GetParsedAttr();
Element* mElement;

View File

@ -36,6 +36,10 @@ function onAttrModified(event) {
}
function checkModification(e, funcName, args, expectedRes, before, after, expectedException) {
if (!Array.isArray(args)) {
args = [args];
}
var shouldThrow = typeof(expectedException) === "string";
if (shouldThrow) {
// If an exception is thrown, the class attribute shouldn't change.
@ -259,12 +263,14 @@ function testClassList(e) {
// add() method
function checkAdd(before, argument, after, expectedException) {
checkModification(e, "add", [argument], null, before, after, expectedException);
checkModification(e, "add", argument, null, before, after, expectedException);
}
checkAdd(null, "", null, "SyntaxError");
checkAdd(null, ["a", ""], null, "SyntaxError");
checkAdd(null, " ", null, "InvalidCharacterError");
checkAdd(null, "aa ", null, "InvalidCharacterError");
checkAdd(null, ["a", " "], null, "InvalidCharacterError");
checkAdd(null, ["a", "aa "], null, "InvalidCharacterError");
checkAdd("a", "a", "a");
checkAdd("aa", "AA", "aa AA");
@ -278,6 +284,14 @@ function testClassList(e) {
checkAdd("a b c", "d", "a b c d");
checkAdd("a b c ", "d", "a b c d");
// multiple add
checkAdd("a b c ", ["d", "e"], "a b c d e");
checkAdd("a b c ", ["a", "a"], "a b c ");
checkAdd("a b c ", ["d", "d"], "a b c d");
checkAdd("a b c ", [], "a b c ");
checkAdd(null, ["a", "b"], "a b");
checkAdd("", ["a", "b"], "a b");
// Test for bug 530171
checkAdd(null, null, "null");
checkAdd(null, undefined, "undefined");
@ -285,7 +299,7 @@ function testClassList(e) {
// remove() method
function checkRemove(before, argument, after, expectedException) {
checkModification(e, "remove", [argument], null, before, after, expectedException);
checkModification(e, "remove", argument, null, before, after, expectedException);
}
checkRemove(null, "", null, "SyntaxError");
@ -317,6 +331,16 @@ function testClassList(e) {
checkRemove("\ra\na\ta\f", "a", "");
// multiple remove
checkRemove("a b c ", ["d", "e"], "a b c ");
checkRemove("a b c ", ["a", "b"], "c ");
checkRemove("a b c ", ["a", "c"], "b");
checkRemove("a b c ", ["a", "a"], "b c ");
checkRemove("a b c ", ["d", "d"], "a b c ");
checkRemove("a b c ", [], "a b c ");
checkRemove(null, ["a", "b"], null);
checkRemove("", ["a", "b"], "");
// Test for bug 530171
checkRemove("null", null, "");
checkRemove("undefined", undefined, "");
@ -324,7 +348,7 @@ function testClassList(e) {
// toggle() method
function checkToggle(before, argument, expectedRes, after, expectedException) {
checkModification(e, "toggle", [argument], expectedRes, before, after, expectedException);
checkModification(e, "toggle", argument, expectedRes, before, after, expectedException);
}
checkToggle(null, "", null, null, "SyntaxError");

View File

@ -13,10 +13,3 @@ JSObject*
WebGLActiveInfo::WrapObject(JSContext *cx, JS::Handle<JSObject*> scope) {
return dom::WebGLActiveInfoBinding::Wrap(cx, scope, this);
}
NS_IMPL_ADDREF(WebGLActiveInfo)
NS_IMPL_RELEASE(WebGLActiveInfo)
NS_INTERFACE_MAP_BEGIN(WebGLActiveInfo)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END

View File

@ -19,7 +19,6 @@ template <typename T> class Handle;
namespace mozilla {
class WebGLActiveInfo MOZ_FINAL
: public nsISupports
{
public:
WebGLActiveInfo(WebGLint size, WebGLenum type, const nsACString& name) :
@ -44,7 +43,7 @@ public:
JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> scope);
NS_DECL_ISUPPORTS
NS_INLINE_DECL_REFCOUNTING(WebGLActiveInfo)
protected:
WebGLint mSize;

View File

@ -61,10 +61,5 @@ WebGLBuffer::WrapObject(JSContext *cx, JS::Handle<JSObject*> scope) {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLBuffer)
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLBuffer)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLBuffer)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLBuffer)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLBuffer, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLBuffer, Release)

View File

@ -20,11 +20,10 @@ namespace mozilla {
class WebGLElementArrayCache;
class WebGLBuffer MOZ_FINAL
: public nsISupports
: public nsWrapperCache
, public WebGLRefCountedObject<WebGLBuffer>
, public LinkedListElement<WebGLBuffer>
, public WebGLContextBoundObject
, public nsWrapperCache
{
public:
WebGLBuffer(WebGLContext *context);
@ -63,8 +62,8 @@ public:
virtual JSObject* WrapObject(JSContext *cx,
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebGLBuffer)
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLBuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLBuffer)
protected:

View File

@ -532,9 +532,11 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
const char* aName,
uint32_t aFlags = 0)
{
CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
aCallback.NoteXPCOMChild(aField.mTexturePtr);
aCallback.NoteXPCOMChild(aField.mRenderbufferPtr);
CycleCollectionNoteChild(aCallback, aField.mTexturePtr.get(),
aName, aFlags);
CycleCollectionNoteChild(aCallback, aField.mRenderbufferPtr.get(),
aName, aFlags);
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_7(WebGLFramebuffer,
@ -546,10 +548,5 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_7(WebGLFramebuffer,
mDepthStencilAttachment.mTexturePtr,
mDepthStencilAttachment.mRenderbufferPtr)
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLFramebuffer)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLFramebuffer)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLFramebuffer)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLFramebuffer, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLFramebuffer, Release)

View File

@ -18,11 +18,10 @@ class WebGLTexture;
class WebGLRenderbuffer;
class WebGLFramebuffer MOZ_FINAL
: public nsISupports
: public nsWrapperCache
, public WebGLRefCountedObject<WebGLFramebuffer>
, public LinkedListElement<WebGLFramebuffer>
, public WebGLContextBoundObject
, public nsWrapperCache
{
public:
WebGLFramebuffer(WebGLContext *context);
@ -149,8 +148,8 @@ public:
virtual JSObject* WrapObject(JSContext *cx,
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebGLFramebuffer)
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
bool CheckAndInitializeRenderbuffers();

View File

@ -329,8 +329,7 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
const char* aName,
uint32_t aFlags = 0)
{
CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
aCallback.NoteXPCOMChild(aField);
CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
}
#endif

View File

@ -245,10 +245,5 @@ WebGLProgram::GetUniformInfoForMappedIdentifier(const nsACString& name) {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(WebGLProgram, mAttachedShaders)
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLProgram)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLProgram)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLProgram)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLProgram, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLProgram, Release)

View File

@ -22,11 +22,10 @@ typedef nsDataHashtable<nsCStringHashKey, nsCString> CStringMap;
typedef nsDataHashtable<nsCStringHashKey, WebGLUniformInfo> CStringToUniformInfoMap;
class WebGLProgram MOZ_FINAL
: public nsISupports
: public nsWrapperCache
, public WebGLRefCountedObject<WebGLProgram>
, public LinkedListElement<WebGLProgram>
, public WebGLContextBoundObject
, public nsWrapperCache
{
public:
WebGLProgram(WebGLContext *context);
@ -107,8 +106,8 @@ public:
virtual JSObject* WrapObject(JSContext *cx,
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebGLProgram)
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLProgram)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLProgram)
// public post-link data
std::map<GLint, nsCString> mActiveAttribMap;

View File

@ -67,10 +67,5 @@ WebGLRenderbuffer::MemoryUsage() const {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLRenderbuffer)
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLRenderbuffer)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLRenderbuffer)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLRenderbuffer)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLRenderbuffer, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLRenderbuffer, Release)

View File

@ -15,12 +15,11 @@
namespace mozilla {
class WebGLRenderbuffer MOZ_FINAL
: public nsISupports
: public nsWrapperCache
, public WebGLRefCountedObject<WebGLRenderbuffer>
, public LinkedListElement<WebGLRenderbuffer>
, public WebGLRectangleObject
, public WebGLContextBoundObject
, public nsWrapperCache
{
public:
WebGLRenderbuffer(WebGLContext *context);
@ -53,8 +52,8 @@ public:
virtual JSObject* WrapObject(JSContext *cx,
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebGLRenderbuffer)
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLRenderbuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLRenderbuffer)
protected:

View File

@ -53,10 +53,5 @@ WebGLShader::SetTranslationSuccess() {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLShader)
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLShader)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLShader)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLShader)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLShader, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLShader, Release)

View File

@ -24,11 +24,10 @@ struct WebGLMappedIdentifier {
};
class WebGLShader MOZ_FINAL
: public nsISupports
: public nsWrapperCache
, public WebGLRefCountedObject<WebGLShader>
, public LinkedListElement<WebGLShader>
, public WebGLContextBoundObject
, public nsWrapperCache
{
friend class WebGLContext;
friend class WebGLProgram;
@ -80,8 +79,8 @@ public:
virtual JSObject* WrapObject(JSContext *cx,
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebGLShader)
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLShader)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLShader)
protected:

View File

@ -9,13 +9,6 @@
using namespace mozilla;
NS_INTERFACE_MAP_BEGIN(WebGLShaderPrecisionFormat)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(WebGLShaderPrecisionFormat)
NS_IMPL_RELEASE(WebGLShaderPrecisionFormat)
JSObject*
WebGLShaderPrecisionFormat::WrapObject(JSContext *cx, JS::Handle<JSObject*> scope)
{

View File

@ -13,8 +13,7 @@ namespace mozilla {
class WebGLBuffer;
class WebGLShaderPrecisionFormat MOZ_FINAL
: public nsISupports
, public WebGLContextBoundObject
: public WebGLContextBoundObject
{
public:
WebGLShaderPrecisionFormat(WebGLContext *context, WebGLint rangeMin, WebGLint rangeMax, WebGLint precision) :
@ -27,8 +26,6 @@ public:
JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> scope);
NS_DECL_ISUPPORTS
// WebIDL WebGLShaderPrecisionFormat API
WebGLint RangeMin() const {
return mRangeMin;
@ -40,6 +37,8 @@ public:
return mPrecision;
}
NS_INLINE_DECL_REFCOUNTING(WebGLShaderPrecisionFormat)
protected:
WebGLint mRangeMin;
WebGLint mRangeMax;

View File

@ -360,10 +360,5 @@ WebGLTexture::NeedFakeBlack() {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTexture)
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLTexture)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLTexture)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLTexture)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLTexture, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLTexture, Release)

View File

@ -24,11 +24,10 @@ inline bool is_pot_assuming_nonnegative(WebGLsizei x)
// NOTE: When this class is switched to new DOM bindings, update the (then-slow)
// WrapObject calls in GetParameter and GetFramebufferAttachmentParameter.
class WebGLTexture MOZ_FINAL
: public nsISupports
: public nsWrapperCache
, public WebGLRefCountedObject<WebGLTexture>
, public LinkedListElement<WebGLTexture>
, public WebGLContextBoundObject
, public nsWrapperCache
{
public:
WebGLTexture(WebGLContext *context);
@ -51,8 +50,8 @@ public:
virtual JSObject* WrapObject(JSContext *cx,
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebGLTexture)
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTexture)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTexture)
protected:

View File

@ -29,9 +29,5 @@ WebGLUniformLocation::WebGLUniformLocation(WebGLContext *context, WebGLProgram *
NS_IMPL_CYCLE_COLLECTION_1(WebGLUniformLocation, mProgram)
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLUniformLocation)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLUniformLocation)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLUniformLocation)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLUniformLocation, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLUniformLocation, Release)

View File

@ -14,8 +14,7 @@ namespace mozilla {
class WebGLProgram;
class WebGLUniformLocation MOZ_FINAL
: public nsISupports
, public WebGLContextBoundObject
: public WebGLContextBoundObject
{
public:
WebGLUniformLocation(WebGLContext *context, WebGLProgram *program, GLint location, const WebGLUniformInfo& info);
@ -36,8 +35,8 @@ public:
JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> scope);
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(WebGLUniformLocation)
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLUniformLocation)
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(WebGLUniformLocation)
protected:
// nsRefPtr, not WebGLRefPtr, so that we don't prevent the program from being explicitly deleted.

View File

@ -75,8 +75,7 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
const char* aName,
uint32_t aFlags = 0)
{
CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
aCallback.NoteXPCOMChild(aField.buf);
CycleCollectionNoteChild(aCallback, aField.buf.get(), aName, aFlags);
}
#endif

View File

@ -66,9 +66,8 @@
MochiKit.DOM.addLoadEvent(function () {
var canvas = document.getElementById("canvas");
try {
gl = canvas.getContext("experimental-webgl");
} catch (e) {
gl = canvas.getContext("experimental-webgl");
if (!gl) {
todo(false, "Canvas WebGL not supported");
SimpleTest.finish();
return;

View File

@ -804,6 +804,7 @@ HTMLCanvasElement::GetContext(JSContext* aCx,
rv = UpdateContext(aCx, aContextOptions);
if (rv.Failed()) {
rv = NS_OK; // See bug 645792
return nullptr;
}
mCurrentContextId.Assign(aContextId);

View File

@ -382,7 +382,8 @@ void* MediaDecoderReader::VideoQueueMemoryFunctor::operator()(void* anObject) {
}
MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder)
: mDecoder(aDecoder)
: mDecoder(aDecoder),
mIgnoreAudioOutputFormat(false)
{
MOZ_COUNT_CTOR(MediaDecoderReader);
}

View File

@ -467,6 +467,14 @@ public:
// decode thread could start up and run in future.
virtual void OnDecodeThreadFinish() {}
// Tell the reader that the data decoded are not for direct playback, so it
// can accept more files, in particular those which have more channels than
// available in the audio output.
void SetIgnoreAudioOutputFormat()
{
mIgnoreAudioOutputFormat = true;
}
protected:
// Queue of audio frames. This queue is threadsafe, and is accessed from
// the audio, decoder, state machine, and main threads.
@ -543,6 +551,11 @@ protected:
// Stores presentation info required for playback.
VideoInfo mInfo;
// Whether we should accept media that we know we can't play
// directly, because they have a number of channel higher than
// what we support.
bool mIgnoreAudioOutputFormat;
};
} // namespace mozilla

View File

@ -61,7 +61,8 @@ static const uint16_t WAVE_FORMAT_CHUNK_SIZE = 16;
// supported by AudioStream.
static const uint16_t WAVE_FORMAT_ENCODING_PCM = 1;
// Maximum number of channels supported
// We reject files with more than this number of channels if we're decoding for
// playback.
static const uint8_t MAX_CHANNELS = 2;
namespace {
@ -430,12 +431,14 @@ WaveReader::LoadFormatChunk(uint32_t aChunkSize)
// Make sure metadata is fairly sane. The rate check is fairly arbitrary,
// but the channels check is intentionally limited to mono or stereo
// because that's what the audio backend currently supports.
// when the media is intended for direct playback because that's what the
// audio backend currently supports.
unsigned int actualFrameSize = sampleFormat == 8 ? 1 : 2 * channels;
if (rate < 100 || rate > 96000 ||
channels < 1 || channels > MAX_CHANNELS ||
(frameSize != 1 && frameSize != 2 && frameSize != 4) ||
(sampleFormat != 8 && sampleFormat != 16) ||
(((channels < 1 || channels > MAX_CHANNELS) ||
(frameSize != 1 && frameSize != 2 && frameSize != 4)) &&
!mIgnoreAudioOutputFormat) ||
(sampleFormat != 8 && sampleFormat != 16) ||
frameSize != actualFrameSize) {
NS_WARNING("Invalid WAVE metadata");
return false;

View File

@ -508,6 +508,11 @@ MediaDecodeTask::Decode()
mBufferDecoder->BeginDecoding(NS_GetCurrentThread());
// Tell the decoder reader that we are not going to play the data directly,
// and that we should not reject files with more channels than the audio
// bakend support.
mDecoderReader->SetIgnoreAudioOutputFormat();
mDecoderReader->OnDecodeThreadStart();
VideoInfo videoInfo;

View File

@ -67,6 +67,7 @@ MOCHITEST_FILES := \
test_gainNodeInLoop.html \
test_maxChannelCount.html \
test_mediaDecoding.html \
test_decodeMultichannel.html \
test_mediaElementAudioSourceNode.html \
test_mediaStreamAudioDestinationNode.html \
test_mediaStreamAudioSourceNode.html \
@ -107,6 +108,7 @@ MOCHITEST_FILES := \
audio-expected.wav \
audio-mono-expected.wav \
audio-mono-expected-2.wav \
audio-quad.wav \
$(NULL)
include $(topsrcdir)/config/rules.mk

Binary file not shown.

View File

@ -0,0 +1,58 @@
<!DOCTYPE HTML>
<html>
<meta charset=utf-8>
<head>
<title>Test that we can decode 4 channel wave file in webaudio, but not in &lt;audio&gt;</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var filename = "audio-quad.wav";
SimpleTest.waitForExplicitFinish();
function finishTest(a) {
if (a) {
a = null;
SimpleTest.finish();
}
}
function decodeUsingAudioElement() {
var a = new Audio();
a.addEventListener("error", function() {
ok(true, "We should not be able to decode this file using an HTMLAudioElement");
finishTest(a);
});
a.addEventListener("loadedmetadata", function() {
ok(false, "We should not be able to decode this file using an HTMLMediaElement.");
finishTest(a);
});
a.src = filename;
a.load();
}
addLoadEvent(function() {
var xhr = new XMLHttpRequest();
xhr.open("GET", filename);
xhr.responseType = "arraybuffer";
xhr.onload = function() {
var context = new AudioContext();
context.decodeAudioData(xhr.response, function(b) {
ok(true, "Decoding of a wave file with four channels succeded.");
is(b.numberOfChannels, 4, "The AudioBuffer should have 4 channels.");
decodeUsingAudioElement();
}, function() {
ok(false, "Decoding of a wave file with four channels failed.");
decodeUsingAudioElement();
});
};
xhr.send(null);
});
</script>
</pre>
</body>
</html>

View File

@ -48,6 +48,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(SpeechSynthesis)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SpeechSynthesis)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCurrentTask)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechQueue)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
tmp->mVoiceCache.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -55,6 +56,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(SpeechSynthesis)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentTask)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechQueue)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
tmp->mVoiceCache.EnumerateRead(TraverseCachedVoices, &cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

View File

@ -18,7 +18,10 @@
namespace mozilla {
namespace dom {
NS_INTERFACE_MAP_BEGIN(SpeechSynthesisUtterance)
NS_IMPL_CYCLE_COLLECTION_INHERITED_1(SpeechSynthesisUtterance,
nsDOMEventTargetHelper, mVoice);
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(SpeechSynthesisUtterance)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)

View File

@ -34,7 +34,8 @@ public:
virtual ~SpeechSynthesisUtterance();
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SpeechSynthesisUtterance,
nsDOMEventTargetHelper)
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
nsISupports* GetParentObject() const;

View File

@ -70,7 +70,7 @@ private:
// nsSpeechTask
NS_IMPL_CYCLE_COLLECTION_1(nsSpeechTask, mSpeechSynthesis);
NS_IMPL_CYCLE_COLLECTION_2(nsSpeechTask, mSpeechSynthesis, mUtterance);
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSpeechTask)
NS_INTERFACE_MAP_ENTRY(nsISpeechTask)

View File

@ -1302,15 +1302,34 @@ ParseMappedAttrAnimValueCallback(void* aObject,
void* aPropertyValue,
void* aData)
{
NS_ABORT_IF_FALSE(aPropertyName != SMIL_MAPPED_ATTR_STYLERULE_ATOM,
"animated content style rule should have been removed "
"from properties table already (we're rebuilding it now)");
MOZ_ASSERT(aPropertyName != SMIL_MAPPED_ATTR_STYLERULE_ATOM,
"animated content style rule should have been removed "
"from properties table already (we're rebuilding it now)");
MappedAttrParser* mappedAttrParser =
static_cast<MappedAttrParser*>(aData);
MappedAttrParser* mappedAttrParser = static_cast<MappedAttrParser*>(aData);
MOZ_ASSERT(mappedAttrParser, "parser should be non-null");
nsStringBuffer* valueBuf = static_cast<nsStringBuffer*>(aPropertyValue);
mappedAttrParser->ParseMappedAttrValue(aPropertyName, nsCheapString(valueBuf));
nsStringBuffer* animValBuf = static_cast<nsStringBuffer*>(aPropertyValue);
MOZ_ASSERT(animValBuf, "animated value should be non-null");
PRUnichar* animValBufData = static_cast<PRUnichar*>(animValBuf->Data());
uint32_t logicalStringLen = NS_strlen(animValBufData);
// SANITY CHECK: In case the string buffer wasn't correctly
// null-terminated, let's check the allocated size, too, and make sure we
// don't read further than that. (Note that StorageSize() is in units of
// bytes, so we have to convert that to units of PRUnichars, and subtract
// 1 for the null-terminator.)
uint32_t allocStringLen =
(animValBuf->StorageSize() / sizeof(PRUnichar)) - 1;
MOZ_ASSERT(logicalStringLen <= allocStringLen,
"The string in our string buffer wasn't null-terminated!!");
nsString animValStr;
animValBuf->ToString(std::min(logicalStringLen, allocStringLen),
animValStr);
mappedAttrParser->ParseMappedAttrValue(aPropertyName, animValStr);
}
// Callback for freeing animated content style rule, in property table.

View File

@ -2557,15 +2557,12 @@ nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput,
class NotifyOffThreadScriptCompletedRunnable : public nsRunnable
{
nsRefPtr<nsIOffThreadScriptReceiver> mReceiver;
// Note: there is no need to root the script, it is protected against GC
// until FinishOffThreadScript is called on it.
JSScript *mScript;
void *mToken;
public:
NotifyOffThreadScriptCompletedRunnable(already_AddRefed<nsIOffThreadScriptReceiver> aReceiver,
JSScript *aScript)
: mReceiver(aReceiver), mScript(aScript)
void *aToken)
: mReceiver(aReceiver), mToken(aToken)
{}
NS_DECL_NSIRUNNABLE
@ -2581,23 +2578,24 @@ NotifyOffThreadScriptCompletedRunnable::Run()
// could GC.
nsCOMPtr<nsIJSRuntimeService> svc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
NS_ENSURE_TRUE(svc, NS_ERROR_FAILURE);
JSRuntime *rt;
svc->GetRuntime(&rt);
NS_ENSURE_TRUE(svc, NS_ERROR_FAILURE);
JS::FinishOffThreadScript(rt, mScript);
JSScript *script = JS::FinishOffThreadScript(NULL, rt, mToken);
return mReceiver->OnScriptCompileComplete(mScript, mScript ? NS_OK : NS_ERROR_FAILURE);
return mReceiver->OnScriptCompileComplete(script, script ? NS_OK : NS_ERROR_FAILURE);
}
static void
OffThreadScriptReceiverCallback(JSScript *script, void *ptr)
OffThreadScriptReceiverCallback(void *aToken, void *aCallbackData)
{
// Be careful not to adjust the refcount on the receiver, as this callback
// may be invoked off the main thread.
nsIOffThreadScriptReceiver* aReceiver = static_cast<nsIOffThreadScriptReceiver*>(ptr);
nsIOffThreadScriptReceiver* aReceiver = static_cast<nsIOffThreadScriptReceiver*>(aCallbackData);
nsRefPtr<NotifyOffThreadScriptCompletedRunnable> notify =
new NotifyOffThreadScriptCompletedRunnable(
already_AddRefed<nsIOffThreadScriptReceiver>(aReceiver), script);
already_AddRefed<nsIOffThreadScriptReceiver>(aReceiver), aToken);
NS_DispatchToMainThread(notify);
}

View File

@ -16,9 +16,8 @@
function testInt64NonFinite(arg) {
// We can use a WebGLRenderingContext to test conversion to 64-bit signed
// ints edge cases.
try {
var gl = $("c").getContext("experimental-webgl");
} catch (ex) {
var gl = $("c").getContext("experimental-webgl");
if (!gl) {
// No WebGL support on MacOS 10.5. Just skip this test
todo(false, "WebGL not supported");
return;

View File

@ -20,9 +20,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=775852
/** Test for Bug 775852 **/
function doTest() {
try {
var gl = $("c").getContext("experimental-webgl");
} catch (e) {
var gl = $("c").getContext("experimental-webgl");
if (!gl) {
// No WebGL support on MacOS 10.5. Just skip this test
todo(false, "WebGL not supported");
return;

View File

@ -671,14 +671,56 @@ ContentChild::DeallocPBlobChild(PBlobChild* aActor)
BlobChild*
ContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aBlob, "Null pointer!");
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aBlob);
// If the blob represents a remote blob then we can simply pass its actor back
// here.
if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob)) {
BlobChild* actor =
static_cast<BlobChild*>(
static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
MOZ_ASSERT(actor);
return actor;
}
// XXX This is only safe so long as all blob implementations in our tree
// inherit nsDOMFileBase. If that ever changes then this will need to grow
// a real interface or something.
const nsDOMFileBase* blob = static_cast<nsDOMFileBase*>(aBlob);
// We often pass blobs that are multipart but that only contain one sub-blob
// (WebActivities does this a bunch). Unwrap to reduce the number of actors
// that we have to maintain.
const nsTArray<nsCOMPtr<nsIDOMBlob> >* subBlobs = blob->GetSubBlobs();
if (subBlobs && subBlobs->Length() == 1) {
const nsCOMPtr<nsIDOMBlob>& subBlob = subBlobs->ElementAt(0);
MOZ_ASSERT(subBlob);
// We can only take this shortcut if the multipart and the sub-blob are both
// Blob objects or both File objects.
nsCOMPtr<nsIDOMFile> multipartBlobAsFile = do_QueryInterface(aBlob);
nsCOMPtr<nsIDOMFile> subBlobAsFile = do_QueryInterface(subBlob);
if (!multipartBlobAsFile == !subBlobAsFile) {
// The wrapping was unnecessary, see if we can simply pass an existing
// remote blob.
if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(subBlob)) {
BlobChild* actor =
static_cast<BlobChild*>(
static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
MOZ_ASSERT(actor);
return actor;
}
// No need to add a reference here since the original blob must have a
// strong reference in the caller and it must also have a strong reference
// to this sub-blob.
aBlob = subBlob;
blob = static_cast<nsDOMFileBase*>(aBlob);
subBlobs = blob->GetSubBlobs();
}
}
// All blobs shared between processes must be immutable.
nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(aBlob);
if (!mutableBlob || NS_FAILED(mutableBlob->SetMutable(false))) {
@ -686,15 +728,6 @@ ContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
return nullptr;
}
nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob);
if (remoteBlob) {
BlobChild* actor =
static_cast<BlobChild*>(static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
NS_ASSERTION(actor, "Null actor?!");
return actor;
}
ParentBlobConstructorParams params;
if (blob->IsSizeUnknown() || blob->IsDateUnknown()) {
@ -743,16 +776,12 @@ ContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
blobParams.length() = length;
params.blobParams() = blobParams;
}
}
}
BlobChild* actor = BlobChild::Create(this, aBlob);
NS_ENSURE_TRUE(actor, nullptr);
if (!SendPBlobConstructor(actor, params)) {
return nullptr;
}
return actor;
return SendPBlobConstructor(actor, params) ? actor : nullptr;
}
PCrashReporterChild*

View File

@ -1881,14 +1881,62 @@ ContentParent::DeallocPBlobParent(PBlobParent* aActor)
BlobParent*
ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aBlob, "Null pointer!");
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aBlob);
// If the blob represents a remote blob for this ContentParent then we can
// simply pass its actor back here.
if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob)) {
BlobParent* actor =
static_cast<BlobParent*>(
static_cast<PBlobParent*>(remoteBlob->GetPBlob()));
MOZ_ASSERT(actor);
if (static_cast<ContentParent*>(actor->Manager()) == this) {
return actor;
}
}
// XXX This is only safe so long as all blob implementations in our tree
// inherit nsDOMFileBase. If that ever changes then this will need to grow
// a real interface or something.
const nsDOMFileBase* blob = static_cast<nsDOMFileBase*>(aBlob);
// We often pass blobs that are multipart but that only contain one sub-blob
// (WebActivities does this a bunch). Unwrap to reduce the number of actors
// that we have to maintain.
const nsTArray<nsCOMPtr<nsIDOMBlob> >* subBlobs = blob->GetSubBlobs();
if (subBlobs && subBlobs->Length() == 1) {
const nsCOMPtr<nsIDOMBlob>& subBlob = subBlobs->ElementAt(0);
MOZ_ASSERT(subBlob);
// We can only take this shortcut if the multipart and the sub-blob are both
// Blob objects or both File objects.
nsCOMPtr<nsIDOMFile> multipartBlobAsFile = do_QueryInterface(aBlob);
nsCOMPtr<nsIDOMFile> subBlobAsFile = do_QueryInterface(subBlob);
if (!multipartBlobAsFile == !subBlobAsFile) {
// The wrapping might have been unnecessary, see if we can simply pass an
// existing remote blob for this ContentParent.
if (nsCOMPtr<nsIRemoteBlob> remoteSubBlob = do_QueryInterface(subBlob)) {
BlobParent* actor =
static_cast<BlobParent*>(
static_cast<PBlobParent*>(remoteSubBlob->GetPBlob()));
MOZ_ASSERT(actor);
if (static_cast<ContentParent*>(actor->Manager()) == this) {
return actor;
}
}
// No need to add a reference here since the original blob must have a
// strong reference in the caller and it must also have a strong reference
// to this sub-blob.
aBlob = subBlob;
blob = static_cast<nsDOMFileBase*>(aBlob);
subBlobs = blob->GetSubBlobs();
}
}
// All blobs shared between processes must be immutable.
nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(aBlob);
if (!mutableBlob || NS_FAILED(mutableBlob->SetMutable(false))) {
@ -1896,18 +1944,6 @@ ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
return nullptr;
}
nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob);
if (remoteBlob) {
BlobParent* actor =
static_cast<BlobParent*>(
static_cast<PBlobParent*>(remoteBlob->GetPBlob()));
NS_ASSERTION(actor, "Null actor?!");
if (static_cast<ContentParent*>(actor->Manager()) == this) {
return actor;
}
}
ChildBlobConstructorParams params;
if (blob->IsSizeUnknown() || blob->IsDateUnknown()) {
@ -1946,16 +1982,12 @@ ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
blobParams.length() = length;
params = blobParams;
}
}
}
BlobParent* actor = BlobParent::Create(this, aBlob);
NS_ENSURE_TRUE(actor, nullptr);
if (!SendPBlobConstructor(actor, params)) {
return nullptr;
}
return actor;
return SendPBlobConstructor(actor, params) ? actor : nullptr;
}
void

View File

@ -74,6 +74,12 @@ Cu.import("resource://gre/modules/Services.jsm");
*
*/
function get_platform() {
var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"]
.getService(Components.interfaces.nsIXULRuntime);
return xulRuntime.OS;
}
/**
* Spin up a listening socket and associate at most one live, accepted socket
* with ourselves.
@ -492,8 +498,12 @@ add_test(clientCloses);
add_test(connectSock);
add_test(bufferedClose);
// - get an error on an attempt to connect to a non-listening port
add_test(badConnect);
if (get_platform() !== "Darwin") {
// This test intermittently fails way too often on OS X, for unknown reasons.
// Please, diagnose and fix it if you can.
// - get an error on an attempt to connect to a non-listening port
add_test(badConnect);
}
// send a buffer, get a drain, send a buffer, get a drain
add_test(connectSock);

View File

@ -16,9 +16,9 @@ interface DOMTokenList {
[Throws]
boolean contains(DOMString token);
[Throws]
void add(DOMString token);
void add(DOMString... tokens);
[Throws]
void remove(DOMString token);
void remove(DOMString... tokens);
[Throws]
boolean toggle(DOMString token, optional boolean force);
stringifier DOMString ();

View File

@ -129,10 +129,123 @@ GfxTexturesReporter::UpdateAmount(MemoryUse action, GLenum format,
}
}
/*
* XXX - we should really know the ARB/EXT variants of these
* instead of only handling the symbol if it's exposed directly.
*/
static bool
ParseGLVersion(GLContext* gl, unsigned int* version)
{
GLenum error = gl->fGetError();
if (error != LOCAL_GL_NO_ERROR) {
MOZ_ASSERT(false, "An OpenGL error has been triggered before.");
return false;
}
/**
* B2G emulator bug work around: The emulator implements OpenGL ES 2.0 on
* OpenGL 3.2. The bug is that GetIntegerv(LOCAL_GL_{MAJOR,MINOR}_VERSION)
* returns OpenGL 3.2 instead of generating an error.
*/
if (!gl->IsGLES())
{
/**
* OpenGL 3.1 and OpenGL ES 3.0 both introduce GL_{MAJOR,MINOR}_VERSION
* with GetIntegerv. So we first try those constants even though we
* might not have an OpenGL context supporting them, has this is a
* better way than parsing GL_VERSION.
*/
GLint majorVersion = 0;
GLint minorVersion = 0;
gl->fGetIntegerv(LOCAL_GL_MAJOR_VERSION, &majorVersion);
gl->fGetIntegerv(LOCAL_GL_MINOR_VERSION, &minorVersion);
// If it's not an OpenGL (ES) 3.0 context, we will have an error
error = gl->fGetError();
if (error == LOCAL_GL_NO_ERROR &&
majorVersion > 0 &&
minorVersion >= 0)
{
*version = majorVersion * 100 + minorVersion * 10;
return true;
}
}
/**
* We were not able to use GL_{MAJOR,MINOR}_VERSION, so we parse
* GL_VERSION.
*
*
* OpenGL 2.x, 3.x, 4.x specifications:
* The VERSION and SHADING_LANGUAGE_VERSION strings are laid out as follows:
*
* <version number><space><vendor-specific information>
*
* The version number is either of the form major_number.minor_number or
* major_number.minor_number.release_number, where the numbers all have
* one or more digits.
*
*
* OpenGL ES 2.0, 3.0 specifications:
* The VERSION string is laid out as follows:
*
* "OpenGL ES N.M vendor-specific information"
*
* The version number is either of the form major_number.minor_number or
* major_number.minor_number.release_number, where the numbers all have
* one or more digits.
*
*
* Note:
* We don't care about release_number.
*/
const char* versionString = (const char*)gl->fGetString(LOCAL_GL_VERSION);
error = gl->fGetError();
if (error != LOCAL_GL_NO_ERROR) {
MOZ_ASSERT(false, "glGetString(GL_VERSION) has generated an error");
return false;
} else if (!versionString) {
MOZ_ASSERT(false, "glGetString(GL_VERSION) has returned 0");
return false;
}
const char kGLESVersionPrefix[] = "OpenGL ES ";
if (strncmp(versionString, kGLESVersionPrefix, strlen(kGLESVersionPrefix)) == 0) {
versionString += strlen(kGLESVersionPrefix);
}
const char* itr = versionString;
char* end = nullptr;
int majorVersion = (int)strtol(itr, &end, 10);
if (!end) {
MOZ_ASSERT(false, "Failed to parse the GL major version number.");
return false;
} else if (*end != '.') {
MOZ_ASSERT(false, "Failed to parse GL's major-minor version number separator.");
return false;
}
// we skip the '.' between the major and the minor version
itr = end + 1;
end = nullptr;
int minorVersion = (int)strtol(itr, &end, 10);
if (!end) {
MOZ_ASSERT(false, "Failed to parse GL's minor version number.");
return false;
}
if (majorVersion <= 0 || majorVersion >= 100) {
MOZ_ASSERT(false, "Invalid major version.");
return false;
} else if (minorVersion < 0 || minorVersion >= 10) {
MOZ_ASSERT(false, "Invalid minor version.");
return false;
}
*version = (unsigned int)(majorVersion * 100 + minorVersion * 10);
return true;
}
bool
GLContext::InitWithPrefix(const char *prefix, bool trygl)
@ -293,6 +406,19 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
mInitialized = LoadSymbols(&symbols[0], trygl, prefix);
if (mInitialized) {
unsigned int version = 0;
bool parseSuccess = ParseGLVersion(this, &version);
printf_stderr("OpenGL version detected: %u\n", version);
if (version >= mVersion) {
mVersion = version;
} else if (parseSuccess) {
MOZ_ASSERT(false, "Parsed version less than expected.");
}
}
// Load OpenGL ES 2.0 symbols, or desktop if we aren't using ES 2.
if (mInitialized) {
if (IsGLES2()) {

View File

@ -258,7 +258,7 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco
pc.construct(&parser, (GenericParseContext *) NULL, (ParseNode *) NULL, &globalsc,
(Directives *) NULL, staticLevel, /* bodyid = */ 0);
if (!pc.ref().init())
if (!pc.ref().init(parser.tokenStream))
return NULL;
/* If this is a direct call to eval, inherit the caller's strictness. */
@ -325,7 +325,7 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco
pc.destroy();
pc.construct(&parser, (GenericParseContext *) NULL, (ParseNode *) NULL,
&globalsc, (Directives *) NULL, staticLevel, /* bodyid = */ 0);
if (!pc.ref().init())
if (!pc.ref().init(parser.tokenStream))
return NULL;
JS_ASSERT(parser.pc == pc.addr());
pn = parser.statement();

View File

@ -16,9 +16,9 @@ namespace frontend {
template <typename ParseHandler>
bool
ParseContext<ParseHandler>::init()
ParseContext<ParseHandler>::init(TokenStream &ts)
{
if (!frontend::GenerateBlockId(this, this->bodyid))
if (!frontend::GenerateBlockId(ts, this, this->bodyid))
return false;
return decls_.init() && lexdeps.ensureMap(sc->context);

View File

@ -70,13 +70,10 @@ typedef Handle<StaticBlockObject*> HandleStaticBlockObject;
template <typename ParseHandler>
bool
GenerateBlockId(ParseContext<ParseHandler> *pc, uint32_t &blockid)
GenerateBlockId(TokenStream &ts, ParseContext<ParseHandler> *pc, uint32_t &blockid)
{
if (pc->blockidGen == JS_BIT(20)) {
if (!pc->sc->context->isJSContext())
return false;
JS_ReportErrorNumber(pc->sc->context->asJSContext(),
js_GetErrorMessage, NULL, JSMSG_NEED_DIET, "program");
ts.reportError(JSMSG_NEED_DIET, "program");
return false;
}
JS_ASSERT(pc->blockidGen < JS_BIT(20));
@ -85,10 +82,10 @@ GenerateBlockId(ParseContext<ParseHandler> *pc, uint32_t &blockid)
}
template bool
GenerateBlockId(ParseContext<SyntaxParseHandler> *pc, uint32_t &blockid);
GenerateBlockId(TokenStream &ts, ParseContext<SyntaxParseHandler> *pc, uint32_t &blockid);
template bool
GenerateBlockId(ParseContext<FullParseHandler> *pc, uint32_t &blockid);
GenerateBlockId(TokenStream &ts, ParseContext<FullParseHandler> *pc, uint32_t &blockid);
template <typename ParseHandler>
static void
@ -625,7 +622,7 @@ Parser<ParseHandler>::parse(JSObject *chain)
ParseContext<ParseHandler> globalpc(this, /* parent = */ NULL, ParseHandler::null(),
&globalsc, /* newDirectives = */ NULL,
/* staticLevel = */ 0, /* bodyid = */ 0);
if (!globalpc.init())
if (!globalpc.init(tokenStream))
return null();
Node pn = statements();
@ -887,7 +884,7 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun, const AutoN
ParseContext<FullParseHandler> funpc(this, pc, fn, funbox, newDirectives,
/* staticLevel = */ 0, /* bodyid = */ 0);
if (!funpc.init())
if (!funpc.init(tokenStream))
return null();
for (unsigned i = 0; i < formals.length(); i++) {
@ -2143,7 +2140,7 @@ Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
ParseContext<SyntaxParseHandler> funpc(parser, outerpc, SyntaxParseHandler::null(), funbox,
newDirectives, outerpc->staticLevel + 1,
outerpc->blockidGen);
if (!funpc.init())
if (!funpc.init(tokenStream))
return false;
if (!parser->functionArgsAndBodyGeneric(SyntaxParseHandler::NodeGeneric,
@ -2175,7 +2172,7 @@ Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
// Continue doing a full parse for this inner function.
ParseContext<FullParseHandler> funpc(this, pc, pn, funbox, newDirectives,
outerpc->staticLevel + 1, outerpc->blockidGen);
if (!funpc.init())
if (!funpc.init(tokenStream))
return false;
if (!functionArgsAndBodyGeneric(pn, fun, type, kind, newDirectives))
@ -2214,7 +2211,7 @@ Parser<SyntaxParseHandler>::functionArgsAndBody(Node pn, HandleFunction fun,
// Initialize early for possible flags mutation via destructuringExpr.
ParseContext<SyntaxParseHandler> funpc(this, pc, handler.null(), funbox, newDirectives,
outerpc->staticLevel + 1, outerpc->blockidGen);
if (!funpc.init())
if (!funpc.init(tokenStream))
return false;
if (!functionArgsAndBodyGeneric(pn, fun, type, kind, newDirectives))
@ -2249,7 +2246,7 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, unsigned st
Directives newDirectives = directives;
ParseContext<FullParseHandler> funpc(this, /* parent = */ NULL, pn, funbox,
&newDirectives, staticLevel, /* bodyid = */ 0);
if (!funpc.init())
if (!funpc.init(tokenStream))
return null();
if (!functionArgsAndBodyGeneric(pn, fun, Normal, Statement, &newDirectives)) {
@ -2378,7 +2375,7 @@ Parser<FullParseHandler>::moduleDecl()
ParseContext<FullParseHandler> modulepc(this, pc, /* function = */ NULL, modulebox,
/* newDirectives = */ NULL, pc->staticLevel + 1,
pc->blockidGen);
if (!modulepc.init())
if (!modulepc.init(tokenStream))
return NULL;
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_MODULE);
pn->pn_body = statements();
@ -3263,7 +3260,7 @@ Parser<ParseHandler>::pushLexicalScope(HandleStaticBlockObject blockObj, StmtInf
if (!pn)
return null();
if (!GenerateBlockId(pc, stmt->blockid))
if (!GenerateBlockId(tokenStream, pc, stmt->blockid))
return null();
handler.setBlockId(pn, stmt->blockid);
return pn;
@ -3414,10 +3411,11 @@ Parser<ParseHandler>::letBlock(LetContext letContext)
template <typename ParseHandler>
static bool
PushBlocklikeStatement(StmtInfoPC *stmt, StmtType type, ParseContext<ParseHandler> *pc)
PushBlocklikeStatement(TokenStream &ts, StmtInfoPC *stmt, StmtType type,
ParseContext<ParseHandler> *pc)
{
PushStatementPC(pc, stmt, type);
return GenerateBlockId(pc, stmt->blockid);
return GenerateBlockId(ts, pc, stmt->blockid);
}
template <typename ParseHandler>
@ -3427,7 +3425,7 @@ Parser<ParseHandler>::blockStatement()
JS_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
StmtInfoPC stmtInfo(context);
if (!PushBlocklikeStatement(&stmtInfo, STMT_BLOCK, pc))
if (!PushBlocklikeStatement(tokenStream, &stmtInfo, STMT_BLOCK, pc))
return null();
Node list = statements();
@ -4343,7 +4341,7 @@ Parser<ParseHandler>::switchStatement()
StmtInfoPC stmtInfo(context);
PushStatementPC(pc, &stmtInfo, STMT_SWITCH);
if (!GenerateBlockId(pc, pc->topStmt->blockid))
if (!GenerateBlockId(tokenStream, pc, pc->topStmt->blockid))
return null();
Node caseList = handler.newStatementList(pc->blockid(), pos());
@ -4802,7 +4800,7 @@ Parser<ParseHandler>::tryStatement()
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
StmtInfoPC stmtInfo(context);
if (!PushBlocklikeStatement(&stmtInfo, STMT_TRY, pc))
if (!PushBlocklikeStatement(tokenStream, &stmtInfo, STMT_TRY, pc))
return null();
Node innerBlock = statements();
if (!innerBlock)
@ -4925,7 +4923,7 @@ Parser<ParseHandler>::tryStatement()
if (tt == TOK_FINALLY) {
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY);
if (!PushBlocklikeStatement(&stmtInfo, STMT_FINALLY, pc))
if (!PushBlocklikeStatement(tokenStream, &stmtInfo, STMT_FINALLY, pc))
return null();
finallyBlock = statements();
if (!finallyBlock)
@ -6126,7 +6124,7 @@ Parser<FullParseHandler>::generatorExpr(ParseNode *kid)
ParseContext<FullParseHandler> genpc(this, outerpc, genfn, genFunbox,
/* newDirectives = */ NULL, outerpc->staticLevel + 1,
outerpc->blockidGen);
if (!genpc.init())
if (!genpc.init(tokenStream))
return null();
/*

View File

@ -76,7 +76,7 @@ struct GenericParseContext
template <typename ParseHandler>
bool
GenerateBlockId(ParseContext<ParseHandler> *pc, uint32_t &blockid);
GenerateBlockId(TokenStream &ts, ParseContext<ParseHandler> *pc, uint32_t &blockid);
/*
* The struct ParseContext stores information about the current parsing context,
@ -269,7 +269,7 @@ struct ParseContext : public GenericParseContext
~ParseContext();
bool init();
bool init(TokenStream &ts);
unsigned blockid() { return topStmt ? topStmt->blockid : bodyid; }

View File

@ -20,6 +20,7 @@
#include "jscntxt.h"
#include "jsexn.h"
#include "jsnum.h"
#include "jsworkers.h"
#include "frontend/BytecodeCompiler.h"
#include "js/CharacterEncoding.h"
@ -30,6 +31,7 @@ using namespace js;
using namespace js::frontend;
using namespace js::unicode;
using mozilla::Maybe;
using mozilla::PodAssign;
using mozilla::PodCopy;
using mozilla::PodZero;
@ -564,7 +566,7 @@ TokenStream::reportStrictModeErrorNumberVA(uint32_t offset, bool strictMode, uns
}
void
CompileError::throwError()
CompileError::throwError(JSContext *cx)
{
// If there's a runtime exception type associated with this error
// number, set that as the pending exception. For errors occuring at
@ -622,12 +624,10 @@ TokenStream::reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigne
warning = false;
}
if (!this->cx->isJSContext())
return warning;
JSContext *cx = this->cx->asJSContext();
CompileError err(cx);
// On the main thread, report the error immediately. When compiling off
// thread, save the error so that the main thread can report it later.
CompileError tempErr;
CompileError &err = cx->isJSContext() ? tempErr : cx->addPendingCompileError();
err.report.flags = flags;
err.report.errorNumber = errorNumber;
@ -697,7 +697,8 @@ TokenStream::reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigne
err.report.uctokenptr = err.report.uclinebuf + windowOffset;
}
err.throwError();
if (cx->isJSContext())
err.throwError(cx->asJSContext());
return warning;
}

View File

@ -307,17 +307,16 @@ struct Token {
};
struct CompileError {
JSContext *cx;
JSErrorReport report;
char *message;
ErrorArgumentsType argumentsType;
CompileError(JSContext *cx)
: cx(cx), message(NULL), argumentsType(ArgumentsAreUnicode)
CompileError()
: message(NULL), argumentsType(ArgumentsAreUnicode)
{
mozilla::PodZero(&report);
}
~CompileError();
void throwError();
void throwError(JSContext *cx);
};
// Ideally, tokenizing would be entirely independent of context. But the

View File

@ -0,0 +1,26 @@
var TZ_PST = -8;
var TZ_DIFF = GetTimezoneOffset();
var PST_DIFF = TZ_DIFF - TZ_PST;
function GetTimezoneOffset() {}
function adjustResultArray(ResultArray) {
var t = ResultArray[TIME] - PST_DIFF;
ResultArray[UTC_YEAR] = YearFromTime(t);
}
function TimeInYear( y ) {}
function YearFromTime( t ) {
var sign = ( t < 0 ) ? -1 : 1;
var year = ( sign < 0 ) ? 1969 : 1970;
for ( var timeToTimeZero = t; ; ) {
timeToTimeZero -= sign * TimeInYear(year)
break;
}
return ( year );
}
gczeal(4);
evaluate("\
var TIME = 0;\
var UTC_YEAR = 1;\
adjustResultArray([]);\
adjustResultArray([946684800000-1]);\
adjustResultArray([]);\
", { noScriptRval : true });

View File

@ -4611,7 +4611,7 @@ ParseFunction(ModuleCompiler &m, ParseNode **fnOut)
Directives newDirectives = directives;
AsmJSParseContext funpc(&m.parser(), outerpc, fn, funbox, &newDirectives,
outerpc->staticLevel + 1, outerpc->blockidGen);
if (!funpc.init())
if (!funpc.init(m.parser().tokenStream))
return false;
if (!m.parser().functionArgsAndBodyGeneric(fn, fun, Normal, Statement, &newDirectives))

View File

@ -2860,10 +2860,10 @@ MacroAssemblerARMCompat::loadValue(Address src, ValueOperand val)
void
MacroAssemblerARMCompat::tagValue(JSValueType type, Register payload, ValueOperand dest)
{
JS_ASSERT(payload != dest.typeReg());
ma_mov(ImmType(type), dest.typeReg());
JS_ASSERT(dest.typeReg() != dest.payloadReg());
if (payload != dest.payloadReg())
ma_mov(payload, dest.payloadReg());
ma_mov(ImmType(type), dest.typeReg());
}
void

View File

@ -486,7 +486,7 @@ StoreAllLiveRegs(MacroAssembler &masm, RegisterSet liveRegs)
masm.loadJitActivation(scratch);
Address checkRegs(scratch, JitActivation::offsetOfCheckRegs());
masm.store32(Imm32(1), checkRegs);
masm.add32(Imm32(1), checkRegs);
StoreOp op(masm);
HandleRegisterDump<StoreOp>(op, masm, liveRegs, scratch, allRegs.getAny());
@ -539,6 +539,13 @@ CodeGeneratorShared::verifyOsiPointRegs(LSafepoint *safepoint)
Address checkRegs(scratch, JitActivation::offsetOfCheckRegs());
masm.branch32(Assembler::Equal, checkRegs, Imm32(0), &done);
// Having more than one VM function call made in one visit function at
// runtime is a sec-ciritcal error, because if we conservatively assume that
// one of the function call can re-enter Ion, then the invalidation process
// will potentially add a call at a random location, by patching the code
// before the return address.
masm.branch32(Assembler::NotEqual, checkRegs, Imm32(1), &failure);
// Ignore temp registers. Some instructions (like LValueToInt32) modify
// temps after calling into the VM. This is fine because no other
// instructions (including this OsiPoint) will depend on them.

View File

@ -175,10 +175,10 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
loadValue(Operand(src), val);
}
void tagValue(JSValueType type, Register payload, ValueOperand dest) {
JS_ASSERT(payload != dest.typeReg());
movl(ImmType(type), dest.typeReg());
JS_ASSERT(dest.typeReg() != dest.payloadReg());
if (payload != dest.payloadReg())
movl(payload, dest.payloadReg());
movl(ImmType(type), dest.typeReg());
}
void pushValue(ValueOperand val) {
push(val.typeReg());

View File

@ -1749,11 +1749,7 @@ JS_PUBLIC_API(char *)
JS_strdup(JSContext *cx, const char *s)
{
AssertHeapIsIdle(cx);
size_t n = strlen(s) + 1;
void *p = cx->malloc_(n);
if (!p)
return NULL;
return (char *)js_memcpy(p, s, n);
return js_strdup(cx, s);
}
JS_PUBLIC_API(char *)
@ -4892,18 +4888,18 @@ JS::CompileOffThread(JSContext *cx, Handle<JSObject*> obj, CompileOptions option
JS_ASSERT(CanCompileOffThread(cx, options));
return StartOffThreadParseScript(cx, options, chars, length, obj, callback, callbackData);
#else
MOZ_ASSUME_UNREACHABLE("Off thread compilation is only available with JS_ION");
MOZ_ASSUME_UNREACHABLE("Off thread compilation is not available.");
#endif
}
JS_PUBLIC_API(void)
JS::FinishOffThreadScript(JSRuntime *rt, JSScript *script)
JS_PUBLIC_API(JSScript *)
JS::FinishOffThreadScript(JSContext *maybecx, JSRuntime *rt, void *token)
{
#ifdef JS_WORKER_THREADS
JS_ASSERT(CurrentThreadCanAccessRuntime(rt));
rt->workerThreadState->finishParseTaskForScript(rt, script);
return rt->workerThreadState->finishParseTask(maybecx, rt, token);
#else
MOZ_ASSUME_UNREACHABLE("Off thread compilation is only available with JS_ION");
MOZ_ASSUME_UNREACHABLE("Off thread compilation is not available.");
#endif
}

View File

@ -3569,12 +3569,12 @@ CanCompileOffThread(JSContext *cx, const CompileOptions &options);
* Off thread compilation control flow.
*
* After successfully triggering an off thread compile of a script, the
* callback will eventually be invoked with the specified data and the result
* script or NULL. The callback will be invoked while off the main thread, so
* must ensure that its operations are thread safe. Afterwards,
* FinishOffThreadScript must be invoked on the main thread to make the script
* usable (correct compartment/zone); this method must be invoked even if the
* off thread compilation produced a NULL script.
* callback will eventually be invoked with the specified data and a token
* for the compilation. The callback will be invoked while off the main thread,
* so must ensure that its operations are thread safe. Afterwards,
* FinishOffThreadScript must be invoked on the main thread to get the result
* script or NULL. If maybecx is specified, this method will also report any
* error or warnings generated during the parse.
*
* The characters passed in to CompileOffThread must remain live until the
* callback is invoked, and the resulting script will be rooted until the call
@ -3586,8 +3586,8 @@ CompileOffThread(JSContext *cx, Handle<JSObject*> obj, CompileOptions options,
const jschar *chars, size_t length,
OffThreadCompileCallback callback, void *callbackData);
extern JS_PUBLIC_API(void)
FinishOffThreadScript(JSRuntime *rt, JSScript *script);
extern JS_PUBLIC_API(JSScript *)
FinishOffThreadScript(JSContext *maybecx, JSRuntime *rt, void *token);
extern JS_PUBLIC_API(JSFunction *)
CompileFunction(JSContext *cx, JS::Handle<JSObject*> obj, CompileOptions options,

View File

@ -623,6 +623,16 @@ js::PrintError(JSContext *cx, FILE *file, const char *message, JSErrorReport *re
return true;
}
char *
js_strdup(ExclusiveContext *cx, const char *s)
{
size_t n = strlen(s) + 1;
void *p = cx->malloc_(n);
if (!p)
return NULL;
return (char *)js_memcpy(p, s, n);
}
/*
* The arguments from ap need to be packaged up into an array and stored
* into the report struct.
@ -635,7 +645,7 @@ js::PrintError(JSContext *cx, FILE *file, const char *message, JSErrorReport *re
* Returns true if the expansion succeeds (can fail if out of memory).
*/
bool
js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
js_ExpandErrorArguments(ExclusiveContext *cx, JSErrorCallback callback,
void *userRef, const unsigned errorNumber,
char **messagep, JSErrorReport *reportp,
ErrorArgumentsType argumentsType, va_list ap)
@ -752,7 +762,7 @@ js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
*/
if (efs->format) {
size_t len;
*messagep = JS_strdup(cx, efs->format);
*messagep = js_strdup(cx, efs->format);
if (!*messagep)
goto error;
len = strlen(*messagep);

View File

@ -106,6 +106,8 @@ class RegExpCompartment;
class RegExpStatics;
class ForkJoinSlice;
namespace frontend { struct CompileError; }
/*
* Execution Context Overview:
*
@ -375,7 +377,7 @@ class ExclusiveContext : public ThreadSafeContext
return runtime_->scriptDataTable();
}
#if defined(JS_ION) && defined(JS_THREADSAFE)
#ifdef JS_WORKER_THREADS
// Since JSRuntime::workerThreadState is necessarily initialized from the
// main thread before the first worker thread can access it, there is no
// possibility for a race read/writing it.
@ -383,6 +385,9 @@ class ExclusiveContext : public ThreadSafeContext
return runtime_->workerThreadState;
}
#endif
// Methods specific to any WorkerThread for the context.
frontend::CompileError &addPendingCompileError();
};
inline void
@ -743,7 +748,7 @@ js_ReportErrorNumberUCArray(JSContext *cx, unsigned flags, JSErrorCallback callb
#endif
extern bool
js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
js_ExpandErrorArguments(js::ExclusiveContext *cx, JSErrorCallback callback,
void *userRef, const unsigned errorNumber,
char **message, JSErrorReport *reportp,
js::ErrorArgumentsType argumentsType, va_list ap);
@ -809,6 +814,9 @@ js_ReportValueErrorFlags(JSContext *cx, unsigned flags, const unsigned errorNumb
extern const JSErrorFormatString js_ErrorFormatString[JSErr_Limit];
char *
js_strdup(js::ExclusiveContext *cx, const char *s);
#ifdef JS_THREADSAFE
# define JS_ASSERT_REQUEST_DEPTH(cx) JS_ASSERT((cx)->runtime()->requestDepth >= 1)
#else
@ -964,11 +972,11 @@ class AutoAssertNoException
*/
class ContextAllocPolicy
{
JSContext *const cx_;
ThreadSafeContext *const cx_;
public:
ContextAllocPolicy(JSContext *cx) : cx_(cx) {}
JSContext *context() const { return cx_; }
ContextAllocPolicy(ThreadSafeContext *cx) : cx_(cx) {}
ThreadSafeContext *context() const { return cx_; }
void *malloc_(size_t bytes) { return cx_->malloc_(bytes); }
void *calloc_(size_t bytes) { return cx_->calloc_(bytes); }
void *realloc_(void *p, size_t oldBytes, size_t bytes) { return cx_->realloc_(p, oldBytes, bytes); }

View File

@ -857,15 +857,22 @@ js_InitExceptionClasses(JSContext *cx, HandleObject obj)
}
const JSErrorFormatString*
js_GetLocalizedErrorMessage(JSContext* cx, void *userRef, const char *locale,
js_GetLocalizedErrorMessage(ExclusiveContext *cx, void *userRef, const char *locale,
const unsigned errorNumber)
{
const JSErrorFormatString *errorString = NULL;
if (cx->runtime()->localeCallbacks && cx->runtime()->localeCallbacks->localeGetErrorMessage) {
errorString = cx->runtime()->localeCallbacks
->localeGetErrorMessage(userRef, locale, errorNumber);
// The locale callbacks might not be thread safe, so don't call them if
// we're not on the main thread. When used with XPConnect,
// |localeGetErrorMessage| will be NULL anyways.
if (cx->isJSContext() &&
cx->asJSContext()->runtime()->localeCallbacks &&
cx->asJSContext()->runtime()->localeCallbacks->localeGetErrorMessage)
{
JSLocaleCallbacks *callbacks = cx->asJSContext()->runtime()->localeCallbacks;
errorString = callbacks->localeGetErrorMessage(userRef, locale, errorNumber);
}
if (!errorString)
errorString = js_GetErrorMessage(userRef, locale, errorNumber);
return errorString;

View File

@ -54,7 +54,7 @@ extern JSErrorReport *
js_ErrorFromException(jsval exn);
extern const JSErrorFormatString *
js_GetLocalizedErrorMessage(JSContext* cx, void *userRef, const char *locale,
js_GetLocalizedErrorMessage(js::ExclusiveContext *cx, void *userRef, const char *locale,
const unsigned errorNumber);
/*

View File

@ -192,7 +192,7 @@ typedef void
namespace JS {
typedef void (*OffThreadCompileCallback)(JSScript *script, void *callbackData);
typedef void (*OffThreadCompileCallback)(void *token, void *callbackData);
namespace shadow {

View File

@ -173,14 +173,14 @@ static JSClass workerGlobalClass = {
JS_ConvertStub, NULL
};
ParseTask::ParseTask(Zone *zone, ExclusiveContext *cx, const CompileOptions &options,
ParseTask::ParseTask(ExclusiveContext *cx, const CompileOptions &options,
const jschar *chars, size_t length, JSObject *scopeChain,
JS::OffThreadCompileCallback callback, void *callbackData)
: zone(zone), cx(cx), options(options), chars(chars), length(length),
: cx(cx), options(options), chars(chars), length(length),
alloc(JSRuntime::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), scopeChain(scopeChain),
callback(callback), callbackData(callbackData), script(NULL)
callback(callback), callbackData(callbackData), script(NULL), errors(cx)
{
JSRuntime *rt = zone->runtimeFromMainThread();
JSRuntime *rt = scopeChain->runtimeFromMainThread();
if (options.principals())
JS_HoldPrincipals(options.principals());
@ -192,7 +192,7 @@ ParseTask::ParseTask(Zone *zone, ExclusiveContext *cx, const CompileOptions &opt
ParseTask::~ParseTask()
{
JSRuntime *rt = zone->runtimeFromMainThread();
JSRuntime *rt = scopeChain->runtimeFromMainThread();
if (options.principals())
JS_DropPrincipals(rt, options.principals());
@ -263,7 +263,7 @@ js::StartOffThreadParseScript(JSContext *cx, const CompileOptions &options,
workercx->enterCompartment(global->compartment());
ScopedJSDeletePtr<ParseTask> task(
cx->new_<ParseTask>(global->zone(), workercx.get(), options, chars, length,
cx->new_<ParseTask>(workercx.get(), options, chars, length,
scopeChain, callback, callbackData));
if (!task)
return false;
@ -372,10 +372,8 @@ WorkerThreadState::cleanup(JSRuntime *rt)
}
// Clean up any parse tasks which haven't been finished yet.
while (!parseFinishedList.empty()) {
JSScript *script = parseFinishedList[0]->script;
finishParseTaskForScript(rt, script);
}
while (!parseFinishedList.empty())
finishParseTask(/* maybecx = */ NULL, rt, parseFinishedList[0]);
}
WorkerThreadState::~WorkerThreadState()
@ -498,15 +496,16 @@ WorkerThreadState::canStartCompressionTask()
return !compressionWorklist.empty();
}
void
WorkerThreadState::finishParseTaskForScript(JSRuntime *rt, JSScript *script)
JSScript *
WorkerThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void *token)
{
ParseTask *parseTask = NULL;
// The token is a ParseTask* which should be in the finished list.
{
AutoLockWorkerThreadState lock(*rt->workerThreadState);
for (size_t i = 0; i < parseFinishedList.length(); i++) {
if (parseFinishedList[i]->script == script) {
if (parseFinishedList[i] == token) {
parseTask = parseFinishedList[i];
parseFinishedList[i] = parseFinishedList.back();
parseFinishedList.popBack();
@ -518,23 +517,16 @@ WorkerThreadState::finishParseTaskForScript(JSRuntime *rt, JSScript *script)
// Mark the zone as no longer in use by an ExclusiveContext, and available
// to be collected by the GC.
rt->clearUsedByExclusiveThread(parseTask->zone);
if (!script) {
// Parsing failed and there is nothing to finish, but there still may
// be lingering ParseTask instances holding roots which need to be
// cleaned up. The ParseTask which we picked might not be the right
// one but this is ok as finish calls will be 1:1 with calls that
// create a ParseTask.
js_delete(parseTask);
return;
}
rt->clearUsedByExclusiveThread(parseTask->cx->zone());
// Point the prototypes of any objects in the script's compartment to refer
// to the corresponding prototype in the new compartment. This will briefly
// create cross compartment pointers, which will be fixed by the
// MergeCompartments call below.
for (gc::CellIter iter(parseTask->zone, gc::FINALIZE_TYPE_OBJECT); !iter.done(); iter.next()) {
for (gc::CellIter iter(parseTask->cx->zone(), gc::FINALIZE_TYPE_OBJECT);
!iter.done();
iter.next())
{
types::TypeObject *object = iter.get<types::TypeObject>();
JSObject *proto = object->proto;
if (!proto)
@ -551,9 +543,19 @@ WorkerThreadState::finishParseTaskForScript(JSRuntime *rt, JSScript *script)
}
// Move the parsed script and all its contents into the desired compartment.
gc::MergeCompartments(parseTask->script->compartment(), parseTask->scopeChain->compartment());
gc::MergeCompartments(parseTask->cx->compartment(), parseTask->scopeChain->compartment());
// If we have a context, report any error or warnings generated during the
// parse.
if (maybecx) {
AutoCompartment ac(maybecx, parseTask->scopeChain);
for (size_t i = 0; i < parseTask->errors.length(); i++)
parseTask->errors[i].throwError(maybecx);
}
JSScript *script = parseTask->script;
js_delete(parseTask);
return script;
}
void
@ -672,6 +674,14 @@ ExclusiveContext::setWorkerThread(WorkerThread *workerThread)
this->perThreadData = workerThread->threadData.addr();
}
frontend::CompileError &
ExclusiveContext::addPendingCompileError()
{
if (!workerThread->parseTask->errors.append(frontend::CompileError()))
MOZ_CRASH();
return workerThread->parseTask->errors.back();
}
void
WorkerThread::handleParseWorkload(WorkerThreadState &state)
{
@ -691,7 +701,7 @@ WorkerThread::handleParseWorkload(WorkerThreadState &state)
}
// The callback is invoked while we are still off the main thread.
parseTask->callback(parseTask->script, parseTask->callbackData);
parseTask->callback(parseTask, parseTask->callbackData);
// FinishOffThreadScript will need to be called on the script to
// migrate it into the correct compartment.
@ -1000,4 +1010,10 @@ AutoPauseWorkersForGC::~AutoPauseWorkersForGC()
{
}
frontend::CompileError &
ExclusiveContext::addPendingCompileError()
{
MOZ_ASSUME_UNREACHABLE("Off thread compilation not available.");
}
#endif /* JS_WORKER_THREADS */

View File

@ -19,6 +19,7 @@
#include "jscntxt.h"
#include "jslock.h"
#include "frontend/TokenStream.h"
#include "jit/Ion.h"
namespace js {
@ -119,7 +120,7 @@ class WorkerThreadState
return asmJSFailedFunction;
}
void finishParseTaskForScript(JSRuntime *rt, JSScript *script);
JSScript *finishParseTask(JSContext *maybecx, JSRuntime *rt, void *token);
bool compressionInProgress(SourceCompressionTask *task);
SourceCompressionTask *compressionTaskForSource(ScriptSource *ss);
@ -366,7 +367,6 @@ struct AsmJSParallelTask
struct ParseTask
{
Zone *zone;
ExclusiveContext *cx;
CompileOptions options;
const jschar *chars;
@ -387,7 +387,11 @@ struct ParseTask
// ParseTask.
JSScript *script;
ParseTask(Zone *zone, ExclusiveContext *cx, const CompileOptions &options,
// Any errors or warnings produced during compilation. These are reported
// when finishing the script.
Vector<frontend::CompileError> errors;
ParseTask(ExclusiveContext *cx, const CompileOptions &options,
const jschar *chars, size_t length, JSObject *scopeChain,
JS::OffThreadCompileCallback callback, void *callbackData);

View File

@ -3237,7 +3237,7 @@ SyntaxParse(JSContext *cx, unsigned argc, jsval *vp)
#ifdef JS_THREADSAFE
static void
OffThreadCompileScriptCallback(JSScript *script, void *callbackData)
OffThreadCompileScriptCallback(void *token, void *callbackData)
{
// This callback is invoked off the main thread and there isn't a good way
// to pass the script on to the main thread. Just let the script leak.

View File

@ -26,7 +26,7 @@ StringBuffer::extractWellSized()
JS_ASSERT(capacity >= length);
if (length > CharBuffer::sMaxInlineStorage && capacity - length > length / 4) {
size_t bytes = sizeof(jschar) * (length + 1);
JSContext *cx = context();
ExclusiveContext *cx = context();
jschar *tmp = (jschar *)cx->realloc_(buf, bytes);
if (!tmp) {
js_free(buf);
@ -41,7 +41,7 @@ StringBuffer::extractWellSized()
JSFlatString *
StringBuffer::finishString()
{
JSContext *cx = context();
ExclusiveContext *cx = context();
if (cb.empty())
return cx->names().empty;
@ -69,7 +69,7 @@ StringBuffer::finishString()
JSAtom *
StringBuffer::finishAtom()
{
JSContext *cx = context();
ExclusiveContext *cx = context();
size_t length = cb.length();
if (length == 0)

View File

@ -33,13 +33,15 @@ class StringBuffer
CharBuffer cb;
JSContext *context() const { return cb.allocPolicy().context(); }
ExclusiveContext *context() const {
return cb.allocPolicy().context()->asExclusiveContext();
}
StringBuffer(const StringBuffer &other) MOZ_DELETE;
void operator=(const StringBuffer &other) MOZ_DELETE;
public:
explicit StringBuffer(JSContext *cx) : cb(cx) { }
explicit StringBuffer(ExclusiveContext *cx) : cb(cx) { }
inline bool reserve(size_t len) { return cb.reserve(len); }
inline bool resize(size_t len) { return cb.resize(len); }
@ -121,7 +123,7 @@ StringBuffer::appendInflated(const char *cstr, size_t cstrlen)
if (!cb.growByUninitialized(cstrlen))
return false;
mozilla::DebugOnly<size_t> oldcstrlen = cstrlen;
mozilla::DebugOnly<bool> ok = InflateStringToBuffer(context(), cstr, cstrlen,
mozilla::DebugOnly<bool> ok = InflateStringToBuffer(NULL, cstr, cstrlen,
begin() + lengthBefore, &cstrlen);
JS_ASSERT(ok && oldcstrlen == cstrlen);
return true;

View File

@ -0,0 +1,91 @@
/* 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/. */
//
// Pref management.
//
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
var gPrefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
function setWatchdogEnabled(enabled) {
gPrefs.setBoolPref("dom.use_watchdog", enabled);
}
function isWatchdogEnabled() {
return gPrefs.getBoolPref("dom.use_watchdog");
}
//
// Utilities.
//
function busyWait(ms) {
var start = new Date();
while ((new Date()) - start < ms) {}
}
function do_log_info(aMessage)
{
print("TEST-INFO | " + _TEST_FILE + " | " + aMessage);
}
// We don't use do_execute_soon, because that inserts a
// do_test_{pending,finished} pair that gets screwed up when we terminate scripts
// from the operation callback.
function executeSoon(fn) {
var tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
tm.mainThread.dispatch({run: fn}, Ci.nsIThread.DISPATCH_NORMAL);
}
//
// Asynchronous watchdog diagnostics.
//
// When running, the watchdog wakes up every second, and fires the operation
// callback if the script has been running for >= one second. As such, a script
// should never be able to run for two seconds or longer without servicing the
// operation callback. We wait 3 seconds, just to be safe.
//
function checkWatchdog(expectInterrupt, continuation) {
var lastWatchdogWakeup = Cu.getWatchdogTimestamp("WatchdogWakeup");
setOperationCallback(function() {
// If the watchdog didn't actually trigger the operation callback, ignore
// this call. This allows us to test the actual watchdog behavior without
// interference from other sites where we trigger the operation callback.
if (lastWatchdogWakeup == Cu.getWatchdogTimestamp("WatchdogWakeup")) {
return true;
}
do_check_true(expectInterrupt);
setOperationCallback(undefined);
// Schedule our continuation before we kill this script.
executeSoon(continuation);
return false;
});
executeSoon(function() {
busyWait(3000);
do_check_true(!expectInterrupt);
setOperationCallback(undefined);
continuation();
});
}
var gGenerator;
function continueTest() {
gGenerator.next();
}
function run_test() {
// Run async.
do_test_pending();
// Instantiate the generator and kick it off.
gGenerator = testBody();
gGenerator.next();
}

View File

@ -1,160 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//
// Pref management.
//
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
var gPrefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
function setWatchdogEnabled(enabled) {
gPrefs.setBoolPref("dom.use_watchdog", enabled);
}
function isWatchdogEnabled() {
return gPrefs.getBoolPref("dom.use_watchdog");
}
//
// Utilities.
//
function busyWait(ms) {
var start = new Date();
while ((new Date()) - start < ms) {}
}
function do_log_info(aMessage)
{
print("TEST-INFO | " + _TEST_FILE + " | " + aMessage);
}
// We don't use do_execute_soon, because that inserts a
// do_test_{pending,finished} pair that gets screwed up when we terminate scripts
// from the operation callback.
function executeSoon(fn) {
var tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
tm.mainThread.dispatch({run: fn}, Ci.nsIThread.DISPATCH_NORMAL);
}
//
// Asynchronous watchdog diagnostics.
//
// When running, the watchdog wakes up every second, and fires the operation
// callback if the script has been running for >= one second. As such, a script
// should never be able to run for two seconds or longer without servicing the
// operation callback. We wait 3 seconds, just to be safe.
//
function checkWatchdog(expectInterrupt, continuation) {
var lastWatchdogWakeup = Cu.getWatchdogTimestamp("WatchdogWakeup");
setOperationCallback(function() {
// If the watchdog didn't actually trigger the operation callback, ignore
// this call. This allows us to test the actual watchdog behavior without
// interference from other sites where we trigger the operation callback.
if (lastWatchdogWakeup == Cu.getWatchdogTimestamp("WatchdogWakeup")) {
return true;
}
do_check_true(expectInterrupt);
setOperationCallback(undefined);
// Schedule our continuation before we kill this script.
executeSoon(continuation);
return false;
});
executeSoon(function() {
busyWait(3000);
do_check_true(!expectInterrupt);
setOperationCallback(undefined);
continuation();
});
}
var gGenerator;
function continueTest() {
gGenerator.next();
}
function run_test() {
// Run async.
do_test_pending();
// Instantiate the generator and kick it off.
gGenerator = testBody();
gGenerator.next();
}
function testBody() {
// Before munging any prefs, check that we properly implement whatever behavior
// is specified by the default profile for this configuration.
checkWatchdog(isWatchdogEnabled(), continueTest);
yield;
// Toggle the watchdog, and check that state.
var was = isWatchdogEnabled();
setWatchdogEnabled(!isWatchdogEnabled());
do_check_true(was != isWatchdogEnabled());
checkWatchdog(isWatchdogEnabled(), continueTest);
yield;
// Now, make sure the watchdog is on.
setWatchdogEnabled(true);
do_check_true(isWatchdogEnabled());
checkWatchdog(true, continueTest);
yield;
//
// Now, check hibernation.
//
// It's unlikely that we've ever hibernated at this point, but the timestamps
// default to 0, so this should always be true.
var now = Date.now() * 1000;
var startHibernation = Cu.getWatchdogTimestamp("WatchdogHibernateStart");
var stopHibernation = Cu.getWatchdogTimestamp("WatchdogHibernateStop");
do_log_info("Pre-hibernation statistics:");
do_log_info("now: " + now / 1000000);
do_log_info("startHibernation: " + startHibernation / 1000000);
do_log_info("stopHibernation: " + stopHibernation / 1000000);
do_check_true(startHibernation < now);
do_check_true(stopHibernation < now);
// When the watchdog runs, it hibernates if there's been no activity for the
// last 2 seconds, otherwise it sleeps for 1 second. As such, given perfect
// scheduling, we should never have more than 3 seconds of inactivity without
// hibernating. To add some padding for automation, we mandate that hibernation
// must begin between 2 and 5 seconds from now.
var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
timer.initWithCallback(continueTest, 10000, Ci.nsITimer.TYPE_ONE_SHOT);
simulateActivityCallback(false);
yield;
simulateActivityCallback(true);
busyWait(1000); // Give the watchdog time to wake up on the condvar.
var stateChange = Cu.getWatchdogTimestamp("RuntimeStateChange");
startHibernation = Cu.getWatchdogTimestamp("WatchdogHibernateStart");
stopHibernation = Cu.getWatchdogTimestamp("WatchdogHibernateStop");
do_log_info("Post-hibernation statistics:");
do_log_info("stateChange: " + stateChange / 1000000);
do_log_info("startHibernation: " + startHibernation / 1000000);
do_log_info("stopHibernation: " + stopHibernation / 1000000);
// XPCOM timers, JS times, and PR_Now() are apparently not directly
// comparable, as evidenced by certain seemingly-impossible timing values
// that occasionally get logged in windows automation. We're really just
// making sure this behavior is roughly as expected on the macro scale,
// so we add a 1 second fuzz factor here.
const FUZZ_FACTOR = 1 * 1000 * 1000;
do_check_true(stateChange > now + 10*1000*1000 - FUZZ_FACTOR);
do_check_true(startHibernation > now + 2*1000*1000 - FUZZ_FACTOR);
do_check_true(startHibernation < now + 5*1000*1000 + FUZZ_FACTOR);
do_check_true(stopHibernation > now + 10*1000*1000 - FUZZ_FACTOR);
do_test_finished();
yield;
}

View File

@ -0,0 +1,12 @@
/* 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/. */
function testBody() {
// Check that we properly implement whatever behavior is specified by the
// default profile for this configuration.
checkWatchdog(isWatchdogEnabled(), continueTest);
yield;
do_test_finished();
yield;
}

View File

@ -0,0 +1,11 @@
/* 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/. */
function testBody() {
setWatchdogEnabled(false);
checkWatchdog(false, continueTest);
yield;
do_test_finished();
yield;
}

View File

@ -0,0 +1,11 @@
/* 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/. */
function testBody() {
setWatchdogEnabled(true);
checkWatchdog(true, continueTest);
yield;
do_test_finished();
yield;
}

View File

@ -0,0 +1,53 @@
/* 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/. */
function testBody() {
setWatchdogEnabled(true);
// It's unlikely that we've ever hibernated at this point, but the timestamps
// default to 0, so this should always be true.
var now = Date.now() * 1000;
var startHibernation = Cu.getWatchdogTimestamp("WatchdogHibernateStart");
var stopHibernation = Cu.getWatchdogTimestamp("WatchdogHibernateStop");
do_log_info("Pre-hibernation statistics:");
do_log_info("now: " + now / 1000000);
do_log_info("startHibernation: " + startHibernation / 1000000);
do_log_info("stopHibernation: " + stopHibernation / 1000000);
do_check_true(startHibernation < now);
do_check_true(stopHibernation < now);
// When the watchdog runs, it hibernates if there's been no activity for the
// last 2 seconds, otherwise it sleeps for 1 second. As such, given perfect
// scheduling, we should never have more than 3 seconds of inactivity without
// hibernating. To add some padding for automation, we mandate that hibernation
// must begin between 2 and 5 seconds from now.
var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
timer.initWithCallback(continueTest, 10000, Ci.nsITimer.TYPE_ONE_SHOT);
simulateActivityCallback(false);
yield;
simulateActivityCallback(true);
busyWait(1000); // Give the watchdog time to wake up on the condvar.
var stateChange = Cu.getWatchdogTimestamp("RuntimeStateChange");
startHibernation = Cu.getWatchdogTimestamp("WatchdogHibernateStart");
stopHibernation = Cu.getWatchdogTimestamp("WatchdogHibernateStop");
do_log_info("Post-hibernation statistics:");
do_log_info("stateChange: " + stateChange / 1000000);
do_log_info("startHibernation: " + startHibernation / 1000000);
do_log_info("stopHibernation: " + stopHibernation / 1000000);
// XPCOM timers, JS times, and PR_Now() are apparently not directly
// comparable, as evidenced by certain seemingly-impossible timing values
// that occasionally get logged in windows automation. We're really just
// making sure this behavior is roughly as expected on the macro scale,
// so we add a 1 second fuzz factor here.
const FUZZ_FACTOR = 1 * 1000 * 1000;
do_check_true(stateChange > now + 10*1000*1000 - FUZZ_FACTOR);
do_check_true(startHibernation > now + 2*1000*1000 - FUZZ_FACTOR);
do_check_true(startHibernation < now + 5*1000*1000 + FUZZ_FACTOR);
do_check_true(stopHibernation > now + 10*1000*1000 - FUZZ_FACTOR);
do_test_finished();
yield;
}

View File

@ -0,0 +1,13 @@
/* 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/. */
function testBody() {
var defaultBehavior = isWatchdogEnabled();
setWatchdogEnabled(!defaultBehavior);
setWatchdogEnabled(defaultBehavior);
checkWatchdog(defaultBehavior, continueTest);
yield;
do_test_finished();
yield;
}

View File

@ -52,4 +52,14 @@ fail-if = os == "android"
[test_allowedDomainsXHR.js]
[test_nuke_sandbox.js]
[test_exportFunction.js]
[test_watchdog.js]
[test_watchdog_enable.js]
head = head_watchdog.js
[test_watchdog_disable.js]
head = head_watchdog.js
[test_watchdog_toggle.js]
head = head_watchdog.js
[test_watchdog_default.js]
head = head_watchdog.js
[test_watchdog_hibernate.js]
head = head_watchdog.js

View File

@ -0,0 +1,13 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<rect height="100%" width="100%" fill="lime" />
<rect height="100" width="100" fill="red">
<set attributeName="fill" attributeType="XML" dur="indefinite"
to="url(#reaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaallyLongURL) transparent"/>
</rect>
</svg>

After

Width:  |  Height:  |  Size: 789 B

View File

@ -245,6 +245,8 @@ fuzzy-if(cocoaWidget&&layersGPUAccelerated,1,2) == anim-gradient-attr-presence-0
== inactivate-with-active-unchanged-1.svg anim-standard-ref.svg
== inactivate-with-active-unchanged-2.svg anim-standard-ref.svg
== mapped-attr-long-url-1.svg lime.svg
# interaction between xml mapped attributes and their css equivalents
== mapped-attr-vs-css-prop-1.svg lime.svg

View File

@ -61,7 +61,12 @@ static ANPTypefaceStyle anp_getStyle(const ANPTypeface* tf) {
static int32_t anp_getFontPath(const ANPTypeface* tf, char fileName[],
int32_t length, int32_t* index) {
SkStream* stream = tf->openStream(index);
strcpy(fileName, stream->getFileName());
if (stream->getFileName()) {
strcpy(fileName, stream->getFileName());
} else {
return 0;
}
return strlen(fileName);
}