mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge inbound to m-c on a CLOSED TREE.
This commit is contained in:
commit
51102e8743
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -382,7 +382,8 @@ void* MediaDecoderReader::VideoQueueMemoryFunctor::operator()(void* anObject) {
|
||||
}
|
||||
|
||||
MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder)
|
||||
: mDecoder(aDecoder)
|
||||
: mDecoder(aDecoder),
|
||||
mIgnoreAudioOutputFormat(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(MediaDecoderReader);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
BIN
content/media/webaudio/test/audio-quad.wav
Normal file
BIN
content/media/webaudio/test/audio-quad.wav
Normal file
Binary file not shown.
58
content/media/webaudio/test/test_decodeMultichannel.html
Normal file
58
content/media/webaudio/test/test_decodeMultichannel.html
Normal 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 <audio></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>
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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*
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 ();
|
||||
|
@ -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()) {
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
||||
/*
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
26
js/src/jit-test/tests/ion/bug909401.js
Normal file
26
js/src/jit-test/tests/ion/bug909401.js
Normal 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 });
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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); }
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -192,7 +192,7 @@ typedef void
|
||||
|
||||
namespace JS {
|
||||
|
||||
typedef void (*OffThreadCompileCallback)(JSScript *script, void *callbackData);
|
||||
typedef void (*OffThreadCompileCallback)(void *token, void *callbackData);
|
||||
|
||||
namespace shadow {
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
91
js/xpconnect/tests/unit/head_watchdog.js
Normal file
91
js/xpconnect/tests/unit/head_watchdog.js
Normal 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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
12
js/xpconnect/tests/unit/test_watchdog_default.js
Normal file
12
js/xpconnect/tests/unit/test_watchdog_default.js
Normal 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;
|
||||
}
|
11
js/xpconnect/tests/unit/test_watchdog_disable.js
Normal file
11
js/xpconnect/tests/unit/test_watchdog_disable.js
Normal 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;
|
||||
}
|
11
js/xpconnect/tests/unit/test_watchdog_enable.js
Normal file
11
js/xpconnect/tests/unit/test_watchdog_enable.js
Normal 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;
|
||||
}
|
53
js/xpconnect/tests/unit/test_watchdog_hibernate.js
Normal file
53
js/xpconnect/tests/unit/test_watchdog_hibernate.js
Normal 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;
|
||||
}
|
13
js/xpconnect/tests/unit/test_watchdog_toggle.js
Normal file
13
js/xpconnect/tests/unit/test_watchdog_toggle.js
Normal 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;
|
||||
}
|
@ -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
|
||||
|
||||
|
13
layout/reftests/svg/smil/mapped-attr-long-url-1.svg
Normal file
13
layout/reftests/svg/smil/mapped-attr-long-url-1.svg
Normal 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 |
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user