From d9b0f7f41896c5e05c837f9c87f68695cd42d47a Mon Sep 17 00:00:00 2001 From: Randy Lin Date: Fri, 31 Oct 2014 11:01:09 +0800 Subject: [PATCH 01/47] Bug 1091451 - [FM radio]The sound can not output from headset in FM radio when active call. r=amarchesini --- dom/speakermanager/SpeakerManagerService.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/dom/speakermanager/SpeakerManagerService.cpp b/dom/speakermanager/SpeakerManagerService.cpp index 48f998cdfb5e..5eabd704f534 100644 --- a/dom/speakermanager/SpeakerManagerService.cpp +++ b/dom/speakermanager/SpeakerManagerService.cpp @@ -99,15 +99,10 @@ SpeakerManagerService::TuruOnSpeaker(bool aOn) { nsCOMPtr audioManager = do_GetService(NS_AUDIOMANAGER_CONTRACTID); NS_ENSURE_TRUE_VOID(audioManager); - int32_t phoneState; - audioManager->GetPhoneState(&phoneState); - int32_t forceuse = (phoneState == nsIAudioManager::PHONE_STATE_IN_CALL || - phoneState == nsIAudioManager::PHONE_STATE_IN_COMMUNICATION) - ? nsIAudioManager::USE_COMMUNICATION : nsIAudioManager::USE_MEDIA; if (aOn) { - audioManager->SetForceForUse(forceuse, nsIAudioManager::FORCE_SPEAKER); + audioManager->SetForceForUse(nsIAudioManager::USE_MEDIA, nsIAudioManager::FORCE_SPEAKER); } else { - audioManager->SetForceForUse(forceuse, nsIAudioManager::FORCE_NONE); + audioManager->SetForceForUse(nsIAudioManager::USE_MEDIA, nsIAudioManager::FORCE_NONE); } } From 17502c7ff13048bfa0a5553115983dc0e26e6de9 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Tue, 11 Nov 2014 09:10:56 +0000 Subject: [PATCH 02/47] Bug 1094257 - nsPrincipal::GetBaseDomain() should not use TLD if the protocol handler of the URI scheme has NORELATIVE flag, r=bz --- caps/nsPrincipal.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/caps/nsPrincipal.cpp b/caps/nsPrincipal.cpp index c2d07b5b88d9..bcbc909f2c75 100644 --- a/caps/nsPrincipal.cpp +++ b/caps/nsPrincipal.cpp @@ -17,6 +17,7 @@ #include "nsIObjectInputStream.h" #include "nsIObjectOutputStream.h" #include "nsIClassInfoImpl.h" +#include "nsIProtocolHandler.h" #include "nsError.h" #include "nsIContentSecurityPolicy.h" #include "jswrapper.h" @@ -490,6 +491,18 @@ nsPrincipal::GetBaseDomain(nsACString& aBaseDomain) } } + bool hasNoRelativeFlag; + nsresult rv = NS_URIChainHasFlags(mCodebase, + nsIProtocolHandler::URI_NORELATIVE, + &hasNoRelativeFlag); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (hasNoRelativeFlag) { + return mCodebase->GetSpec(aBaseDomain); + } + // For everything else, we ask the TLD service via // the ThirdPartyUtil. nsCOMPtr thirdPartyUtil = From 88b1d4572f4e2354d780c733aa5f1aff8c362487 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Tue, 11 Nov 2014 11:56:44 +0100 Subject: [PATCH 03/47] Bug 1094255 - Optimize GetElements on NodeLists to make fun.apply(x, nodeList) faster. r=bz,evilpie --- dom/bindings/Codegen.py | 14 +-- js/public/Class.h | 42 ++++++- js/src/builtin/TypedObject.cpp | 2 +- .../tests/basic/function-apply-proxy.js | 26 +++++ js/src/jsarray.cpp | 105 +++++++++++++----- js/src/jsfriendapi.cpp | 8 -- js/src/jsfriendapi.h | 13 +-- js/src/jsproxy.h | 4 +- js/src/proxy/BaseProxyHandler.cpp | 6 +- js/src/proxy/Proxy.cpp | 14 +-- js/src/proxy/Proxy.h | 4 +- js/src/vm/ScopeObject.cpp | 4 +- js/xpconnect/src/XPCWrappedNativeJSOps.cpp | 2 +- js/xpconnect/src/xpcprivate.h | 4 +- 14 files changed, 175 insertions(+), 73 deletions(-) create mode 100644 js/src/jit-test/tests/basic/function-apply-proxy.js diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 7e9596bcfa37..b8b78b56fad1 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -409,7 +409,7 @@ class CGDOMJSClass(CGThing): nullptr, /* deleteGeneric */ nullptr, /* watch */ nullptr, /* unwatch */ - nullptr, /* slice */ + nullptr, /* getElements */ nullptr, /* enumerate */ JS_ObjectToOuterObject /* thisObject */ } @@ -10716,7 +10716,7 @@ class CGDOMJSProxyHandler_finalize(ClassMethod): finalizeHook(self.descriptor, FINALIZE_HOOK_NAME, self.args[0].name).define()) -class CGDOMJSProxyHandler_slice(ClassMethod): +class CGDOMJSProxyHandler_getElements(ClassMethod): def __init__(self, descriptor): assert descriptor.supportsIndexedProperties() @@ -10724,8 +10724,8 @@ class CGDOMJSProxyHandler_slice(ClassMethod): Argument('JS::Handle', 'proxy'), Argument('uint32_t', 'begin'), Argument('uint32_t', 'end'), - Argument('JS::Handle', 'array')] - ClassMethod.__init__(self, "slice", "bool", args, virtual=True, override=True, const=True) + Argument('js::ElementAdder*', 'adder')] + ClassMethod.__init__(self, "getElements", "bool", args, virtual=True, override=True, const=True) self.descriptor = descriptor def getBody(self): @@ -10738,7 +10738,7 @@ class CGDOMJSProxyHandler_slice(ClassMethod): 'jsvalRef': 'temp', 'jsvalHandle': '&temp', 'obj': 'proxy', - 'successCode': ("js::UnsafeDefineElement(cx, array, index - begin, temp);\n" + 'successCode': ("adder->append(cx, temp);\n" "continue;\n") } get = CGProxyIndexedGetter(self.descriptor, templateValues, False, False).define() @@ -10763,7 +10763,7 @@ class CGDOMJSProxyHandler_slice(ClassMethod): if (!js::GetObjectProto(cx, proxy, &proto)) { return false; } - return js::SliceSlowly(cx, proto, proxy, ourEnd, end, array); + return js::GetElementsWithAdder(cx, proto, proxy, ourEnd, end, adder); } return true; @@ -10836,7 +10836,7 @@ class CGDOMJSProxyHandler(CGClass): if descriptor.supportsIndexedProperties(): - methods.append(CGDOMJSProxyHandler_slice(descriptor)) + methods.append(CGDOMJSProxyHandler_getElements(descriptor)) if (descriptor.operations['IndexedSetter'] is not None or (descriptor.operations['NamedSetter'] is not None and descriptor.interface.getExtendedAttribute('OverrideBuiltins'))): diff --git a/js/public/Class.h b/js/public/Class.h index 0c7b5063d629..50f5dd91c0c6 100644 --- a/js/public/Class.h +++ b/js/public/Class.h @@ -9,6 +9,7 @@ #ifndef js_Class_h #define js_Class_h +#include "mozilla/DebugOnly.h" #include "mozilla/NullPtr.h" #include "jstypes.h" @@ -226,9 +227,44 @@ typedef bool typedef bool (* UnwatchOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id); +class JS_FRIEND_API(ElementAdder) +{ + public: + enum GetBehavior { + // Check if the element exists before performing the Get and preserve + // holes. + CheckHasElemPreserveHoles, + + // Perform a Get operation, like obj[index] in JS. + GetElement + }; + + private: + // Only one of these is used. + JS::RootedObject resObj_; + JS::Value *vp_; + + uint32_t index_; + mozilla::DebugOnly length_; + GetBehavior getBehavior_; + + public: + ElementAdder(JSContext *cx, JSObject *obj, uint32_t length, GetBehavior behavior) + : resObj_(cx, obj), vp_(nullptr), index_(0), length_(length), getBehavior_(behavior) + {} + ElementAdder(JSContext *cx, JS::Value *vp, uint32_t length, GetBehavior behavior) + : resObj_(cx), vp_(vp), index_(0), length_(length), getBehavior_(behavior) + {} + + GetBehavior getBehavior() const { return getBehavior_; } + + void append(JSContext *cx, JS::HandleValue v); + void appendHole(); +}; + typedef bool -(* SliceOp)(JSContext *cx, JS::HandleObject obj, uint32_t begin, uint32_t end, - JS::HandleObject result); // result is actually preallocted. +(* GetElementsOp)(JSContext *cx, JS::HandleObject obj, uint32_t begin, uint32_t end, + ElementAdder *adder); // A generic type for functions mapping an object to another object, or null // if an error or exception was thrown on cx. @@ -364,7 +400,7 @@ struct ObjectOps DeleteGenericOp deleteGeneric; WatchOp watch; UnwatchOp unwatch; - SliceOp slice; // Optimized slice, can be null. + GetElementsOp getElements; JSNewEnumerateOp enumerate; ObjectOp thisObject; }; diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index 5518697ba3a5..22baa228c083 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -2404,7 +2404,7 @@ LazyArrayBufferTable::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) TypedObject::obj_setGenericAttributes, \ TypedObject::obj_deleteGeneric, \ nullptr, nullptr, /* watch/unwatch */ \ - nullptr, /* slice */ \ + nullptr, /* getElements */ \ TypedObject::obj_enumerate, \ nullptr, /* thisObject */ \ } \ diff --git a/js/src/jit-test/tests/basic/function-apply-proxy.js b/js/src/jit-test/tests/basic/function-apply-proxy.js new file mode 100644 index 000000000000..9a00fdb3de7e --- /dev/null +++ b/js/src/jit-test/tests/basic/function-apply-proxy.js @@ -0,0 +1,26 @@ +// fun.apply(null, proxy) should not invoke the proxy's Has trap. + +var proxy = new Proxy({}, { + get: function (target, name, proxy) { + switch (name) { + case "length": + return 2; + case "0": + return 15; + case "1": + return undefined; + default: + assertEq(false, true); + } + }, + has: function (target, name) { + assertEq(false, true); + } +}); +function foo() { + assertEq(arguments.length, 2); + assertEq(arguments[0], 15); + assertEq(1 in arguments, true); + assertEq(arguments[1], undefined); +} +foo.apply(null, proxy); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 46209b82bb4b..8fa6f8f034e6 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -237,12 +237,51 @@ GetElement(JSContext *cx, HandleObject obj, IndexType index, bool *hole, Mutable return GetElement(cx, obj, obj, index, hole, vp); } -static bool -GetElementsSlow(JSContext *cx, HandleObject aobj, uint32_t length, Value *vp) +void +ElementAdder::append(JSContext *cx, HandleValue v) { - for (uint32_t i = 0; i < length; i++) { - if (!JSObject::getElement(cx, aobj, aobj, i, MutableHandleValue::fromMarkedLocation(&vp[i]))) - return false; + MOZ_ASSERT(index_ < length_); + if (resObj_) + resObj_->as().setDenseElementWithType(cx, index_++, v); + else + vp_[index_++] = v; +} + +void +ElementAdder::appendHole() +{ + MOZ_ASSERT(getBehavior_ == ElementAdder::CheckHasElemPreserveHoles); + MOZ_ASSERT(index_ < length_); + if (resObj_) { + MOZ_ASSERT(resObj_->as().getDenseElement(index_).isMagic(JS_ELEMENTS_HOLE)); + index_++; + } else { + vp_[index_++].setMagic(JS_ELEMENTS_HOLE); + } +} + +bool +js::GetElementsWithAdder(JSContext *cx, HandleObject obj, HandleObject receiver, + uint32_t begin, uint32_t end, ElementAdder *adder) +{ + MOZ_ASSERT(begin <= end); + + RootedValue val(cx); + for (uint32_t i = begin; i < end; i++) { + if (adder->getBehavior() == ElementAdder::CheckHasElemPreserveHoles) { + bool hole; + if (!GetElement(cx, obj, receiver, i, &hole, &val)) + return false; + if (hole) { + adder->appendHole(); + continue; + } + } else { + MOZ_ASSERT(adder->getBehavior() == ElementAdder::GetElement); + if (!JSObject::getElement(cx, obj, receiver, i, &val)) + return false; + } + adder->append(cx, val); } return true; @@ -272,7 +311,17 @@ js::GetElements(JSContext *cx, HandleObject aobj, uint32_t length, Value *vp) } } - return GetElementsSlow(cx, aobj, length, vp); + if (js::GetElementsOp op = aobj->getOps()->getElements) { + ElementAdder adder(cx, vp, length, ElementAdder::GetElement); + return op(cx, aobj, 0, length, &adder); + } + + for (uint32_t i = 0; i < length; i++) { + if (!JSObject::getElement(cx, aobj, aobj, i, MutableHandleValue::fromMarkedLocation(&vp[i]))) + return false; + } + + return true; } /* @@ -2815,6 +2864,24 @@ GetIndexedPropertiesInRange(JSContext *cx, HandleObject obj, uint32_t begin, uin return true; } +static bool +SliceSlowly(JSContext* cx, HandleObject obj, HandleObject receiver, + uint32_t begin, uint32_t end, HandleObject result) +{ + RootedValue value(cx); + for (uint32_t slot = begin; slot < end; slot++) { + bool hole; + if (!CheckForInterrupt(cx) || + !GetElement(cx, obj, receiver, slot, &hole, &value)) + { + return false; + } + if (!hole && !JSObject::defineElement(cx, result, slot - begin, value)) + return false; + } + return true; +} + static bool SliceSparse(JSContext *cx, HandleObject obj, uint32_t begin, uint32_t end, HandleObject result) { @@ -2913,14 +2980,16 @@ js::array_slice(JSContext *cx, unsigned argc, Value *vp) return false; TryReuseArrayType(obj, narr); - if (js::SliceOp op = obj->getOps()->slice) { - // Ensure that we have dense elements, so that DOM can use js::UnsafeDefineElement. + if (js::GetElementsOp op = obj->getOps()->getElements) { + // Ensure that we have dense elements, so that ElementAdder::append can + // use setDenseElementWithType. NativeObject::EnsureDenseResult result = narr->ensureDenseElements(cx, 0, end - begin); if (result == NativeObject::ED_FAILED) return false; if (result == NativeObject::ED_OK) { - if (!op(cx, obj, begin, end, narr)) + ElementAdder adder(cx, narr, end - begin, ElementAdder::CheckHasElemPreserveHoles); + if (!op(cx, obj, begin, end, &adder)) return false; args.rval().setObject(*narr); @@ -2943,24 +3012,6 @@ js::array_slice(JSContext *cx, unsigned argc, Value *vp) return true; } -JS_FRIEND_API(bool) -js::SliceSlowly(JSContext* cx, HandleObject obj, HandleObject receiver, - uint32_t begin, uint32_t end, HandleObject result) -{ - RootedValue value(cx); - for (uint32_t slot = begin; slot < end; slot++) { - bool hole; - if (!CheckForInterrupt(cx) || - !GetElement(cx, obj, receiver, slot, &hole, &value)) - { - return false; - } - if (!hole && !JSObject::defineElement(cx, result, slot - begin, value)) - return false; - } - return true; -} - /* ES5 15.4.4.20. */ static bool array_filter(JSContext *cx, unsigned argc, Value *vp) diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 08fe7d241e81..c89076c61e2d 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -1386,14 +1386,6 @@ js::GetObjectMetadata(JSObject *obj) return obj->getMetadata(); } -JS_FRIEND_API(void) -js::UnsafeDefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value) -{ - MOZ_ASSERT(obj->isNative()); - MOZ_ASSERT(index < obj->as().getDenseInitializedLength()); - obj->as().setDenseElementWithType(cx, index, value); -} - JS_FRIEND_API(bool) js_DefineOwnProperty(JSContext *cx, JSObject *objArg, jsid idArg, JS::Handle descriptor, bool *bp) diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index d7514cb5f7fb..c3a39c033fc2 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -323,7 +323,7 @@ namespace js { js::proxy_SetGenericAttributes, \ js::proxy_DeleteGeneric, \ js::proxy_Watch, js::proxy_Unwatch, \ - js::proxy_Slice, \ + js::proxy_GetElements, \ nullptr, /* enumerate */ \ nullptr, /* thisObject */ \ } \ @@ -411,8 +411,8 @@ proxy_Watch(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObje extern JS_FRIEND_API(bool) proxy_Unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id); extern JS_FRIEND_API(bool) -proxy_Slice(JSContext *cx, JS::HandleObject proxy, uint32_t begin, uint32_t end, - JS::HandleObject result); +proxy_GetElements(JSContext *cx, JS::HandleObject proxy, uint32_t begin, uint32_t end, + ElementAdder *adder); /* * A class of objects that return source code on demand. @@ -2578,12 +2578,9 @@ SetObjectMetadata(JSContext *cx, JS::HandleObject obj, JS::HandleObject metadata JS_FRIEND_API(JSObject *) GetObjectMetadata(JSObject *obj); -JS_FRIEND_API(void) -UnsafeDefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value); - JS_FRIEND_API(bool) -SliceSlowly(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver, - uint32_t begin, uint32_t end, JS::HandleObject result); +GetElementsWithAdder(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, + uint32_t begin, uint32_t end, js::ElementAdder *adder); JS_FRIEND_API(bool) ForwardToNative(JSContext *cx, JSNative native, const JS::CallArgs &args); diff --git a/js/src/jsproxy.h b/js/src/jsproxy.h index c9221fd0d5fb..2d122385609d 100644 --- a/js/src/jsproxy.h +++ b/js/src/jsproxy.h @@ -332,8 +332,8 @@ class JS_FRIEND_API(BaseProxyHandler) JS::HandleObject callable) const; virtual bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id) const; - virtual bool slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end, - HandleObject result) const; + virtual bool getElements(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end, + ElementAdder *adder) const; /* See comment for weakmapKeyDelegateOp in js/Class.h. */ virtual JSObject *weakmapKeyDelegate(JSObject *proxy) const; diff --git a/js/src/proxy/BaseProxyHandler.cpp b/js/src/proxy/BaseProxyHandler.cpp index ff0454427680..403e5f856f01 100644 --- a/js/src/proxy/BaseProxyHandler.cpp +++ b/js/src/proxy/BaseProxyHandler.cpp @@ -341,12 +341,12 @@ BaseProxyHandler::unwatch(JSContext *cx, HandleObject proxy, HandleId id) const } bool -BaseProxyHandler::slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end, - HandleObject result) const +BaseProxyHandler::getElements(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end, + ElementAdder *adder) const { assertEnteredPolicy(cx, proxy, JSID_VOID, GET); - return js::SliceSlowly(cx, proxy, proxy, begin, end, result); + return js::GetElementsWithAdder(cx, proxy, proxy, begin, end, adder); } bool diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index 67d92da466de..505740fde96a 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -550,8 +550,8 @@ Proxy::unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id) } /* static */ bool -Proxy::slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end, - HandleObject result) +Proxy::getElements(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end, + ElementAdder *adder) { JS_CHECK_RECURSION(cx, return false); const BaseProxyHandler *handler = proxy->as().handler(); @@ -560,11 +560,11 @@ Proxy::slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end, if (!policy.allowed()) { if (policy.returnValue()) { MOZ_ASSERT(!cx->isExceptionPending()); - return js::SliceSlowly(cx, proxy, proxy, begin, end, result); + return js::GetElementsWithAdder(cx, proxy, proxy, begin, end, adder); } return false; } - return handler->slice(cx, proxy, begin, end, result); + return handler->getElements(cx, proxy, begin, end, adder); } JSObject * @@ -835,10 +835,10 @@ js::proxy_Unwatch(JSContext *cx, HandleObject obj, HandleId id) } bool -js::proxy_Slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end, - HandleObject result) +js::proxy_GetElements(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end, + ElementAdder *adder) { - return Proxy::slice(cx, proxy, begin, end, result); + return Proxy::getElements(cx, proxy, begin, end, adder); } const Class js::ProxyObject::class_ = diff --git a/js/src/proxy/Proxy.h b/js/src/proxy/Proxy.h index f163c52cda67..c634a040a5fb 100644 --- a/js/src/proxy/Proxy.h +++ b/js/src/proxy/Proxy.h @@ -69,8 +69,8 @@ class Proxy static bool watch(JSContext *cx, HandleObject proxy, HandleId id, HandleObject callable); static bool unwatch(JSContext *cx, HandleObject proxy, HandleId id); - static bool slice(JSContext *cx, HandleObject obj, uint32_t begin, uint32_t end, - HandleObject result); + static bool getElements(JSContext *cx, HandleObject obj, uint32_t begin, uint32_t end, + ElementAdder *adder); /* IC entry path for handling __noSuchMethod__ on access. */ static bool callProp(JSContext *cx, HandleObject proxy, HandleObject reveiver, HandleId id, diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index f4fdfc2b21e6..1c6ea12f9b8f 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -605,7 +605,7 @@ const Class DynamicWithObject::class_ = { with_SetGenericAttributes, with_DeleteGeneric, nullptr, nullptr, /* watch/unwatch */ - nullptr, /* slice */ + nullptr, /* getElements */ nullptr, /* enumerate (native enumeration of target doesn't work) */ with_ThisObject, } @@ -1045,7 +1045,7 @@ const Class UninitializedLexicalObject::class_ = { uninitialized_SetGenericAttributes, uninitialized_DeleteGeneric, nullptr, nullptr, /* watch/unwatch */ - nullptr, /* slice */ + nullptr, /* getElements */ nullptr, /* enumerate (native enumeration of target doesn't work) */ nullptr, /* this */ } diff --git a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp index 762747134a2d..471c27d86dd6 100644 --- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp @@ -697,7 +697,7 @@ const XPCWrappedNativeJSClass XPC_WN_NoHelper_JSClass = { nullptr, // setGenericAttributes nullptr, // deleteGeneric nullptr, nullptr, // watch/unwatch - nullptr, // slice + nullptr, // getElements XPC_WN_JSOp_Enumerate, XPC_WN_JSOp_ThisObject, } diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index f4c729c2bf83..f73634d612c1 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -974,7 +974,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS::HandleObject obj); nullptr, /* setGenericAttributes */ \ nullptr, /* deleteGeneric */ \ nullptr, nullptr, /* watch/unwatch */ \ - nullptr, /* slice */ \ + nullptr, /* getElements */ \ XPC_WN_JSOp_Enumerate, \ XPC_WN_JSOp_ThisObject, \ } @@ -997,7 +997,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS::HandleObject obj); nullptr, /* setGenericAttributes */ \ nullptr, /* deleteGeneric */ \ nullptr, nullptr, /* watch/unwatch */ \ - nullptr, /* slice */ \ + nullptr, /* getElements */ \ XPC_WN_JSOp_Enumerate, \ XPC_WN_JSOp_ThisObject, \ } From 8412cec73ab77cb81d4dfa25dd03c15734b58e82 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Tue, 11 Nov 2014 11:02:41 +0000 Subject: [PATCH 04/47] Bug 1096260 - Convert flags parameter of nsIFrame::ComputeSize from uint32_t to a typed enum, and update callers accordingly. r=dholbert --- layout/forms/nsFieldSetFrame.cpp | 2 +- layout/forms/nsFieldSetFrame.h | 2 +- layout/generic/nsBlockReflowState.cpp | 2 +- layout/generic/nsFirstLetterFrame.cpp | 2 +- layout/generic/nsFirstLetterFrame.h | 2 +- layout/generic/nsFrame.cpp | 6 +++--- layout/generic/nsFrame.h | 2 +- layout/generic/nsHTMLCanvasFrame.cpp | 2 +- layout/generic/nsHTMLCanvasFrame.h | 2 +- layout/generic/nsHTMLReflowState.cpp | 19 +++++++++++++------ layout/generic/nsIFrame.h | 5 +++-- layout/generic/nsImageFrame.cpp | 2 +- layout/generic/nsImageFrame.h | 2 +- layout/generic/nsInlineFrame.cpp | 2 +- layout/generic/nsInlineFrame.h | 2 +- layout/generic/nsSubDocumentFrame.cpp | 2 +- layout/generic/nsSubDocumentFrame.h | 2 +- layout/generic/nsTextFrame.cpp | 2 +- layout/generic/nsTextFrame.h | 2 +- layout/generic/nsVideoFrame.cpp | 2 +- layout/generic/nsVideoFrame.h | 2 +- layout/svg/nsSVGOuterSVGFrame.cpp | 2 +- layout/svg/nsSVGOuterSVGFrame.h | 2 +- layout/tables/nsTableFrame.cpp | 2 +- layout/tables/nsTableFrame.h | 2 +- layout/tables/nsTableOuterFrame.cpp | 2 +- 26 files changed, 42 insertions(+), 34 deletions(-) diff --git a/layout/forms/nsFieldSetFrame.cpp b/layout/forms/nsFieldSetFrame.cpp index b12759c225a6..48d524a2ee94 100644 --- a/layout/forms/nsFieldSetFrame.cpp +++ b/layout/forms/nsFieldSetFrame.cpp @@ -318,7 +318,7 @@ nsFieldSetFrame::ComputeSize(nsRenderingContext *aRenderingContext, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, - uint32_t aFlags) + ComputeSizeFlags aFlags) { LogicalSize result = nsContainerFrame::ComputeSize(aRenderingContext, aWM, diff --git a/layout/forms/nsFieldSetFrame.h b/layout/forms/nsFieldSetFrame.h index 626ce58f45b7..768f097eee0a 100644 --- a/layout/forms/nsFieldSetFrame.h +++ b/layout/forms/nsFieldSetFrame.h @@ -29,7 +29,7 @@ public: const mozilla::LogicalSize& aMargin, const mozilla::LogicalSize& aBorder, const mozilla::LogicalSize& aPadding, - uint32_t aFlags) MOZ_OVERRIDE; + ComputeSizeFlags aFlags) MOZ_OVERRIDE; virtual nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode) const MOZ_OVERRIDE; /** diff --git a/layout/generic/nsBlockReflowState.cpp b/layout/generic/nsBlockReflowState.cpp index b35e67482b31..4e1658be70cf 100644 --- a/layout/generic/nsBlockReflowState.cpp +++ b/layout/generic/nsBlockReflowState.cpp @@ -641,7 +641,7 @@ FloatMarginISize(const nsHTMLReflowState& aCBReflowState, aFloatOffsetState.ComputedLogicalBorderPadding().Size(wm) - aFloatOffsetState.ComputedLogicalPadding().Size(wm), aFloatOffsetState.ComputedLogicalPadding().Size(wm), - true); + nsIFrame::ComputeSizeFlags::eShrinkWrap); return floatSize.ISize(wm) + aFloatOffsetState.ComputedLogicalMargin().IStartEnd(wm) + diff --git a/layout/generic/nsFirstLetterFrame.cpp b/layout/generic/nsFirstLetterFrame.cpp index e1a3c5251158..95c813168847 100644 --- a/layout/generic/nsFirstLetterFrame.cpp +++ b/layout/generic/nsFirstLetterFrame.cpp @@ -147,7 +147,7 @@ nsFirstLetterFrame::ComputeSize(nsRenderingContext *aRenderingContext, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, - uint32_t aFlags) + ComputeSizeFlags aFlags) { if (GetPrevInFlow()) { // We're wrapping the text *after* the first letter, so behave like an diff --git a/layout/generic/nsFirstLetterFrame.h b/layout/generic/nsFirstLetterFrame.h index 8295a428fb93..269257d613a1 100644 --- a/layout/generic/nsFirstLetterFrame.h +++ b/layout/generic/nsFirstLetterFrame.h @@ -58,7 +58,7 @@ public: const mozilla::LogicalSize& aMargin, const mozilla::LogicalSize& aBorder, const mozilla::LogicalSize& aPadding, - uint32_t aFlags) MOZ_OVERRIDE; + ComputeSizeFlags aFlags) MOZ_OVERRIDE; virtual void Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 2cc1a5ac4d2d..9670a0ae808b 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -4074,12 +4074,12 @@ nsFrame::ComputeSize(nsRenderingContext *aRenderingContext, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, - uint32_t aFlags) + ComputeSizeFlags aFlags) { LogicalSize result = ComputeAutoSize(aRenderingContext, aWM, aCBSize, aAvailableISize, aMargin, aBorder, aPadding, - aFlags & eShrinkWrap); + aFlags & ComputeSizeFlags::eShrinkWrap); LogicalSize boxSizingAdjust(aWM); const nsStylePosition *stylePos = StylePosition(); @@ -8399,7 +8399,7 @@ nsFrame::BoxReflow(nsBoxLayoutState& aState, reflowState.ComputedLogicalBorderPadding().Size(wm) - reflowState.ComputedLogicalPadding().Size(wm), reflowState.ComputedLogicalPadding().Size(wm), - false).Height(wm)); + ComputeSizeFlags::eDefault).Height(wm)); } } diff --git a/layout/generic/nsFrame.h b/layout/generic/nsFrame.h index 0f69001cb442..74d5dc820e90 100644 --- a/layout/generic/nsFrame.h +++ b/layout/generic/nsFrame.h @@ -257,7 +257,7 @@ public: const mozilla::LogicalSize& aMargin, const mozilla::LogicalSize& aBorder, const mozilla::LogicalSize& aPadding, - uint32_t aFlags) MOZ_OVERRIDE; + ComputeSizeFlags aFlags) MOZ_OVERRIDE; // Compute tight bounds assuming this frame honours its border, background // and outline, its children's tight bounds, and nothing else. diff --git a/layout/generic/nsHTMLCanvasFrame.cpp b/layout/generic/nsHTMLCanvasFrame.cpp index 62158e04f4e0..11ac7899fd6f 100644 --- a/layout/generic/nsHTMLCanvasFrame.cpp +++ b/layout/generic/nsHTMLCanvasFrame.cpp @@ -161,7 +161,7 @@ nsHTMLCanvasFrame::ComputeSize(nsRenderingContext *aRenderingContext, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, - uint32_t aFlags) + ComputeSizeFlags aFlags) { nsIntSize size = GetCanvasSize(); diff --git a/layout/generic/nsHTMLCanvasFrame.h b/layout/generic/nsHTMLCanvasFrame.h index 4351f53effb6..612087cf728b 100644 --- a/layout/generic/nsHTMLCanvasFrame.h +++ b/layout/generic/nsHTMLCanvasFrame.h @@ -68,7 +68,7 @@ public: const mozilla::LogicalSize& aMargin, const mozilla::LogicalSize& aBorder, const mozilla::LogicalSize& aPadding, - uint32_t aFlags) MOZ_OVERRIDE; + ComputeSizeFlags aFlags) MOZ_OVERRIDE; virtual void Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, diff --git a/layout/generic/nsHTMLReflowState.cpp b/layout/generic/nsHTMLReflowState.cpp index cc334691e55e..dbb11cf73026 100644 --- a/layout/generic/nsHTMLReflowState.cpp +++ b/layout/generic/nsHTMLReflowState.cpp @@ -1461,9 +1461,11 @@ nsHTMLReflowState::InitAbsoluteConstraints(nsPresContext* aPresContext, bool widthIsAuto = eStyleUnit_Auto == mStylePosition->mWidth.GetUnit(); bool heightIsAuto = eStyleUnit_Auto == mStylePosition->mHeight.GetUnit(); - uint32_t computeSizeFlags = 0; + typedef nsIFrame::ComputeSizeFlags ComputeSizeFlags; + ComputeSizeFlags computeSizeFlags = ComputeSizeFlags::eDefault; if (leftIsAuto || rightIsAuto) { - computeSizeFlags |= nsIFrame::eShrinkWrap; + computeSizeFlags = + ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap); } { @@ -2117,7 +2119,9 @@ nsHTMLReflowState::InitConstraints(nsPresContext* aPresContext, AutoMaybeDisableFontInflation an(frame); bool isBlock = NS_CSS_FRAME_TYPE_BLOCK == NS_FRAME_GET_TYPE(mFrameType); - uint32_t computeSizeFlags = isBlock ? 0 : nsIFrame::eShrinkWrap; + typedef nsIFrame::ComputeSizeFlags ComputeSizeFlags; + ComputeSizeFlags computeSizeFlags = + isBlock ? ComputeSizeFlags::eDefault : ComputeSizeFlags::eShrinkWrap; // Make sure legend frames with display:block and width:auto still // shrink-wrap. @@ -2126,17 +2130,20 @@ nsHTMLReflowState::InitConstraints(nsPresContext* aPresContext, frame->StyleContext()->GetPseudo() != nsCSSAnonBoxes::scrolledContent) || (aFrameType == nsGkAtoms::scrollFrame && frame->GetContentInsertionFrame()->GetType() == nsGkAtoms::legendFrame))) { - computeSizeFlags |= nsIFrame::eShrinkWrap; + computeSizeFlags = + ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap); } const nsFlexContainerFrame* flexContainerFrame = GetFlexContainer(frame); if (flexContainerFrame) { - computeSizeFlags |= nsIFrame::eShrinkWrap; + computeSizeFlags = + ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap); // If we're inside of a flex container that needs to measure our // auto height, pass that information along to ComputeSize(). if (mFlags.mIsFlexContainerMeasuringHeight) { - computeSizeFlags |= nsIFrame::eUseAutoHeight; + computeSizeFlags = + ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eUseAutoHeight); } } else { MOZ_ASSERT(!mFlags.mIsFlexContainerMeasuringHeight, diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 3bf6d18d68b3..f76fc07f141d 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -1634,7 +1634,8 @@ public: /** * Bit-flags to pass to ComputeSize in |aFlags| parameter. */ - enum { + enum ComputeSizeFlags { + eDefault = 0, /* Set if the frame is in a context where non-replaced blocks should * shrink-wrap (e.g., it's floating, absolutely positioned, or * inline-block). */ @@ -1693,7 +1694,7 @@ public: const mozilla::LogicalSize& aMargin, const mozilla::LogicalSize& aBorder, const mozilla::LogicalSize& aPadding, - uint32_t aFlags) = 0; + ComputeSizeFlags aFlags) = 0; /** * Compute a tight bounding rectangle for the frame. This is a rectangle diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 153fceb3e57d..96f97bf4f27d 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -773,7 +773,7 @@ nsImageFrame::ComputeSize(nsRenderingContext *aRenderingContext, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, - uint32_t aFlags) + ComputeSizeFlags aFlags) { EnsureIntrinsicSizeAndRatio(); diff --git a/layout/generic/nsImageFrame.h b/layout/generic/nsImageFrame.h index 2b1299498b2b..9eb1eb1ca3dd 100644 --- a/layout/generic/nsImageFrame.h +++ b/layout/generic/nsImageFrame.h @@ -184,7 +184,7 @@ protected: const mozilla::LogicalSize& aMargin, const mozilla::LogicalSize& aBorder, const mozilla::LogicalSize& aPadding, - uint32_t aFlags) MOZ_OVERRIDE; + ComputeSizeFlags aFlags) MOZ_OVERRIDE; bool IsServerImageMap(); diff --git a/layout/generic/nsInlineFrame.cpp b/layout/generic/nsInlineFrame.cpp index 425262877438..3e31510b4f1e 100644 --- a/layout/generic/nsInlineFrame.cpp +++ b/layout/generic/nsInlineFrame.cpp @@ -233,7 +233,7 @@ nsInlineFrame::ComputeSize(nsRenderingContext *aRenderingContext, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, - uint32_t aFlags) + ComputeSizeFlags aFlags) { // Inlines and text don't compute size before reflow. return LogicalSize(aWM, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); diff --git a/layout/generic/nsInlineFrame.h b/layout/generic/nsInlineFrame.h index 5d19be72fd81..fd59f28a3e91 100644 --- a/layout/generic/nsInlineFrame.h +++ b/layout/generic/nsInlineFrame.h @@ -78,7 +78,7 @@ public: const mozilla::LogicalSize& aMargin, const mozilla::LogicalSize& aBorder, const mozilla::LogicalSize& aPadding, - uint32_t aFlags) MOZ_OVERRIDE; + ComputeSizeFlags aFlags) MOZ_OVERRIDE; virtual nsRect ComputeTightBounds(gfxContext* aContext) const MOZ_OVERRIDE; virtual void Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp index cacf3d895042..2d242fe95bcd 100644 --- a/layout/generic/nsSubDocumentFrame.cpp +++ b/layout/generic/nsSubDocumentFrame.cpp @@ -712,7 +712,7 @@ nsSubDocumentFrame::ComputeSize(nsRenderingContext *aRenderingContext, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, - uint32_t aFlags) + ComputeSizeFlags aFlags) { nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame(); if (subDocRoot) { diff --git a/layout/generic/nsSubDocumentFrame.h b/layout/generic/nsSubDocumentFrame.h index da1c10b82454..c4414a32e6ca 100644 --- a/layout/generic/nsSubDocumentFrame.h +++ b/layout/generic/nsSubDocumentFrame.h @@ -69,7 +69,7 @@ public: const mozilla::LogicalSize& aMargin, const mozilla::LogicalSize& aBorder, const mozilla::LogicalSize& aPadding, - uint32_t aFlags) MOZ_OVERRIDE; + ComputeSizeFlags aFlags) MOZ_OVERRIDE; virtual void Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 35903ac26947..aac55f276729 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -7553,7 +7553,7 @@ nsTextFrame::ComputeSize(nsRenderingContext *aRenderingContext, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, - uint32_t aFlags) + ComputeSizeFlags aFlags) { // Inlines and text don't compute size before reflow. return LogicalSize(aWM, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index fb9ffb46bcaa..16c0560dbc9b 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -218,7 +218,7 @@ public: const mozilla::LogicalSize& aMargin, const mozilla::LogicalSize& aBorder, const mozilla::LogicalSize& aPadding, - uint32_t aFlags) MOZ_OVERRIDE; + ComputeSizeFlags aFlags) MOZ_OVERRIDE; virtual nsRect ComputeTightBounds(gfxContext* aContext) const MOZ_OVERRIDE; virtual nsresult GetPrefWidthTightBounds(nsRenderingContext* aContext, nscoord* aX, diff --git a/layout/generic/nsVideoFrame.cpp b/layout/generic/nsVideoFrame.cpp index 88ca14bc90ba..06e6a767d2a6 100644 --- a/layout/generic/nsVideoFrame.cpp +++ b/layout/generic/nsVideoFrame.cpp @@ -489,7 +489,7 @@ nsVideoFrame::ComputeSize(nsRenderingContext *aRenderingContext, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, - uint32_t aFlags) + ComputeSizeFlags aFlags) { nsSize size = GetVideoIntrinsicSize(aRenderingContext); diff --git a/layout/generic/nsVideoFrame.h b/layout/generic/nsVideoFrame.h index 707713bfdbe0..22e53e3ed8f9 100644 --- a/layout/generic/nsVideoFrame.h +++ b/layout/generic/nsVideoFrame.h @@ -58,7 +58,7 @@ public: const mozilla::LogicalSize& aMargin, const mozilla::LogicalSize& aBorder, const mozilla::LogicalSize& aPadding, - uint32_t aFlags) MOZ_OVERRIDE; + ComputeSizeFlags aFlags) MOZ_OVERRIDE; virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; diff --git a/layout/svg/nsSVGOuterSVGFrame.cpp b/layout/svg/nsSVGOuterSVGFrame.cpp index b9298167be61..c4a25a2b5733 100644 --- a/layout/svg/nsSVGOuterSVGFrame.cpp +++ b/layout/svg/nsSVGOuterSVGFrame.cpp @@ -271,7 +271,7 @@ nsSVGOuterSVGFrame::ComputeSize(nsRenderingContext *aRenderingContext, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, - uint32_t aFlags) + ComputeSizeFlags aFlags) { if (IsRootOfImage() || IsRootOfReplacedElementSubDoc()) { // The embedding element has sized itself using the CSS replaced element diff --git a/layout/svg/nsSVGOuterSVGFrame.h b/layout/svg/nsSVGOuterSVGFrame.h index 07203c54674d..a77577cd54a8 100644 --- a/layout/svg/nsSVGOuterSVGFrame.h +++ b/layout/svg/nsSVGOuterSVGFrame.h @@ -53,7 +53,7 @@ public: const mozilla::LogicalSize& aMargin, const mozilla::LogicalSize& aBorder, const mozilla::LogicalSize& aPadding, - uint32_t aFlags) MOZ_OVERRIDE; + ComputeSizeFlags aFlags) MOZ_OVERRIDE; virtual void Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 74e563c22c9c..9e56b22cf862 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -1562,7 +1562,7 @@ nsTableFrame::ComputeSize(nsRenderingContext *aRenderingContext, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, - uint32_t aFlags) + ComputeSizeFlags aFlags) { LogicalSize result = nsContainerFrame::ComputeSize(aRenderingContext, aWM, diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index da918d32d8a5..62562501efd6 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -311,7 +311,7 @@ public: const mozilla::LogicalSize& aMargin, const mozilla::LogicalSize& aBorder, const mozilla::LogicalSize& aPadding, - uint32_t aFlags) MOZ_OVERRIDE; + ComputeSizeFlags aFlags) MOZ_OVERRIDE; virtual mozilla::LogicalSize ComputeAutoSize(nsRenderingContext *aRenderingContext, diff --git a/layout/tables/nsTableOuterFrame.cpp b/layout/tables/nsTableOuterFrame.cpp index 4cb29163a285..271da76ff930 100644 --- a/layout/tables/nsTableOuterFrame.cpp +++ b/layout/tables/nsTableOuterFrame.cpp @@ -493,7 +493,7 @@ ChildShrinkWrapWidth(nsRenderingContext *aRenderingContext, offsets.ComputedLogicalBorderPadding().Size(wm) - offsets.ComputedLogicalPadding().Size(wm), offsets.ComputedLogicalPadding().Size(wm), - true); + nsIFrame::ComputeSizeFlags::eShrinkWrap); if (aMarginResult) *aMarginResult = offsets.ComputedLogicalMargin().IStartEnd(wm); return size.ISize(wm) + offsets.ComputedLogicalMargin().IStartEnd(wm) + From a274c19e07ff4354965a8c2d6c6e924a1ceaaa6d Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 11 Nov 2014 11:02:43 +0000 Subject: [PATCH 05/47] Bug 1085051 - Fix mismatched new[]/delete in DrawTargetCG::FillGlyphs. r=jrmuizel --- gfx/2d/DrawTargetCG.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gfx/2d/DrawTargetCG.cpp b/gfx/2d/DrawTargetCG.cpp index 35c30f2a5242..6982ae8248b4 100644 --- a/gfx/2d/DrawTargetCG.cpp +++ b/gfx/2d/DrawTargetCG.cpp @@ -1270,7 +1270,7 @@ DrawTargetCG::FillGlyphs(ScaledFont *aFont, const GlyphBuffer &aBuffer, const Pa extents = ComputeGlyphsExtents(bboxes, &positions.front(), aBuffer.mNumGlyphs, 1.0f); ScaledFontMac::CTFontDrawGlyphsPtr(macFont->mCTFont, &glyphs.front(), &positions.front(), aBuffer.mNumGlyphs, cg); - delete bboxes; + delete[] bboxes; } else { CGRect *bboxes = new CGRect[aBuffer.mNumGlyphs]; CGFontGetGlyphBBoxes(macFont->mFont, &glyphs.front(), aBuffer.mNumGlyphs, bboxes); @@ -1280,7 +1280,7 @@ DrawTargetCG::FillGlyphs(ScaledFont *aFont, const GlyphBuffer &aBuffer, const Pa CGContextSetFontSize(cg, macFont->mSize); CGContextShowGlyphsAtPositions(cg, &glyphs.front(), &positions.front(), aBuffer.mNumGlyphs); - delete bboxes; + delete[] bboxes; } CGContextScaleCTM(cg, 1, -1); DrawGradient(mColorSpace, cg, aPattern, extents); From 94e739f695c59d460fb530154f6ca2f58ceb234c Mon Sep 17 00:00:00 2001 From: David Burns Date: Mon, 10 Nov 2014 16:47:23 +0000 Subject: [PATCH 06/47] Bug 1073732: Allow Marionette to have sessions ids that are unique for that session; r=jgriffin The string is an opaque string(uuid) that uniquely identifies the session. It gives us webdriver compability and we can use it to set sessions if we are doing restarts --HG-- extra : rebase_source : e2d59e16a82d431da4a445f9890433353a6ac7f7 --- testing/marionette/client/marionette/marionette.py | 14 +++++++++----- .../client/marionette/tests/unit/test_session.py | 12 ++++++++++++ testing/marionette/marionette-server.js | 12 +++++++++++- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/testing/marionette/client/marionette/marionette.py b/testing/marionette/client/marionette/marionette.py index d1b71c61b142..48a764381b71 100644 --- a/testing/marionette/client/marionette/marionette.py +++ b/testing/marionette/client/marionette/marionette.py @@ -479,6 +479,7 @@ class Marionette(object): self.bin = bin self.instance = None self.session = None + self.session_id = None self.window = None self.runner = None self.emulator = None @@ -607,12 +608,12 @@ class Marionette(object): @do_crash_check def _send_message(self, command, response_key="ok", **kwargs): - if not self.session and command != "newSession": + if not self.session_id and command != "newSession": raise errors.MarionetteException("Please start a session") message = {"name": command} - if self.session: - message["sessionId"] = self.session + if self.session_id: + message["sessionId"] = self.session_id if kwargs: message["parameters"] = kwargs @@ -637,6 +638,8 @@ class Marionette(object): continue; break; + if not self.session_id: + self.session_id = response.get("sessionId", None) if response_key in response: return response[response_key] @@ -811,7 +814,7 @@ class Marionette(object): ''' return "%s%s" % (self.baseurl, relative_url) - def start_session(self, desired_capabilities=None): + def start_session(self, session_id=None, desired_capabilities=None): """Create a new Marionette session. This method must be called before performing any other action. @@ -820,7 +823,7 @@ class Marionette(object): capabilities. This is currently ignored. :returns: A dict of the capabilities offered.""" - self.session = self._send_message('newSession', 'value', capabilities=desired_capabilities) + self.session = self._send_message('newSession', 'value', capabilities=desired_capabilities, session_id=session_id) self.b2g = 'b2g' in self.session return self.session @@ -836,6 +839,7 @@ class Marionette(object): def delete_session(self): """Close the current session and disconnect from the server.""" response = self._send_message('deleteSession', 'ok') + self.session_id = None self.session = None self.window = None self.client.close() diff --git a/testing/marionette/client/marionette/tests/unit/test_session.py b/testing/marionette/client/marionette/tests/unit/test_session.py index 16eec76d3a59..6ef600e48821 100644 --- a/testing/marionette/client/marionette/tests/unit/test_session.py +++ b/testing/marionette/client/marionette/tests/unit/test_session.py @@ -29,4 +29,16 @@ class TestSession(marionette_test.MarionetteTestCase): self.assertIn("takesScreenshot", caps) self.assertIn("version", caps) + def test_we_can_get_the_session_id(self): + # Sends newSession + caps = self.marionette.start_session() + self.assertTrue(self.marionette.session_id is not None) + self.assertTrue(isinstance(self.marionette.session_id, unicode)) + + def test_we_can_set_the_session_id(self): + # Sends newSession + caps = self.marionette.start_session(session_id="ILoveCheese") + + self.assertEqual(self.marionette.session_id, "ILoveCheese") + self.assertTrue(isinstance(self.marionette.session_id, unicode)) \ No newline at end of file diff --git a/testing/marionette/marionette-server.js b/testing/marionette/marionette-server.js index 810b7f3c7fdd..3279b7485bd6 100644 --- a/testing/marionette/marionette-server.js +++ b/testing/marionette/marionette-server.js @@ -127,6 +127,7 @@ function MarionetteServerConnection(aPrefix, aTransport, aServer) // passing back "actor ids" with responses. unlike the debugger server, // we don't have multiple actors, so just use a dummy value of "0" here this.actorID = "0"; + this.sessionId = null; this.globalMessageManager = Cc["@mozilla.org/globalmessagemanager;1"] .getService(Ci.nsIMessageBroadcaster); @@ -330,7 +331,9 @@ MarionetteServerConnection.prototype = { sendResponse: function MDA_sendResponse(value, command_id) { if (typeof(value) == 'undefined') value = null; - this.sendToClient({from:this.actorID, value: value}, command_id); + this.sendToClient({from:this.actorID, + sessionId: this.sessionId, + value: value}, command_id); }, sayHello: function MDA_sayHello() { @@ -553,6 +556,8 @@ MarionetteServerConnection.prototype = { this.scriptTimeout = 10000; if (aRequest && aRequest.parameters) { + this.sessionId = aRequest.parameters.session_id ? aRequest.parameters.session_id : null; + logger.info("Session Id is set to: " + this.sessionId); this.setSessionCapabilities(aRequest.parameters.capabilities); } @@ -625,6 +630,10 @@ MarionetteServerConnection.prototype = { getSessionCapabilities: function MDA_getSessionCapabilities() { this.command_id = this.getCommandId(); + if (!this.sessionId) { + this.sessionId = this.uuidGen.generateUUID().toString(); + } + // eideticker (bug 965297) and mochitest (bug 965304) // compatibility. They only check for the presence of this // property and should so not be in caps if not on a B2G device. @@ -2277,6 +2286,7 @@ MarionetteServerConnection.prototype = { if (this.mainFrame) { this.mainFrame.focus(); } + this.sessionId = null; this.deleteFile('marionetteChromeScripts'); this.deleteFile('marionetteContentScripts'); }, From 115ea308705d971f6036f0b17c936f54616037e1 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Tue, 11 Nov 2014 00:38:28 +0200 Subject: [PATCH 07/47] Bug 1096076 - [E10s] When resizing a window, all the tabs are resized, r=roc --- layout/base/nsPresShell.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 8e8cc0870649..ac8193b28937 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -8832,7 +8832,7 @@ PresShell::IsVisible() // inner view of subdoc frame view = view->GetParent(); if (!view) - return true; + return mIsActive; // subdoc view view = view->GetParent(); From 90482773b297baeb2a8ec72e58244ed1358d37ef Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Tue, 11 Nov 2014 13:40:45 +0200 Subject: [PATCH 08/47] Bug 1096263 - XMLHttpRequest.send({}) should not throw, r=bz --- dom/base/nsXMLHttpRequest.h | 35 +++++++++++++++++++++++++---------- dom/bindings/Bindings.conf | 2 +- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/dom/base/nsXMLHttpRequest.h b/dom/base/nsXMLHttpRequest.h index b4860b71f93a..a0628527b406 100644 --- a/dom/base/nsXMLHttpRequest.h +++ b/dom/base/nsXMLHttpRequest.h @@ -427,46 +427,61 @@ private: bool IsDeniedCrossSiteRequest(); public: - void Send(ErrorResult& aRv) + void Send(JSContext* /*aCx*/, ErrorResult& aRv) { aRv = Send(Nullable()); } - void Send(const mozilla::dom::ArrayBuffer& aArrayBuffer, ErrorResult& aRv) + void Send(JSContext* /*aCx*/, + const mozilla::dom::ArrayBuffer& aArrayBuffer, + ErrorResult& aRv) { aRv = Send(RequestBody(&aArrayBuffer)); } - void Send(const mozilla::dom::ArrayBufferView& aArrayBufferView, + void Send(JSContext* /*aCx*/, + const mozilla::dom::ArrayBufferView& aArrayBufferView, ErrorResult& aRv) { aRv = Send(RequestBody(&aArrayBufferView)); } - void Send(mozilla::dom::File& aBlob, ErrorResult& aRv) + void Send(JSContext* /*aCx*/, mozilla::dom::File& aBlob, ErrorResult& aRv) { aRv = Send(RequestBody(aBlob)); } - void Send(nsIDocument& aDoc, ErrorResult& aRv) + void Send(JSContext* /*aCx*/, nsIDocument& aDoc, ErrorResult& aRv) { aRv = Send(RequestBody(&aDoc)); } - void Send(const nsAString& aString, ErrorResult& aRv) + void Send(JSContext* aCx, const nsAString& aString, ErrorResult& aRv) { if (DOMStringIsNull(aString)) { - Send(aRv); + Send(aCx, aRv); } else { aRv = Send(RequestBody(aString)); } } - void Send(nsFormData& aFormData, ErrorResult& aRv) + void Send(JSContext* /*aCx*/, nsFormData& aFormData, ErrorResult& aRv) { aRv = Send(RequestBody(aFormData)); } - void Send(nsIInputStream* aStream, ErrorResult& aRv) + void Send(JSContext* aCx, nsIInputStream* aStream, ErrorResult& aRv) { NS_ASSERTION(aStream, "Null should go to string version"); nsCOMPtr wjs = do_QueryInterface(aStream); if (wjs) { - aRv.Throw(NS_ERROR_DOM_TYPE_ERR); + JSObject* data = wjs->GetJSObject(); + if (!data) { + aRv.Throw(NS_ERROR_DOM_TYPE_ERR); + return; + } + JS::Rooted dataAsValue(aCx, JS::ObjectValue(*data)); + nsAutoString dataAsString; + if (ConvertJSValueToString(aCx, dataAsValue, mozilla::dom::eNull, + mozilla::dom::eNull, dataAsString)) { + Send(aCx, dataAsString, aRv); + } else { + aRv.Throw(NS_ERROR_FAILURE); + } return; } aRv = Send(RequestBody(aStream)); diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index 33b4ea85d9e4..3336922c6b4c 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -1551,7 +1551,7 @@ DOMInterfaces = { 'XMLHttpRequest': [ { 'nativeType': 'nsXMLHttpRequest', - 'implicitJSContext': [ 'constructor', ], + 'implicitJSContext': [ 'constructor', 'send'], }, { 'workers': True, From 52b9b1f74d8d3fc6de4b20797cd1856a14ceac29 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Tue, 11 Nov 2014 13:41:20 +0200 Subject: [PATCH 09/47] Bug 1096263 - XMLHttpRequest.send({}) should not throw, tests, r=bz --- dom/base/test/echo.sjs | 21 ++++++++ dom/base/test/mochitest.ini | 2 + dom/base/test/test_xhr_send.html | 83 ++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 dom/base/test/echo.sjs create mode 100644 dom/base/test/test_xhr_send.html diff --git a/dom/base/test/echo.sjs b/dom/base/test/echo.sjs new file mode 100644 index 000000000000..6e3242c9f72e --- /dev/null +++ b/dom/base/test/echo.sjs @@ -0,0 +1,21 @@ +const CC = Components.Constructor; +const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1", + "nsIBinaryInputStream", + "setInputStream"); + +function handleRequest(request, response) +{ + response.setHeader("Content-Type", "text/plain"); + if (request.method == "GET") { + response.write(request.queryString); + return; + } + + var bodyStream = new BinaryInputStream(request.bodyInputStream); + var body = ""; + var bodyAvail; + while ((bodyAvail = bodyStream.available()) > 0) + body += String.fromCharCode.apply(null, bodyStream.readByteArray(bodyAvail)); + + response.write(body); +} diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index 383e987a9261..79b75df1063a 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -56,6 +56,7 @@ support-files = bug819051.sjs copypaste.js delayedServerEvents.sjs + echo.sjs eventsource.resource eventsource.resource^headers^ eventsource_redirect.resource @@ -739,6 +740,7 @@ skip-if = toolkit == 'android' [test_xhr_forbidden_headers.html] [test_xhr_progressevents.html] skip-if = toolkit == 'android' +[test_xhr_send.html] [test_xhr_send_readystate.html] [test_xhr_withCredentials.html] [test_file_from_blob.html] diff --git a/dom/base/test/test_xhr_send.html b/dom/base/test/test_xhr_send.html new file mode 100644 index 000000000000..7d8e1bae8483 --- /dev/null +++ b/dom/base/test/test_xhr_send.html @@ -0,0 +1,83 @@ + + + + + + Test for Bug 1096263 + + + + + +Mozilla Bug 1096263 +

+
+ +
+
+
+ + From 4df4b9674d281ca672e90e3f4574c3d15406f86b Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Tue, 11 Nov 2014 13:51:22 +0100 Subject: [PATCH 10/47] Backed out changeset 5548373ee88b (bug 1073732) for marionette test failures on a CLOSED TREE --- testing/marionette/client/marionette/marionette.py | 14 +++++--------- .../client/marionette/tests/unit/test_session.py | 12 ------------ testing/marionette/marionette-server.js | 12 +----------- 3 files changed, 6 insertions(+), 32 deletions(-) diff --git a/testing/marionette/client/marionette/marionette.py b/testing/marionette/client/marionette/marionette.py index 48a764381b71..d1b71c61b142 100644 --- a/testing/marionette/client/marionette/marionette.py +++ b/testing/marionette/client/marionette/marionette.py @@ -479,7 +479,6 @@ class Marionette(object): self.bin = bin self.instance = None self.session = None - self.session_id = None self.window = None self.runner = None self.emulator = None @@ -608,12 +607,12 @@ class Marionette(object): @do_crash_check def _send_message(self, command, response_key="ok", **kwargs): - if not self.session_id and command != "newSession": + if not self.session and command != "newSession": raise errors.MarionetteException("Please start a session") message = {"name": command} - if self.session_id: - message["sessionId"] = self.session_id + if self.session: + message["sessionId"] = self.session if kwargs: message["parameters"] = kwargs @@ -638,8 +637,6 @@ class Marionette(object): continue; break; - if not self.session_id: - self.session_id = response.get("sessionId", None) if response_key in response: return response[response_key] @@ -814,7 +811,7 @@ class Marionette(object): ''' return "%s%s" % (self.baseurl, relative_url) - def start_session(self, session_id=None, desired_capabilities=None): + def start_session(self, desired_capabilities=None): """Create a new Marionette session. This method must be called before performing any other action. @@ -823,7 +820,7 @@ class Marionette(object): capabilities. This is currently ignored. :returns: A dict of the capabilities offered.""" - self.session = self._send_message('newSession', 'value', capabilities=desired_capabilities, session_id=session_id) + self.session = self._send_message('newSession', 'value', capabilities=desired_capabilities) self.b2g = 'b2g' in self.session return self.session @@ -839,7 +836,6 @@ class Marionette(object): def delete_session(self): """Close the current session and disconnect from the server.""" response = self._send_message('deleteSession', 'ok') - self.session_id = None self.session = None self.window = None self.client.close() diff --git a/testing/marionette/client/marionette/tests/unit/test_session.py b/testing/marionette/client/marionette/tests/unit/test_session.py index 6ef600e48821..16eec76d3a59 100644 --- a/testing/marionette/client/marionette/tests/unit/test_session.py +++ b/testing/marionette/client/marionette/tests/unit/test_session.py @@ -29,16 +29,4 @@ class TestSession(marionette_test.MarionetteTestCase): self.assertIn("takesScreenshot", caps) self.assertIn("version", caps) - def test_we_can_get_the_session_id(self): - # Sends newSession - caps = self.marionette.start_session() - self.assertTrue(self.marionette.session_id is not None) - self.assertTrue(isinstance(self.marionette.session_id, unicode)) - - def test_we_can_set_the_session_id(self): - # Sends newSession - caps = self.marionette.start_session(session_id="ILoveCheese") - - self.assertEqual(self.marionette.session_id, "ILoveCheese") - self.assertTrue(isinstance(self.marionette.session_id, unicode)) \ No newline at end of file diff --git a/testing/marionette/marionette-server.js b/testing/marionette/marionette-server.js index 3279b7485bd6..810b7f3c7fdd 100644 --- a/testing/marionette/marionette-server.js +++ b/testing/marionette/marionette-server.js @@ -127,7 +127,6 @@ function MarionetteServerConnection(aPrefix, aTransport, aServer) // passing back "actor ids" with responses. unlike the debugger server, // we don't have multiple actors, so just use a dummy value of "0" here this.actorID = "0"; - this.sessionId = null; this.globalMessageManager = Cc["@mozilla.org/globalmessagemanager;1"] .getService(Ci.nsIMessageBroadcaster); @@ -331,9 +330,7 @@ MarionetteServerConnection.prototype = { sendResponse: function MDA_sendResponse(value, command_id) { if (typeof(value) == 'undefined') value = null; - this.sendToClient({from:this.actorID, - sessionId: this.sessionId, - value: value}, command_id); + this.sendToClient({from:this.actorID, value: value}, command_id); }, sayHello: function MDA_sayHello() { @@ -556,8 +553,6 @@ MarionetteServerConnection.prototype = { this.scriptTimeout = 10000; if (aRequest && aRequest.parameters) { - this.sessionId = aRequest.parameters.session_id ? aRequest.parameters.session_id : null; - logger.info("Session Id is set to: " + this.sessionId); this.setSessionCapabilities(aRequest.parameters.capabilities); } @@ -630,10 +625,6 @@ MarionetteServerConnection.prototype = { getSessionCapabilities: function MDA_getSessionCapabilities() { this.command_id = this.getCommandId(); - if (!this.sessionId) { - this.sessionId = this.uuidGen.generateUUID().toString(); - } - // eideticker (bug 965297) and mochitest (bug 965304) // compatibility. They only check for the presence of this // property and should so not be in caps if not on a B2G device. @@ -2286,7 +2277,6 @@ MarionetteServerConnection.prototype = { if (this.mainFrame) { this.mainFrame.focus(); } - this.sessionId = null; this.deleteFile('marionetteChromeScripts'); this.deleteFile('marionetteContentScripts'); }, From cd70429f27fd8113edbcebd6dbb7430f97e16ca2 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Tue, 11 Nov 2014 15:01:20 +0200 Subject: [PATCH 11/47] Bug 1096263, we pass now this XHR wp test, CLOSED TREE, r=sheriff --- .../meta/XMLHttpRequest/send-entity-body-basic.htm.ini | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 testing/web-platform/meta/XMLHttpRequest/send-entity-body-basic.htm.ini diff --git a/testing/web-platform/meta/XMLHttpRequest/send-entity-body-basic.htm.ini b/testing/web-platform/meta/XMLHttpRequest/send-entity-body-basic.htm.ini deleted file mode 100644 index 00ca3d02a9d1..000000000000 --- a/testing/web-platform/meta/XMLHttpRequest/send-entity-body-basic.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[send-entity-body-basic.htm] - type: testharness - [XMLHttpRequest: send() - data argument (2,2)] - expected: FAIL - From 41cf2228a541816ef7d7e6973ca8c3fe8b9ac5c1 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Tue, 11 Nov 2014 15:12:24 +0100 Subject: [PATCH 12/47] Bug 1093573 part 4 - Add yield index to YIELD ops. r=wingo --- js/src/frontend/BytecodeEmitter.cpp | 31 ++++++++++++++++++++++++---- js/src/frontend/BytecodeEmitter.h | 2 ++ js/src/js.msg | 1 + js/src/jsopcode.cpp | 3 +-- js/src/vm/GeneratorObject.cpp | 24 +++++++++++++++++++--- js/src/vm/GeneratorObject.h | 32 ++++++++++++++++++++++------- js/src/vm/Interpreter.cpp | 4 ++-- js/src/vm/Opcodes.h | 8 ++++---- js/src/vm/Xdr.h | 2 +- 9 files changed, 84 insertions(+), 23 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 804e0f3c85c3..3ee0d1bc755a 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -133,6 +133,7 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent, firstLine(lineNum), localsToFrameSlots_(sc->context), stackDepth(0), maxStackDepth(0), + yieldIndex(0), arrayCompDepth(0), emitLevel(0), constList(sc->context), @@ -2999,6 +3000,28 @@ BytecodeEmitter::isRunOnceLambda() !funbox->function()->name(); } +static bool +EmitYieldOp(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op) +{ + if (op == JSOP_FINALYIELDRVAL) + return Emit1(cx, bce, JSOP_FINALYIELDRVAL) >= 0; + + MOZ_ASSERT(op == JSOP_INITIALYIELD || op == JSOP_YIELD); + + ptrdiff_t off = EmitN(cx, bce, op, 3); + if (off < 0) + return false; + + if (bce->yieldIndex >= JS_BIT(24)) { + bce->reportError(nullptr, JSMSG_TOO_MANY_YIELDS); + return false; + } + + SET_UINT24(bce->code(off), bce->yieldIndex); + bce->yieldIndex++; + return true; +} + bool frontend::EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *body) { @@ -3074,7 +3097,7 @@ frontend::EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNo return false; // No need to check for finally blocks, etc as in EmitReturn. - if (Emit1(cx, bce, JSOP_FINALYIELDRVAL) < 0) + if (!EmitYieldOp(cx, bce, JSOP_FINALYIELDRVAL)) return false; } @@ -5559,7 +5582,7 @@ EmitReturn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) MOZ_ALWAYS_TRUE(LookupAliasedNameSlot(bce, bce->script, cx->names().dotGenerator, &sc)); if (!EmitAliasedVarOp(cx, JSOP_GETALIASEDVAR, sc, DontCheckLexical, bce)) return false; - if (Emit1(cx, bce, JSOP_FINALYIELDRVAL) < 0) + if (!EmitYieldOp(cx, bce, JSOP_FINALYIELDRVAL)) return false; } else if (top + static_cast(JSOP_RETURN_LENGTH) != bce->offset()) { bce->code()[top] = JSOP_SETRVAL; @@ -5598,7 +5621,7 @@ EmitYield(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) if (!EmitTree(cx, bce, pn->pn_right)) return false; - if (Emit1(cx, bce, pn->getOp()) < 0) + if (!EmitYieldOp(cx, bce, pn->getOp())) return false; if (pn->getOp() == JSOP_INITIALYIELD && Emit1(cx, bce, JSOP_POP) < 0) @@ -5643,7 +5666,7 @@ EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter, Parse return false; // Yield RESULT as-is, without re-boxing. - if (Emit1(cx, bce, JSOP_YIELD) < 0) // ITER RECEIVED + if (!EmitYieldOp(cx, bce, JSOP_YIELD)) // ITER RECEIVED return false; // Try epilogue. diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index ccc775404b8d..0043da13a5b2 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -126,6 +126,8 @@ struct BytecodeEmitter int32_t stackDepth; /* current stack depth in script frame */ uint32_t maxStackDepth; /* maximum stack depth so far */ + uint32_t yieldIndex; /* index stored as operand of yield ops */ + uint32_t arrayCompDepth; /* stack depth of array in comprehension */ unsigned emitLevel; /* js::frontend::EmitTree recursion level */ diff --git a/js/src/js.msg b/js/src/js.msg index abb167d27405..cb313742837f 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -303,6 +303,7 @@ MSG_DEF(JSMSG_TOO_MANY_CON_ARGS, 0, JSEXN_SYNTAXERR, "too many constructor MSG_DEF(JSMSG_TOO_MANY_DEFAULTS, 0, JSEXN_SYNTAXERR, "more than one switch default") MSG_DEF(JSMSG_TOO_MANY_FUN_ARGS, 0, JSEXN_SYNTAXERR, "too many function arguments") MSG_DEF(JSMSG_TOO_MANY_LOCALS, 0, JSEXN_SYNTAXERR, "too many local variables") +MSG_DEF(JSMSG_TOO_MANY_YIELDS, 0, JSEXN_SYNTAXERR, "too many yield expressions") MSG_DEF(JSMSG_TOUGH_BREAK, 0, JSEXN_SYNTAXERR, "unlabeled break must be inside loop or switch") MSG_DEF(JSMSG_UNEXPECTED_TOKEN, 2, JSEXN_SYNTAXERR, "expected {0}, got {1}") MSG_DEF(JSMSG_UNNAMED_FUNCTION_STMT, 0, JSEXN_SYNTAXERR, "function statement requires a name") diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 0b93fce23072..66e14fb6936f 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -1067,8 +1067,7 @@ js_Disassemble1(JSContext *cx, HandleScript script, jsbytecode *pc, goto print_int; case JOF_UINT24: - MOZ_ASSERT(op == JSOP_UINT24 || op == JSOP_NEWARRAY || op == JSOP_INITELEM_ARRAY || - op == JSOP_DUPAT); + MOZ_ASSERT(len == 4); i = (int)GET_UINT24(pc); goto print_int; diff --git a/js/src/vm/GeneratorObject.cpp b/js/src/vm/GeneratorObject.cpp index dc27855d196f..4b65ac0f1014 100644 --- a/js/src/vm/GeneratorObject.cpp +++ b/js/src/vm/GeneratorObject.cpp @@ -60,19 +60,28 @@ GeneratorObject::create(JSContext *cx, AbstractFramePtr frame) bool GeneratorObject::suspend(JSContext *cx, HandleObject obj, AbstractFramePtr frame, jsbytecode *pc, - Value *vp, unsigned nvalues, GeneratorObject::SuspendKind suspendKind) + Value *vp, unsigned nvalues) { + MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD); + Rooted genObj(cx, &obj->as()); MOZ_ASSERT(!genObj->hasExpressionStack()); - if (suspendKind == NORMAL && genObj->isClosing()) { + if (*pc == JSOP_YIELD && genObj->isClosing()) { MOZ_ASSERT(genObj->is()); RootedValue val(cx, ObjectValue(*frame.callee())); js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, JSDVG_SEARCH_STACK, val, NullPtr()); return false; } - genObj->setSuspendedBytecodeOffset(pc - frame.script()->code(), suspendKind == INITIAL); + uint32_t yieldIndex = GET_UINT24(pc); + MOZ_ASSERT((*pc == JSOP_INITIALYIELD) == (yieldIndex == 0)); + + static_assert(JSOP_INITIALYIELD_LENGTH == JSOP_YIELD_LENGTH, + "code below assumes INITIALYIELD and YIELD have same length"); + pc += JSOP_YIELD_LENGTH; + + genObj->setSuspendedBytecodeOffset(frame.script()->pcToOffset(pc), yieldIndex); genObj->setScopeChain(*frame.scopeChain()); if (nvalues) { @@ -128,6 +137,15 @@ GeneratorObject::resume(JSContext *cx, InterpreterActivation &activation, activation.regs().pc = callee->nonLazyScript()->code() + genObj->suspendedBytecodeOffset(); +#ifdef DEBUG + // Verify the YIELD_INDEX slot holds the right value. + static_assert(JSOP_INITIALYIELD_LENGTH == JSOP_YIELD_LENGTH, + "code below assumes INITIALYIELD and YIELD have same length"); + jsbytecode *yieldpc = activation.regs().pc - JSOP_YIELD_LENGTH; + MOZ_ASSERT(*yieldpc == JSOP_INITIALYIELD || *yieldpc == JSOP_YIELD); + MOZ_ASSERT(GET_UINT24(yieldpc) == genObj->suspendedYieldIndex()); +#endif + // Always push on a value, even if we are raising an exception. In the // exception case, the stack needs to have something on it so that exception // handling doesn't skip the catch blocks. See TryNoteIter::settle. diff --git a/js/src/vm/GeneratorObject.h b/js/src/vm/GeneratorObject.h index e134591ceb3f..f8af42fe6324 100644 --- a/js/src/vm/GeneratorObject.h +++ b/js/src/vm/GeneratorObject.h @@ -28,12 +28,17 @@ class GeneratorObject : public NativeObject ARGS_OBJ_SLOT, EXPRESSION_STACK_SLOT, BYTECODE_OFFSET_SLOT, + YIELD_INDEX_SLOT, RESERVED_SLOTS }; - enum SuspendKind { INITIAL, NORMAL, FINAL }; enum ResumeKind { NEXT, THROW, CLOSE }; + private: + static bool suspend(JSContext *cx, HandleObject obj, AbstractFramePtr frame, jsbytecode *pc, + Value *vp, unsigned nvalues); + + public: static inline ResumeKind getResumeKind(jsbytecode *pc) { MOZ_ASSERT(*pc == JSOP_RESUME); unsigned arg = GET_UINT16(pc); @@ -52,19 +57,16 @@ class GeneratorObject : public NativeObject static JSObject *create(JSContext *cx, AbstractFramePtr frame); - static bool suspend(JSContext *cx, HandleObject obj, AbstractFramePtr frame, jsbytecode *pc, - Value *vp, unsigned nvalues, SuspendKind kind); - static bool resume(JSContext *cx, InterpreterActivation &activation, HandleObject obj, HandleValue arg, ResumeKind resumeKind); static bool initialSuspend(JSContext *cx, HandleObject obj, AbstractFramePtr frame, jsbytecode *pc) { - return suspend(cx, obj, frame, pc, nullptr, 0, INITIAL); + return suspend(cx, obj, frame, pc, nullptr, 0); } static bool normalSuspend(JSContext *cx, HandleObject obj, AbstractFramePtr frame, jsbytecode *pc, Value *vp, unsigned nvalues) { - return suspend(cx, obj, frame, pc, vp, nvalues, NORMAL); + return suspend(cx, obj, frame, pc, vp, nvalues); } static bool finalSuspend(JSContext *cx, HandleObject obj); @@ -149,11 +151,23 @@ class GeneratorObject : public NativeObject MOZ_ASSERT(isSuspended()); return getFixedSlot(BYTECODE_OFFSET_SLOT).toInt32() >> 1; } - void setSuspendedBytecodeOffset(ptrdiff_t offset, bool newborn) { + void setSuspendedBytecodeOffset(ptrdiff_t offset, uint32_t yieldIndex) { + bool newborn = (yieldIndex == 0); MOZ_ASSERT(newborn ? getFixedSlot(BYTECODE_OFFSET_SLOT).isUndefined() : isRunning()); MOZ_ASSERT(offset > 0 && offset < MAX_BYTECODE_OFFSET); setFixedSlot(BYTECODE_OFFSET_SLOT, Int32Value((offset << 1) | (newborn ? 0x1 : 0))); MOZ_ASSERT(isSuspended()); + MOZ_ASSERT(yieldIndex <= INT32_MAX); + setFixedSlot(YIELD_INDEX_SLOT, Int32Value(yieldIndex)); + } + + // When the generator is suspended, the yield index slot contains the yield + // index (see JSOP_INITIALYIELD/JSOP_YIELD operand) of the yield instruction + // that suspended the generator. This is only used by JIT code to lookup the + // native code address when resuming. + uint32_t suspendedYieldIndex() const { + MOZ_ASSERT(isSuspended()); + return getFixedSlot(YIELD_INDEX_SLOT).toInt32(); } bool isClosed() const { return getFixedSlot(CALLEE_SLOT).isNull(); @@ -165,6 +179,7 @@ class GeneratorObject : public NativeObject setFixedSlot(ARGS_OBJ_SLOT, NullValue()); setFixedSlot(EXPRESSION_STACK_SLOT, NullValue()); setFixedSlot(BYTECODE_OFFSET_SLOT, NullValue()); + setFixedSlot(YIELD_INDEX_SLOT, NullValue()); } static size_t offsetOfCalleeSlot() { @@ -182,6 +197,9 @@ class GeneratorObject : public NativeObject static size_t offsetOfBytecodeOffsetSlot() { return getFixedSlotOffset(BYTECODE_OFFSET_SLOT); } + static size_t offsetOfYieldIndexSlot() { + return getFixedSlotOffset(YIELD_INDEX_SLOT); + } static size_t offsetOfExpressionStackSlot() { return getFixedSlotOffset(EXPRESSION_STACK_SLOT); } diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 281f7da76711..226590c0ee9d 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -3362,7 +3362,7 @@ CASE(JSOP_INITIALYIELD) obj = ®S.sp[-1].toObject(); POP_RETURN_VALUE(); MOZ_ASSERT(REGS.stackDepth() == 0); - if (!GeneratorObject::initialSuspend(cx, obj, REGS.fp(), REGS.pc + JSOP_INITIALYIELD_LENGTH)) + if (!GeneratorObject::initialSuspend(cx, obj, REGS.fp(), REGS.pc)) goto error; goto successful_return_continuation; } @@ -3373,7 +3373,7 @@ CASE(JSOP_YIELD) MOZ_ASSERT(REGS.fp()->isNonEvalFunctionFrame()); RootedObject &obj = rootObject0; obj = ®S.sp[-1].toObject(); - if (!GeneratorObject::normalSuspend(cx, obj, REGS.fp(), REGS.pc + JSOP_YIELD_LENGTH, + if (!GeneratorObject::normalSuspend(cx, obj, REGS.fp(), REGS.pc, REGS.spForStackDepth(0), REGS.stackDepth() - 2)) { goto error; diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h index 2268b8635224..78fada9960b6 100644 --- a/js/src/vm/Opcodes.h +++ b/js/src/vm/Opcodes.h @@ -1565,19 +1565,19 @@ * interpretation. * Category: Statements * Type: Generator - * Operands: + * Operands: uint24_t yieldIndex * Stack: generator => */ \ - macro(JSOP_INITIALYIELD, 202,"initialyield", NULL, 1, 1, 1, JOF_BYTE) \ + macro(JSOP_INITIALYIELD, 202,"initialyield", NULL, 4, 1, 1, JOF_UINT24) \ /* * Pops the generator and the return value 'rval1', stops interpretation and * returns 'rval1'. Pushes sent value from 'send()' onto the stack. * Category: Statements * Type: Generator - * Operands: + * Operands: uint24_t yieldIndex * Stack: rval1, gen => rval2 */ \ - macro(JSOP_YIELD, 203,"yield", NULL, 1, 2, 1, JOF_BYTE) \ + macro(JSOP_YIELD, 203,"yield", NULL, 4, 2, 1, JOF_UINT24) \ /* * Pops the generator and suspends and closes it. Yields the value in the * frame's return value slot. diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index 47d9c755a8e3..d45bfde6576a 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -34,7 +34,7 @@ namespace js { * Nightly) and without (all others). FIXME: Bug 1066322 - Enable ES6 symbols * in all builds. */ -static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 194; +static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 196; static_assert(XDR_BYTECODE_VERSION_SUBTRAHEND % 2 == 0, "see the comment above"); static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - (XDR_BYTECODE_VERSION_SUBTRAHEND From 60aac0476601de546b25c9835c8c58d5d425deb3 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Tue, 11 Nov 2014 15:12:26 +0100 Subject: [PATCH 13/47] Bug 1093573 part 5 - Baseline-compile JSOP_GENERATOR. r=wingo --- js/src/jit/BaselineCompiler.cpp | 21 +++++++++++++++++++++ js/src/jit/BaselineCompiler.h | 1 + js/src/jit/VMFunctions.cpp | 6 ++++++ js/src/jit/VMFunctions.h | 2 ++ 4 files changed, 30 insertions(+) diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 8491db46ea10..b998c4059694 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -3235,3 +3235,24 @@ BaselineCompiler::emit_JSOP_REST() frame.push(R0); return true; } + +typedef JSObject *(*CreateGeneratorFn)(JSContext *, BaselineFrame *); +static const VMFunction CreateGeneratorInfo = FunctionInfo(jit::CreateGenerator); + +bool +BaselineCompiler::emit_JSOP_GENERATOR() +{ + MOZ_ASSERT(frame.stackDepth() == 0); + + masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg()); + + prepareVMCall(); + pushArg(R0.scratchReg()); + if (!callVM(CreateGeneratorInfo)) + return false; + + masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0); + frame.push(R0); + return true; +} + diff --git a/js/src/jit/BaselineCompiler.h b/js/src/jit/BaselineCompiler.h index c6086465b023..13b3da8fe392 100644 --- a/js/src/jit/BaselineCompiler.h +++ b/js/src/jit/BaselineCompiler.h @@ -173,6 +173,7 @@ namespace jit { _(JSOP_MOREITER) \ _(JSOP_ISNOITER) \ _(JSOP_ENDITER) \ + _(JSOP_GENERATOR) \ _(JSOP_CALLEE) \ _(JSOP_SETRVAL) \ _(JSOP_RETRVAL) \ diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 164c7542d08e..ae29126c9e04 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -829,6 +829,12 @@ DebugEpilogue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool ok) return ok; } +JSObject * +CreateGenerator(JSContext *cx, BaselineFrame *frame) +{ + return GeneratorObject::create(cx, frame); +} + bool StrictEvalPrologue(JSContext *cx, BaselineFrame *frame) { diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index 6523e07cf57e..8e7aa8442f52 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -706,6 +706,8 @@ bool DebugPrologue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool *mu bool DebugEpilogue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool ok); bool DebugEpilogueOnBaselineReturn(JSContext *cx, BaselineFrame *frame, jsbytecode *pc); +JSObject *CreateGenerator(JSContext *cx, BaselineFrame *frame); + bool StrictEvalPrologue(JSContext *cx, BaselineFrame *frame); bool HeavyweightFunPrologue(JSContext *cx, BaselineFrame *frame); From d010174e369ac78194a1104f5ad09923c6507161 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Tue, 11 Nov 2014 15:12:28 +0100 Subject: [PATCH 14/47] Bug 1093573 part 6 - Baseline-compile yield instructions. r=wingo --- js/src/jit/BaselineCompiler.cpp | 100 +++++++++++++++++++++++++++++++- js/src/jit/BaselineCompiler.h | 9 +++ js/src/jit/BaselineJIT.cpp | 23 +++++++- js/src/jit/BaselineJIT.h | 15 ++++- js/src/jit/VMFunctions.cpp | 45 ++++++++++++++ js/src/jit/VMFunctions.h | 4 ++ 6 files changed, 192 insertions(+), 4 deletions(-) diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index b998c4059694..a833129a0e4e 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -30,6 +30,7 @@ using namespace js::jit; BaselineCompiler::BaselineCompiler(JSContext *cx, TempAllocator &alloc, JSScript *script) : BaselineCompilerSpecific(cx, alloc, script), + yieldOffsets_(cx), modifiesArguments_(false) { } @@ -186,7 +187,8 @@ BaselineCompiler::compile() icEntries_.length(), pcMappingIndexEntries.length(), pcEntries.length(), - bytecodeTypeMapEntries); + bytecodeTypeMapEntries, + yieldOffsets_.length()); if (!baselineScript) return Method_Error; @@ -243,6 +245,8 @@ BaselineCompiler::compile() // searches for the sought entry when queries are in linear order. bytecodeMap[script->nTypeSets()] = 0; + baselineScript->copyYieldEntries(script, yieldOffsets_); + if (script->compartment()->debugMode()) baselineScript->setDebugMode(); @@ -3256,3 +3260,97 @@ BaselineCompiler::emit_JSOP_GENERATOR() return true; } +bool +BaselineCompiler::addYieldOffset() +{ + MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD); + + uint32_t yieldIndex = GET_UINT24(pc); + + while (yieldIndex >= yieldOffsets_.length()) { + if (!yieldOffsets_.append(0)) + return false; + } + + static_assert(JSOP_INITIALYIELD_LENGTH == JSOP_YIELD_LENGTH, + "code below assumes INITIALYIELD and YIELD have same length"); + yieldOffsets_[yieldIndex] = script->pcToOffset(pc + JSOP_YIELD_LENGTH); + return true; +} + +typedef bool (*InitialSuspendFn)(JSContext *, HandleObject, BaselineFrame *, jsbytecode *); +static const VMFunction InitialSuspendInfo = FunctionInfo(jit::InitialSuspend); + +bool +BaselineCompiler::emit_JSOP_INITIALYIELD() +{ + if (!addYieldOffset()) + return false; + + frame.syncStack(0); + + // Store generator in R0, BaselineFrame pointer in R1. + masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg()); + masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg()); + + prepareVMCall(); + pushArg(ImmPtr(pc)); + pushArg(R1.scratchReg()); + pushArg(R0.scratchReg()); + + if (!callVM(InitialSuspendInfo)) + return false; + + masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), JSReturnOperand); + return emitReturn(); +} + +typedef bool (*NormalSuspendFn)(JSContext *, HandleObject, BaselineFrame *, jsbytecode *, uint32_t); +static const VMFunction NormalSuspendInfo = FunctionInfo(jit::NormalSuspend); + +bool +BaselineCompiler::emit_JSOP_YIELD() +{ + if (!addYieldOffset()) + return false; + + // Store generator in R0, BaselineFrame pointer in R1. + frame.popRegsAndSync(1); + masm.unboxObject(R0, R0.scratchReg()); + masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg()); + + prepareVMCall(); + pushArg(Imm32(frame.stackDepth())); + pushArg(ImmPtr(pc)); + pushArg(R1.scratchReg()); + pushArg(R0.scratchReg()); + + if (!callVM(NormalSuspendInfo)) + return false; + + masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), JSReturnOperand); + return emitReturn(); +} + +typedef bool (*FinalSuspendFn)(JSContext *, HandleObject, BaselineFrame *, jsbytecode *); +static const VMFunction FinalSuspendInfo = FunctionInfo(jit::FinalSuspend); + +bool +BaselineCompiler::emit_JSOP_FINALYIELDRVAL() +{ + // Store generator in R0, BaselineFrame pointer in R1. + frame.popRegsAndSync(1); + masm.unboxObject(R0, R0.scratchReg()); + masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg()); + + prepareVMCall(); + pushArg(ImmPtr(pc)); + pushArg(R1.scratchReg()); + pushArg(R0.scratchReg()); + + if (!callVM(FinalSuspendInfo)) + return false; + + masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand); + return emitReturn(); +} diff --git a/js/src/jit/BaselineCompiler.h b/js/src/jit/BaselineCompiler.h index 13b3da8fe392..baec72bfd2aa 100644 --- a/js/src/jit/BaselineCompiler.h +++ b/js/src/jit/BaselineCompiler.h @@ -174,6 +174,9 @@ namespace jit { _(JSOP_ISNOITER) \ _(JSOP_ENDITER) \ _(JSOP_GENERATOR) \ + _(JSOP_INITIALYIELD) \ + _(JSOP_YIELD) \ + _(JSOP_FINALYIELDRVAL) \ _(JSOP_CALLEE) \ _(JSOP_SETRVAL) \ _(JSOP_RETRVAL) \ @@ -198,6 +201,10 @@ class BaselineCompiler : public BaselineCompilerSpecific // equivalent positions when debug mode is off. CodeOffsetLabel postDebugPrologueOffset_; + // For each INITIALYIELD or YIELD op, this Vector maps the yield index + // to the bytecode offset of the next op. + Vector yieldOffsets_; + // Whether any on stack arguments are modified. bool modifiesArguments_; @@ -279,6 +286,8 @@ class BaselineCompiler : public BaselineCompilerSpecific bool addPCMappingEntry(bool addIndexEntry); + bool addYieldOffset(); + void getScopeCoordinateObject(Register reg); Address getScopeCoordinateAddressFromObject(Register objReg, Register reg); Address getScopeCoordinateAddress(Register reg); diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp index 3d0a3cc92b0a..8d9c2f55eb3c 100644 --- a/js/src/jit/BaselineJIT.cpp +++ b/js/src/jit/BaselineJIT.cpp @@ -339,23 +339,26 @@ BaselineScript * BaselineScript::New(JSScript *jsscript, uint32_t prologueOffset, uint32_t epilogueOffset, uint32_t spsPushToggleOffset, uint32_t postDebugPrologueOffset, size_t icEntries, size_t pcMappingIndexEntries, size_t pcMappingSize, - size_t bytecodeTypeMapEntries) + size_t bytecodeTypeMapEntries, size_t yieldEntries) { static const unsigned DataAlignment = sizeof(uintptr_t); size_t icEntriesSize = icEntries * sizeof(ICEntry); size_t pcMappingIndexEntriesSize = pcMappingIndexEntries * sizeof(PCMappingIndexEntry); size_t bytecodeTypeMapSize = bytecodeTypeMapEntries * sizeof(uint32_t); + size_t yieldEntriesSize = yieldEntries * sizeof(uintptr_t); size_t paddedICEntriesSize = AlignBytes(icEntriesSize, DataAlignment); size_t paddedPCMappingIndexEntriesSize = AlignBytes(pcMappingIndexEntriesSize, DataAlignment); size_t paddedPCMappingSize = AlignBytes(pcMappingSize, DataAlignment); size_t paddedBytecodeTypesMapSize = AlignBytes(bytecodeTypeMapSize, DataAlignment); + size_t paddedYieldEntriesSize = AlignBytes(yieldEntriesSize, DataAlignment); size_t allocBytes = paddedICEntriesSize + paddedPCMappingIndexEntriesSize + paddedPCMappingSize + - paddedBytecodeTypesMapSize; + paddedBytecodeTypesMapSize + + paddedYieldEntriesSize; BaselineScript *script = jsscript->zone()->pod_malloc_with_extra(allocBytes); if (!script) @@ -379,7 +382,12 @@ BaselineScript::New(JSScript *jsscript, uint32_t prologueOffset, uint32_t epilog offsetCursor += paddedPCMappingSize; script->bytecodeTypeMapOffset_ = bytecodeTypeMapEntries ? offsetCursor : 0; + offsetCursor += paddedBytecodeTypesMapSize; + script->yieldEntriesOffset_ = yieldEntries ? offsetCursor : 0; + offsetCursor += paddedYieldEntriesSize; + + MOZ_ASSERT(offsetCursor == sizeof(BaselineScript) + allocBytes); return script; } @@ -570,6 +578,17 @@ BaselineScript::icEntryFromReturnAddress(uint8_t *returnAddr) return icEntryFromReturnOffset(offset); } +void +BaselineScript::copyYieldEntries(JSScript *script, Vector &yieldOffsets) +{ + uint8_t **entries = yieldEntryList(); + + for (size_t i = 0; i < yieldOffsets.length(); i++) { + uint32_t offset = yieldOffsets[i]; + entries[i] = nativeCodeForPC(script, script->offsetToPC(offset)); + } +} + void BaselineScript::copyICEntries(JSScript *script, const ICEntry *entries, MacroAssembler &masm) { diff --git a/js/src/jit/BaselineJIT.h b/js/src/jit/BaselineJIT.h index 89243877a66b..8f62ad85b988 100644 --- a/js/src/jit/BaselineJIT.h +++ b/js/src/jit/BaselineJIT.h @@ -178,6 +178,10 @@ struct BaselineScript // they correspond to, for use by TypeScript::BytecodeTypes. uint32_t bytecodeTypeMapOffset_; + // For generator scripts, we store the native code address for each yield + // instruction. + uint32_t yieldEntriesOffset_; + public: // Do not call directly, use BaselineScript::New. This is public for cx->new_. BaselineScript(uint32_t prologueOffset, uint32_t epilogueOffset, @@ -187,7 +191,8 @@ struct BaselineScript uint32_t epilogueOffset, uint32_t postDebugPrologueOffset, uint32_t spsPushToggleOffset, size_t icEntries, size_t pcMappingIndexEntries, size_t pcMappingSize, - size_t bytecodeTypeMapEntries); + size_t bytecodeTypeMapEntries, size_t yieldEntries); + static void Trace(JSTracer *trc, BaselineScript *script); static void Destroy(FreeOp *fop, BaselineScript *script); @@ -268,6 +273,9 @@ struct BaselineScript ICEntry *icEntryList() { return (ICEntry *)(reinterpret_cast(this) + icEntriesOffset_); } + uint8_t **yieldEntryList() { + return (uint8_t **)(reinterpret_cast(this) + yieldEntriesOffset_); + } PCMappingIndexEntry *pcMappingIndexEntryList() { return (PCMappingIndexEntry *)(reinterpret_cast(this) + pcMappingIndexOffset_); } @@ -319,6 +327,8 @@ struct BaselineScript void copyICEntries(JSScript *script, const ICEntry *entries, MacroAssembler &masm); void adoptFallbackStubs(FallbackICStubSpace *stubSpace); + void copyYieldEntries(JSScript *script, Vector &yieldOffsets); + PCMappingIndexEntry &pcMappingIndexEntry(size_t index); CompactBufferReader pcMappingReader(size_t indexEntry); @@ -354,6 +364,9 @@ struct BaselineScript static size_t offsetOfFlags() { return offsetof(BaselineScript, flags_); } + static size_t offsetOfYieldEntriesOffset() { + return offsetof(BaselineScript, yieldEntriesOffset_); + } static void writeBarrierPre(Zone *zone, BaselineScript *script); diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index ae29126c9e04..501562c5b663 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -835,6 +835,51 @@ CreateGenerator(JSContext *cx, BaselineFrame *frame) return GeneratorObject::create(cx, frame); } +bool +InitialSuspend(JSContext *cx, HandleObject obj, BaselineFrame *frame, jsbytecode *pc) +{ + MOZ_ASSERT(*pc == JSOP_INITIALYIELD); + return GeneratorObject::initialSuspend(cx, obj, frame, pc); +} + +bool +NormalSuspend(JSContext *cx, HandleObject obj, BaselineFrame *frame, jsbytecode *pc, + uint32_t stackDepth) +{ + MOZ_ASSERT(*pc == JSOP_YIELD); + + // Return value is still on the stack. + MOZ_ASSERT(stackDepth >= 1); + + // The expression stack slots are stored on the stack in reverse order, so + // we copy them to a Vector and pass a pointer to that instead. We use + // stackDepth - 1 because we don't want to include the return value. + AutoValueVector exprStack(cx); + if (!exprStack.reserve(stackDepth - 1)) + return false; + + size_t firstSlot = frame->numValueSlots() - stackDepth; + for (size_t i = 0; i < stackDepth - 1; i++) + exprStack.infallibleAppend(*frame->valueSlot(firstSlot + i)); + + MOZ_ASSERT(exprStack.length() == stackDepth - 1); + + return GeneratorObject::normalSuspend(cx, obj, frame, pc, exprStack.begin(), stackDepth - 1); +} + +bool +FinalSuspend(JSContext *cx, HandleObject obj, BaselineFrame *frame, jsbytecode *pc) +{ + MOZ_ASSERT(*pc == JSOP_FINALYIELDRVAL); + + if (!GeneratorObject::finalSuspend(cx, obj)) { + // Leave this frame and propagate the exception to the caller. + return DebugEpilogue(cx, frame, pc, /* ok = */ false); + } + + return true; +} + bool StrictEvalPrologue(JSContext *cx, BaselineFrame *frame) { diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index 8e7aa8442f52..dbdeb996f743 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -707,6 +707,10 @@ bool DebugEpilogue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool ok) bool DebugEpilogueOnBaselineReturn(JSContext *cx, BaselineFrame *frame, jsbytecode *pc); JSObject *CreateGenerator(JSContext *cx, BaselineFrame *frame); +bool InitialSuspend(JSContext *cx, HandleObject obj, BaselineFrame *frame, jsbytecode *pc); +bool NormalSuspend(JSContext *cx, HandleObject obj, BaselineFrame *frame, jsbytecode *pc, + uint32_t stackDepth); +bool FinalSuspend(JSContext *cx, HandleObject obj, BaselineFrame *frame, jsbytecode *pc); bool StrictEvalPrologue(JSContext *cx, BaselineFrame *frame); bool HeavyweightFunPrologue(JSContext *cx, BaselineFrame *frame); From d676b698cab0a4bee89dc193e3412fb2d3ec1e81 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Mon, 10 Nov 2014 14:18:09 -0500 Subject: [PATCH 15/47] Bug 1096501 - include nsRefPtr.h instead of nsAutoPtr.h in ipdl generated files; r=bent --- ipc/ipdl/ipdl/builtin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipc/ipdl/ipdl/builtin.py b/ipc/ipdl/ipdl/builtin.py index 24fea9660427..20898a39a625 100644 --- a/ipc/ipdl/ipdl/builtin.py +++ b/ipc/ipdl/ipdl/builtin.py @@ -46,7 +46,7 @@ HeaderIncludes = ( 'prtime.h', 'IPCMessageStart.h', 'ipc/IPCMessageUtils.h', - 'nsAutoPtr.h', + 'nsRefPtr.h', 'nsStringGlue.h', 'nsTArray.h', 'mozilla/ipc/ProtocolUtils.h', From 7c30f4465ad2b9a737b28ac0ebf09edbd566221a Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Tue, 11 Nov 2014 08:36:52 -0600 Subject: [PATCH 16/47] Bug 1091912 - stop using mprotect to halt Ion/asm.js execution (r=bhackett) --HG-- extra : rebase_source : 2b5b2958d5a1782680800132ab01bf407640a92b --- js/src/asmjs/AsmJSModule.cpp | 95 +---- js/src/asmjs/AsmJSModule.h | 10 - js/src/asmjs/AsmJSSignalHandlers.cpp | 542 ++++++++++++------------ js/src/asmjs/AsmJSSignalHandlers.h | 13 +- js/src/jit/CodeGenerator.cpp | 14 - js/src/jit/ExecutableAllocator.cpp | 26 -- js/src/jit/ExecutableAllocator.h | 8 - js/src/jit/ExecutableAllocatorPosix.cpp | 15 - js/src/jit/ExecutableAllocatorWin.cpp | 16 - js/src/jit/Ion.cpp | 136 +----- js/src/jit/Ion.h | 2 - js/src/jit/IonLinker.h | 4 - js/src/jit/JitCompartment.h | 41 +- js/src/jit/VMFunctions.cpp | 14 +- js/src/jsapi.cpp | 2 +- js/src/jscntxt.h | 1 - js/src/jscompartment.cpp | 17 +- js/src/jsgc.cpp | 23 +- js/src/vm/ForkJoin.cpp | 4 +- js/src/vm/HelperThreads.cpp | 2 +- js/src/vm/Runtime.cpp | 50 +-- js/src/vm/Runtime.h | 64 +-- js/src/vm/Stack.cpp | 9 +- 23 files changed, 386 insertions(+), 722 deletions(-) diff --git a/js/src/asmjs/AsmJSModule.cpp b/js/src/asmjs/AsmJSModule.cpp index ae86f8fb05c6..bed659926a5a 100644 --- a/js/src/asmjs/AsmJSModule.cpp +++ b/js/src/asmjs/AsmJSModule.cpp @@ -54,36 +54,6 @@ using mozilla::PodEqual; using mozilla::Compression::LZ4; using mozilla::Swap; -// At any time, the executable code of an asm.js module can be protected (as -// part of RequestInterruptForAsmJSCode). When we touch the executable outside -// of executing it (which the AsmJSFaultHandler will correctly handle), we need -// to guard against this by unprotecting the code (if it has been protected) and -// preventing it from being protected while we are touching it. -class AutoUnprotectCode -{ - JSRuntime *rt_; - JSRuntime::AutoLockForInterrupt lock_; - const AsmJSModule &module_; - const bool protectedBefore_; - - public: - AutoUnprotectCode(JSContext *cx, const AsmJSModule &module) - : rt_(cx->runtime()), - lock_(rt_), - module_(module), - protectedBefore_(module_.codeIsProtected(rt_)) - { - if (protectedBefore_) - module_.unprotectCode(rt_); - } - - ~AutoUnprotectCode() - { - if (protectedBefore_) - module_.protectCode(rt_); - } -}; - static uint8_t * AllocateExecutableMemory(ExclusiveContext *cx, size_t bytes) { @@ -113,8 +83,7 @@ AsmJSModule::AsmJSModule(ScriptSource *scriptSource, uint32_t srcStart, uint32_t dynamicallyLinked_(false), loadedFromCache_(false), profilingEnabled_(false), - interrupted_(false), - codeIsProtected_(false) + interrupted_(false) { mozilla::PodZero(&pod); pod.funcPtrTableAndExitBytes_ = SIZE_MAX; @@ -830,7 +799,6 @@ AsmJSModule::initHeap(Handle heap, JSContext *cx #endif } -// This method assumes the caller has a live AutoUnprotectCode. void AsmJSModule::restoreHeapToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer) { @@ -852,7 +820,6 @@ AsmJSModule::restoreHeapToInitialState(ArrayBufferObjectMaybeShared *maybePrevBu heapDatum() = nullptr; } -// This method assumes the caller has a live AutoUnprotectCode. void AsmJSModule::restoreToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer, uint8_t *prevCode, @@ -907,7 +874,6 @@ AsmJSModule::detachHeap(JSContext *cx) MOZ_ASSERT_IF(active(), activation()->exitReason() == AsmJSExit::Reason_IonFFI || activation()->exitReason() == AsmJSExit::Reason_SlowFFI); - AutoUnprotectCode auc(cx, *this); restoreHeapToInitialState(maybeHeap_); MOZ_ASSERT(hasDetachedHeap()); @@ -1568,8 +1534,6 @@ AsmJSModule::deserialize(ExclusiveContext *cx, const uint8_t *cursor) bool AsmJSModule::clone(JSContext *cx, ScopedJSDeletePtr *moduleOut) const { - AutoUnprotectCode auc(cx, *this); - *moduleOut = cx->new_(scriptSource_, srcStart_, srcBodyStart_, pod.strict_, pod.usesSignalHandlers_); if (!*moduleOut) @@ -1628,7 +1592,6 @@ AsmJSModule::changeHeap(Handle newHeap, JSContext *cx) if (interrupted_) return false; - AutoUnprotectCode auc(cx, *this); restoreHeapToInitialState(maybeHeap_); initHeap(newHeap, cx); return true; @@ -1669,9 +1632,6 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext *cx) AutoFlushICache afc("AsmJSModule::setProfilingEnabled"); setAutoFlushICacheRange(); - // To enable profiling, we need to patch 3 kinds of things: - AutoUnprotectCode auc(cx, *this); - // Patch all internal (asm.js->asm.js) callsites to call the profiling // prologues: for (size_t i = 0; i < callSites_.length(); i++) { @@ -1818,59 +1778,6 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext *cx) profilingEnabled_ = enabled; } -void -AsmJSModule::protectCode(JSRuntime *rt) const -{ - MOZ_ASSERT(isDynamicallyLinked()); - MOZ_ASSERT(rt->currentThreadOwnsInterruptLock()); - - codeIsProtected_ = true; - - if (!pod.functionBytes_) - return; - - // Technically, we should be able to only take away the execute permissions, - // however this seems to break our emulators which don't always check - // execute permissions while executing code. -#if defined(XP_WIN) - DWORD oldProtect; - if (!VirtualProtect(codeBase(), functionBytes(), PAGE_NOACCESS, &oldProtect)) - MOZ_CRASH(); -#else // assume Unix - if (mprotect(codeBase(), functionBytes(), PROT_NONE)) - MOZ_CRASH(); -#endif -} - -void -AsmJSModule::unprotectCode(JSRuntime *rt) const -{ - MOZ_ASSERT(isDynamicallyLinked()); - MOZ_ASSERT(rt->currentThreadOwnsInterruptLock()); - - codeIsProtected_ = false; - - if (!pod.functionBytes_) - return; - -#if defined(XP_WIN) - DWORD oldProtect; - if (!VirtualProtect(codeBase(), functionBytes(), PAGE_EXECUTE_READWRITE, &oldProtect)) - MOZ_CRASH(); -#else // assume Unix - if (mprotect(codeBase(), functionBytes(), PROT_READ | PROT_WRITE | PROT_EXEC)) - MOZ_CRASH(); -#endif -} - -bool -AsmJSModule::codeIsProtected(JSRuntime *rt) const -{ - MOZ_ASSERT(isDynamicallyLinked()); - MOZ_ASSERT(rt->currentThreadOwnsInterruptLock()); - return codeIsProtected_; -} - static bool GetCPUID(uint32_t *cpuId) { diff --git a/js/src/asmjs/AsmJSModule.h b/js/src/asmjs/AsmJSModule.h index 129e1b3c5dbe..2491b0289ea1 100644 --- a/js/src/asmjs/AsmJSModule.h +++ b/js/src/asmjs/AsmJSModule.h @@ -826,10 +826,6 @@ class AsmJSModule bool profilingEnabled_; bool interrupted_; - // This field is accessed concurrently when requesting an interrupt. - // Access must be synchronized via the runtime's interrupt lock. - mutable bool codeIsProtected_; - void restoreHeapToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer); void restoreToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer, uint8_t *prevCode, ExclusiveContext *cx); @@ -1529,12 +1525,6 @@ class AsmJSModule MOZ_ASSERT(isDynamicallyLinked()); interrupted_ = interrupted; } - - // Additionally, these functions may only be called while holding the - // runtime's interrupt lock. - void protectCode(JSRuntime *rt) const; - void unprotectCode(JSRuntime *rt) const; - bool codeIsProtected(JSRuntime *rt) const; }; // Store the just-parsed module in the cache using AsmJSCacheOps. diff --git a/js/src/asmjs/AsmJSSignalHandlers.cpp b/js/src/asmjs/AsmJSSignalHandlers.cpp index 2fae613a9abd..7f09247f4cda 100644 --- a/js/src/asmjs/AsmJSSignalHandlers.cpp +++ b/js/src/asmjs/AsmJSSignalHandlers.cpp @@ -19,6 +19,7 @@ #include "asmjs/AsmJSSignalHandlers.h" #include "mozilla/DebugOnly.h" +#include "mozilla/PodOperations.h" #include "asmjs/AsmJSModule.h" #include "vm/Runtime.h" @@ -28,6 +29,81 @@ using namespace js::jit; using JS::GenericNaN; using mozilla::DebugOnly; +using mozilla::PodArrayZero; + +#if defined(ANDROID) +# include +# if defined(MOZ_LINKER) +extern "C" MFBT_API bool IsSignalHandlingBroken(); +# endif + +static bool +IsSignalHandlingBrokenOnAndroid() +{ + // pthread_kill appears to cause memory corruption on Android 2.3 (SDK + // version 9-10) on tinderbox. It's possible the bug is just in the + // emulator, so if we end up wanting signal-handler-based optimizations for + // non-emulated Android 2.3, we could refine this test to only report + // failure if on an emulator. Most phones are on a newer Android version. + char version_string[PROP_VALUE_MAX]; + PodArrayZero(version_string); + if (__system_property_get("ro.build.version.sdk", version_string) > 0) { + long version = atol(version_string); + if (version && version <= 10) + return true; + } + +# if defined(MOZ_LINKER) + // Apparently, on some Android systems, the signal handler is always passed + // nullptr as the faulting address. This would cause the asm.js signal + // handler to think that a safe out-of-bounds access was a nullptr-deref. + // This brokenness is already detected by ElfLoader (enabled by MOZ_LINKER), + // so reuse that check to disable asm.js compilation on systems where the + // signal handler is broken. + if (IsSignalHandlingBroken()) + return true; +# endif + + return false; +} +#endif + +// For platforms where the signal/exception handler runs on the same +// thread/stack as the victim (Unix and Windows), we can use TLS to find any +// currently executing asm.js code. +static JSRuntime * +RuntimeForCurrentThread() +{ + PerThreadData *threadData = TlsPerThreadData.get(); + if (!threadData) + return nullptr; + + return threadData->runtimeIfOnOwnerThread(); +} + +// Crashing inside the signal handler can cause the handler to be recursively +// invoked, eventually blowing the stack without actually showing a crash +// report dialog via Breakpad. To guard against this we watch for such +// recursion and fall through to the next handler immediately rather than +// trying to handle it. +class AutoSetHandlingSignal +{ + JSRuntime *rt; + + public: + explicit AutoSetHandlingSignal(JSRuntime *rt) + : rt(rt) + { + MOZ_ASSERT(!rt->handlingSignal); + rt->handlingSignal = true; + } + + ~AutoSetHandlingSignal() + { + MOZ_ASSERT(rt->handlingSignal); + rt->handlingSignal = false; + } +}; #if defined(XP_WIN) # define XMM_sig(p,i) ((p)->Xmm##i) @@ -152,71 +228,12 @@ using mozilla::DebugOnly; # define R15_sig(p) ((p)->uc_mcontext.mc_r15) # endif #elif defined(XP_MACOSX) -// Mach requires special treatment. +# define EIP_sig(p) ((p)->uc_mcontext->__ss.__eip) +# define RIP_sig(p) ((p)->uc_mcontext->__ss.__rip) #else # error "Don't know how to read/write to the thread state via the mcontext_t." #endif -// For platforms where the signal/exception handler runs on the same -// thread/stack as the victim (Unix and Windows), we can use TLS to find any -// currently executing asm.js code. -#if !defined(XP_MACOSX) -static JSRuntime * -RuntimeForCurrentThread() -{ - PerThreadData *threadData = TlsPerThreadData.get(); - if (!threadData) - return nullptr; - - return threadData->runtimeIfOnOwnerThread(); -} -#endif // !defined(XP_MACOSX) - -// Crashing inside the signal handler can cause the handler to be recursively -// invoked, eventually blowing the stack without actually showing a crash -// report dialog via Breakpad. To guard against this we watch for such -// recursion and fall through to the next handler immediately rather than -// trying to handle it. -class AutoSetHandlingSignal -{ - JSRuntime *rt; - - public: - explicit AutoSetHandlingSignal(JSRuntime *rt) - : rt(rt) - { - MOZ_ASSERT(!rt->handlingSignal); - rt->handlingSignal = true; - } - - ~AutoSetHandlingSignal() - { - MOZ_ASSERT(rt->handlingSignal); - rt->handlingSignal = false; - } -}; - -#if defined(JS_CODEGEN_X64) -template -static void -SetXMMRegToNaN(bool isFloat32, T *xmm_reg) -{ - if (isFloat32) { - JS_STATIC_ASSERT(sizeof(T) == 4 * sizeof(float)); - float *floats = reinterpret_cast(xmm_reg); - floats[0] = GenericNaN(); - floats[1] = 0; - floats[2] = 0; - floats[3] = 0; - } else { - JS_STATIC_ASSERT(sizeof(T) == 2 * sizeof(double)); - double *dbls = reinterpret_cast(xmm_reg); - dbls[0] = GenericNaN(); - dbls[1] = 0; - } -} -#endif - #if defined(XP_WIN) # include "jswin.h" #else @@ -228,7 +245,7 @@ SetXMMRegToNaN(bool isFloat32, T *xmm_reg) # include // for ucontext_t, mcontext_t #endif -#if defined(JS_CODEGEN_X64) +#if defined(JS_CPU_X64) # if defined(__DragonFly__) # include // for union savefpu # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ @@ -317,18 +334,6 @@ enum { REG_EIP = 14 }; # endif // !defined(__BIONIC_HAVE_UCONTEXT_T) #endif // defined(ANDROID) -#if defined(ANDROID) && defined(MOZ_LINKER) -// Apparently, on some Android systems, the signal handler is always passed -// nullptr as the faulting address. This would cause the asm.js signal handler -// to think that a safe out-of-bounds access was a nullptr-deref. This -// brokenness is already detected by ElfLoader (enabled by MOZ_LINKER), so -// reuse that check to disable asm.js compilation on systems where the signal -// handler is broken. -extern "C" MFBT_API bool IsSignalHandlingBroken(); -#else -static bool IsSignalHandlingBroken() { return false; } -#endif // defined(MOZ_LINKER) - #if !defined(XP_WIN) # define CONTEXT ucontext_t #endif @@ -343,41 +348,33 @@ static bool IsSignalHandlingBroken() { return false; } # define PC_sig(p) EPC_sig(p) #endif -static bool -HandleSimulatorInterrupt(JSRuntime *rt, AsmJSActivation *activation, void *faultingAddress) -{ - // If the ARM simulator is enabled, the pc is in the simulator C++ code and - // not in the generated code, so we check the simulator's pc manually. Also - // note that we can't simply use simulator->set_pc() here because the - // simulator could be in the middle of an instruction. On ARM, the signal - // handlers are currently only used for Odin code, see bug 964258. - -#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR) - const AsmJSModule &module = activation->module(); - if (module.containsFunctionPC((void *)rt->mainThread.simulator()->get_pc()) && - module.containsFunctionPC(faultingAddress)) - { - activation->setResumePC(nullptr); - int32_t nextpc = int32_t(module.interruptExit()); - rt->mainThread.simulator()->set_resume_pc(nextpc); - return true; - } -#endif - return false; -} - -#if !defined(XP_MACOSX) static uint8_t ** ContextToPC(CONTEXT *context) { -#ifdef JS_CODEGEN_NONE - MOZ_CRASH(); -#else return reinterpret_cast(&PC_sig(context)); -#endif } -# if defined(JS_CODEGEN_X64) +#if defined(JS_CPU_X64) +template +static void +SetXMMRegToNaN(bool isFloat32, T *xmm_reg) +{ + if (isFloat32) { + JS_STATIC_ASSERT(sizeof(T) == 4 * sizeof(float)); + float *floats = reinterpret_cast(xmm_reg); + floats[0] = GenericNaN(); + floats[1] = 0; + floats[2] = 0; + floats[3] = 0; + } else { + JS_STATIC_ASSERT(sizeof(T) == 2 * sizeof(double)); + double *dbls = reinterpret_cast(xmm_reg); + dbls[0] = GenericNaN(); + dbls[1] = 0; + } +} + +# if !defined(XP_MACOSX) static void SetRegisterToCoercedUndefined(CONTEXT *context, bool isFloat32, AnyRegister reg) { @@ -423,13 +420,13 @@ SetRegisterToCoercedUndefined(CONTEXT *context, bool isFloat32, AnyRegister reg) } } } -# endif // JS_CODEGEN_X64 -#endif // !XP_MACOSX +# endif // !XP_MACOSX +#endif // JS_CPU_X64 #if defined(XP_WIN) static bool -HandleException(PEXCEPTION_POINTERS exception) +HandleFault(PEXCEPTION_POINTERS exception) { EXCEPTION_RECORD *record = exception->ExceptionRecord; CONTEXT *context = exception->ContextRecord; @@ -444,19 +441,13 @@ HandleException(PEXCEPTION_POINTERS exception) if (record->NumberParameters < 2) return false; - void *faultingAddress = (void*)record->ExceptionInformation[1]; - - JSRuntime *rt = RuntimeForCurrentThread(); - // Don't allow recursive handling of signals, see AutoSetHandlingSignal. + JSRuntime *rt = RuntimeForCurrentThread(); if (!rt || rt->handlingSignal) return false; AutoSetHandlingSignal handling(rt); - if (rt->jitRuntime() && rt->jitRuntime()->handleAccessViolation(rt, faultingAddress)) - return true; - - AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation(); + AsmJSActivation *activation = rt->mainThread.asmJSActivationStack(); if (!activation) return false; @@ -464,23 +455,10 @@ HandleException(PEXCEPTION_POINTERS exception) if (!module.containsFunctionPC(pc)) return false; - // If we faulted trying to execute code in 'module', this must be an - // interrupt callback (see RequestInterruptForAsmJSCode). Redirect - // execution to a trampoline which will call js::HandleExecutionInterrupt. - // The trampoline will jump to activation->resumePC if execution isn't - // interrupted. - if (module.containsFunctionPC(faultingAddress)) { - activation->setResumePC(pc); - *ppc = module.interruptExit(); - - JSRuntime::AutoLockForInterrupt lock(rt); - module.unprotectCode(rt); - return true; - } - -# if defined(JS_CODEGEN_X64) +# if defined(JS_CPU_X64) // These checks aren't necessary, but, since we can, check anyway to make // sure we aren't covering up a real bug. + void *faultingAddress = (void*)record->ExceptionInformation[1]; if (!module.maybeHeap() || faultingAddress < module.maybeHeap() || faultingAddress >= module.maybeHeap() + AsmJSMappedSize) @@ -512,9 +490,9 @@ HandleException(PEXCEPTION_POINTERS exception) } static LONG WINAPI -AsmJSExceptionHandler(LPEXCEPTION_POINTERS exception) +AsmJSFaultHandler(LPEXCEPTION_POINTERS exception) { - if (HandleException(exception)) + if (HandleFault(exception)) return EXCEPTION_CONTINUE_EXECUTION; // No need to worry about calling other handlers, the OS does this for us. @@ -527,18 +505,16 @@ AsmJSExceptionHandler(LPEXCEPTION_POINTERS exception) static uint8_t ** ContextToPC(x86_thread_state_t &state) { -# if defined(JS_CODEGEN_X64) +# if defined(JS_CPU_X64) JS_STATIC_ASSERT(sizeof(state.uts.ts64.__rip) == sizeof(void*)); return reinterpret_cast(&state.uts.ts64.__rip); -# elif defined(JS_CODEGEN_NONE) - MOZ_CRASH(); # else JS_STATIC_ASSERT(sizeof(state.uts.ts32.__eip) == sizeof(void*)); return reinterpret_cast(&state.uts.ts32.__eip); # endif } -# if defined(JS_CODEGEN_X64) +# if defined(JS_CPU_X64) static bool SetRegisterToCoercedUndefined(mach_port_t rtThread, x86_thread_state64_t &state, const AsmJSHeapAccess &heapAccess) @@ -650,45 +626,18 @@ HandleMachException(JSRuntime *rt, const ExceptionRequest &request) if (request.body.exception != EXC_BAD_ACCESS || request.body.codeCnt != 2) return false; - void *faultingAddress = (void*)request.body.code[1]; - - if (rt->jitRuntime() && rt->jitRuntime()->handleAccessViolation(rt, faultingAddress)) - return true; - AsmJSActivation *activation = rt->mainThread.asmJSActivationStack(); if (!activation) return false; const AsmJSModule &module = activation->module(); - if (HandleSimulatorInterrupt(rt, activation, faultingAddress)) { - JSRuntime::AutoLockForInterrupt lock(rt); - module.unprotectCode(rt); - return true; - } - if (!module.containsFunctionPC(pc)) return false; - // If we faulted trying to execute code in 'module', this must be an - // interrupt callback (see RequestInterruptForAsmJSCode). Redirect - // execution to a trampoline which will call js::HandleExecutionInterrupt. - // The trampoline will jump to activation->resumePC if execution isn't - // interrupted. - if (module.containsFunctionPC(faultingAddress)) { - activation->setResumePC(pc); - *ppc = module.interruptExit(); - - JSRuntime::AutoLockForInterrupt lock(rt); - module.unprotectCode(rt); - - // Update the thread state with the new pc. - kret = thread_set_state(rtThread, x86_THREAD_STATE, (thread_state_t)&state, x86_THREAD_STATE_COUNT); - return kret == KERN_SUCCESS; - } - -# if defined(JS_CODEGEN_X64) +# if defined(JS_CPU_X64) // These checks aren't necessary, but, since we can, check anyway to make // sure we aren't covering up a real bug. + void *faultingAddress = (void*)request.body.code[1]; if (!module.maybeHeap() || faultingAddress < module.maybeHeap() || faultingAddress >= module.maybeHeap() + AsmJSMappedSize) @@ -879,55 +828,30 @@ AsmJSMachExceptionHandler::install(JSRuntime *rt) // Be very cautious and default to not handling; we don't want to accidentally // silence real crashes from real bugs. static bool -HandleSignal(int signum, siginfo_t *info, void *ctx) +HandleFault(int signum, siginfo_t *info, void *ctx) { CONTEXT *context = (CONTEXT *)ctx; uint8_t **ppc = ContextToPC(context); uint8_t *pc = *ppc; - void *faultingAddress = info->si_addr; - - JSRuntime *rt = RuntimeForCurrentThread(); - // Don't allow recursive handling of signals, see AutoSetHandlingSignal. + JSRuntime *rt = RuntimeForCurrentThread(); if (!rt || rt->handlingSignal) return false; AutoSetHandlingSignal handling(rt); - if (rt->jitRuntime() && rt->jitRuntime()->handleAccessViolation(rt, faultingAddress)) - return true; - - AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation(); + AsmJSActivation *activation = rt->mainThread.asmJSActivationStack(); if (!activation) return false; const AsmJSModule &module = activation->module(); - if (HandleSimulatorInterrupt(rt, activation, faultingAddress)) { - JSRuntime::AutoLockForInterrupt lock(rt); - module.unprotectCode(rt); - return true; - } - if (!module.containsFunctionPC(pc)) return false; - // If we faulted trying to execute code in 'module', this must be an - // interrupt callback (see RequestInterruptForAsmJSCode). Redirect - // execution to a trampoline which will call js::HandleExecutionInterrupt. - // The trampoline will jump to activation->resumePC if execution isn't - // interrupted. - if (module.containsFunctionPC(faultingAddress)) { - activation->setResumePC(pc); - *ppc = module.interruptExit(); - - JSRuntime::AutoLockForInterrupt lock(rt); - module.unprotectCode(rt); - return true; - } - -# if defined(JS_CODEGEN_X64) +# if defined(JS_CPU_X64) // These checks aren't necessary, but, since we can, check anyway to make // sure we aren't covering up a real bug. + void *faultingAddress = info->si_addr; if (!module.maybeHeap() || faultingAddress < module.maybeHeap() || faultingAddress >= module.maybeHeap() + AsmJSMappedSize) @@ -954,12 +878,12 @@ HandleSignal(int signum, siginfo_t *info, void *ctx) # endif } -static struct sigaction sPrevHandler; +static struct sigaction sPrevSEGVHandler; static void AsmJSFaultHandler(int signum, siginfo_t *info, void *context) { - if (HandleSignal(signum, info, context)) + if (HandleFault(signum, info, context)) return; // This signal is not for any asm.js code we expect, so we need to forward @@ -974,90 +898,188 @@ AsmJSFaultHandler(int signum, siginfo_t *info, void *context) // signal to it's original disposition and returning. // // Note: the order of these tests matter. - if (sPrevHandler.sa_flags & SA_SIGINFO) - sPrevHandler.sa_sigaction(signum, info, context); - else if (sPrevHandler.sa_handler == SIG_DFL || sPrevHandler.sa_handler == SIG_IGN) - sigaction(signum, &sPrevHandler, nullptr); + if (sPrevSEGVHandler.sa_flags & SA_SIGINFO) + sPrevSEGVHandler.sa_sigaction(signum, info, context); + else if (sPrevSEGVHandler.sa_handler == SIG_DFL || sPrevSEGVHandler.sa_handler == SIG_IGN) + sigaction(signum, &sPrevSEGVHandler, nullptr); else - sPrevHandler.sa_handler(signum); + sPrevSEGVHandler.sa_handler(signum); } #endif -#if !defined(XP_MACOSX) -static bool sInstalledHandlers = false; +static void +RedirectIonBackedgesToInterruptCheck(JSRuntime *rt) +{ + if (jit::JitRuntime *jitRuntime = rt->jitRuntime()) { + // If the backedge list is being mutated, the pc must be in C++ code and + // thus not in a JIT iloop. We assume that the interrupt flag will be + // checked at least once before entering JIT code (if not, no big deal; + // the browser will just request another interrupt in a second). + if (!jitRuntime->mutatingBackedgeList()) + jitRuntime->patchIonBackedges(rt, jit::JitRuntime::BackedgeInterruptCheck); + } +} + +static void +RedirectJitCodeToInterruptCheck(JSRuntime *rt, CONTEXT *context) +{ + RedirectIonBackedgesToInterruptCheck(rt); + + if (AsmJSActivation *activation = rt->mainThread.asmJSActivationStack()) { + const AsmJSModule &module = activation->module(); + +#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR) + if (module.containsFunctionPC((void*)rt->mainThread.simulator()->get_pc())) + rt->mainThread.simulator()->set_resume_pc(int32_t(module.interruptExit())); +#endif + + uint8_t **ppc = ContextToPC(context); + uint8_t *pc = *ppc; + if (module.containsFunctionPC(pc)) { + activation->setResumePC(pc); + *ppc = module.interruptExit(); + } + } +} + +#if !defined(XP_WIN) +// For the interrupt signal, pick a signal number that: +// - is not otherwise used by mozilla or standard libraries +// - defaults to nostop and noprint on gdb/lldb so that noone is bothered +// SIGVTALRM a relative of SIGALRM, so intended for user code, but, unlike +// SIGALRM, not used anywhere else in Mozilla. +static const int sInterruptSignal = SIGVTALRM; + +static void +JitInterruptHandler(int signum, siginfo_t *info, void *context) +{ + if (JSRuntime *rt = RuntimeForCurrentThread()) + RedirectJitCodeToInterruptCheck(rt, (CONTEXT*)context); +} #endif bool -js::EnsureAsmJSSignalHandlersInstalled(JSRuntime *rt) +js::EnsureSignalHandlersInstalled(JSRuntime *rt) { -#ifdef JS_CODEGEN_NONE - // Don't install signal handlers in builds with the JIT disabled. - return false; -#endif - - if (IsSignalHandlingBroken()) - return false; - #if defined(XP_MACOSX) - // On OSX, each JSRuntime gets its own handler. - return rt->asmJSMachExceptionHandler.installed() || rt->asmJSMachExceptionHandler.install(rt); -#else - // Assume Windows or Unix. For these platforms, there is a single, - // process-wide signal handler installed. Take care to only install it once. - if (sInstalledHandlers) - return true; - -# if defined(XP_WIN) - if (!AddVectoredExceptionHandler(/* FirstHandler = */true, AsmJSExceptionHandler)) + // On OSX, each JSRuntime gets its own handler thread. + if (!rt->asmJSMachExceptionHandler.installed() && !rt->asmJSMachExceptionHandler.install(rt)) return false; -# else - // Assume Unix. SA_NODEFER allows us to reenter the signal handler if we - // crash while handling the signal, and fall through to the Breakpad - // handler by testing handlingSignal. - struct sigaction sigAction; - sigAction.sa_flags = SA_SIGINFO | SA_NODEFER; - sigAction.sa_sigaction = &AsmJSFaultHandler; - sigemptyset(&sigAction.sa_mask); - if (sigaction(SIGSEGV, &sigAction, &sPrevHandler)) - return false; -# endif - - sInstalledHandlers = true; #endif + + // All the rest of the handlers are process-wide and thus must only be + // installed once. We assume that there are no races creating the first + // JSRuntime of the process. + static bool sTried = false; + static bool sResult = false; + if (sTried) + return sResult; + sTried = true; + +#if defined(ANDROID) + // Signal handling is broken on some android systems. + if (IsSignalHandlingBrokenOnAndroid()) + return false; +#endif + +#if defined(XP_WIN) + // Windows uses SuspendThread to stop the main thread from another thread, + // so the only handler we need is for asm.js out-of-bound faults. + if (!AddVectoredExceptionHandler(/* FirstHandler = */true, AsmJSFaultHandler)) + return false; +#else + // The interrupt handler allows the main thread to be paused from another + // thread (see InterruptRunningJitCode). + struct sigaction interruptHandler; + interruptHandler.sa_flags = SA_SIGINFO; + interruptHandler.sa_sigaction = &JitInterruptHandler; + sigemptyset(&interruptHandler.sa_mask); + struct sigaction prev; + if (sigaction(sInterruptSignal, &interruptHandler, &prev)) + MOZ_CRASH("unable to install interrupt handler"); + + // There shouldn't be any other handlers installed for sInterruptSignal. If + // there are, we could always forward, but we need to understand what we're + // doing to avoid problematic interference. + if ((prev.sa_flags & SA_SIGINFO && prev.sa_sigaction) || + (prev.sa_handler != SIG_DFL && prev.sa_handler != SIG_IGN)) + { + MOZ_CRASH("contention for interrupt signal"); + } + + // Lastly, install a SIGSEGV handler to handle safely-out-of-bounds asm.js + // heap access. OSX handles seg faults via the Mach exception handler above, + // so don't install AsmJSFaultHandler. +# if !defined(XP_MACOSX) + // SA_NODEFER allows us to reenter the signal handler if we crash while + // handling the signal, and fall through to the Breakpad handler by testing + // handlingSignal. + struct sigaction faultHandler; + faultHandler.sa_flags = SA_SIGINFO | SA_NODEFER; + faultHandler.sa_sigaction = &AsmJSFaultHandler; + sigemptyset(&faultHandler.sa_mask); + if (sigaction(SIGSEGV, &faultHandler, &sPrevSEGVHandler)) + return false; +# endif // defined(XP_MACOSX) +#endif // defined(XP_WIN) + + sResult = true; return true; } -// To interrupt execution of a JSRuntime, any thread may call -// JS_RequestInterruptCallback (JSRuntime::requestInterruptCallback from inside -// the engine). In the simplest case, this sets some state that is polled at -// regular intervals (function prologues, loop headers). For tight loops, this -// poses non-trivial overhead. For asm.js, we can do better: when another -// thread requests an interrupt, we simply mprotect all of the innermost asm.js -// module activation's code. This will trigger a SIGSEGV, taking us into -// AsmJSFaultHandler. From there, we can manually redirect execution to call -// js::HandleExecutionInterrupt. The memory is un-protected from the signal -// handler after control flow is redirected. +// JSRuntime::requestInterrupt sets interrupt_ (which is checked frequently by +// C++ code at every Baseline JIT loop backedge) and jitStackLimit_ (which is +// checked at every Baseline and Ion JIT function prologue). The remaining +// sources of potential iloops (Ion loop backedges and all asm.js code) are +// handled by this function: +// 1. Ion loop backedges are patched to instead point to a stub that handles the +// interrupt; +// 2. if the main thread's pc is inside asm.js code, the pc is updated to point +// to a stub that handles the interrupt. void -js::RequestInterruptForAsmJSCode(JSRuntime *rt, int interruptModeRaw) +js::InterruptRunningJitCode(JSRuntime *rt) { - switch (JSRuntime::InterruptMode(interruptModeRaw)) { - case JSRuntime::RequestInterruptMainThread: - case JSRuntime::RequestInterruptAnyThread: - break; - case JSRuntime::RequestInterruptAnyThreadDontStopIon: - case JSRuntime::RequestInterruptAnyThreadForkJoin: - // It is ok to wait for asm.js execution to complete; we aren't trying - // to break an iloop or anything. Avoid the overhead of protecting all - // the code and taking a fault. + // If signal handlers weren't installed, then Ion and asm.js emit normal + // interrupt checks and don't need asynchronous interruption. + if (!rt->canUseSignalHandlers()) + return; + + // If we are on runtime's main thread, then: pc is not in asm.js code (so + // nothing to do for asm.js) and we can patch Ion backedges without any + // special synchronization. + if (rt == RuntimeForCurrentThread()) { + RedirectIonBackedgesToInterruptCheck(rt); return; } - AsmJSActivation *activation = rt->mainThread.asmJSActivationStack(); - if (!activation) - return; + // We are not on the runtime's main thread, so to do 1 and 2 above, we need + // to halt the runtime's main thread first. +#if defined(XP_WIN) + // On Windows, we can simply suspend the main thread and work directly on + // its context from this thread. + HANDLE thread = (HANDLE)rt->ownerThreadNative(); + if (SuspendThread(thread) == -1) + MOZ_CRASH("Failed to suspend main thread"); - MOZ_ASSERT(rt->currentThreadOwnsInterruptLock()); - activation->module().protectCode(rt); + CONTEXT context; + context.ContextFlags = CONTEXT_CONTROL; + if (!GetThreadContext(thread, &context)) + MOZ_CRASH("Failed to get suspended thread context"); + + RedirectJitCodeToInterruptCheck(rt, &context); + + if (!SetThreadContext(thread, &context)) + MOZ_CRASH("Failed to set suspended thread context"); + + if (ResumeThread(thread) == -1) + MOZ_CRASH("Failed to resume main thread"); +#else + // On Unix, we instead deliver an async signal to the main thread which + // halts the thread and callers our JitInterruptHandler (which has already + // been installed by EnsureSignalHandlersInstalled). + pthread_t thread = (pthread_t)rt->ownerThreadNative(); + pthread_kill(thread, sInterruptSignal); +#endif } // This is not supported by clang-cl yet. diff --git a/js/src/asmjs/AsmJSSignalHandlers.h b/js/src/asmjs/AsmJSSignalHandlers.h index d94ce1b611dd..e4133191d92b 100644 --- a/js/src/asmjs/AsmJSSignalHandlers.h +++ b/js/src/asmjs/AsmJSSignalHandlers.h @@ -28,15 +28,16 @@ struct JSRuntime; namespace js { -// Returns whether signal handlers for asm.js and for JitRuntime access -// violations have been installed. +// Set up any signal/exception handlers needed to execute code in the given +// runtime. Return whether runtime can: +// - rely on fault handler support for avoiding asm.js heap bounds checks +// - rely on InterruptRunningJitCode to halt running Ion/asm.js from any thread bool -EnsureAsmJSSignalHandlersInstalled(JSRuntime *rt); +EnsureSignalHandlersInstalled(JSRuntime *rt); -// Force any currently-executing asm.js code to call -// js::HandleExecutionInterrupt. +// Force any currently-executing asm.js code to call HandleExecutionInterrupt. extern void -RequestInterruptForAsmJSCode(JSRuntime *rt, int interruptMode); +InterruptRunningJitCode(JSRuntime *rt); // On OSX we are forced to use the lower-level Mach exception mechanism instead // of Unix signals. Mach exceptions are not handled on the victim's stack but diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index be05db38ac57..a323902b23b6 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -7624,20 +7624,6 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints) return false; discardIonCode.ionScript = ionScript; - // Lock the runtime against interrupt callbacks during the link. - // We don't want an interrupt request to protect the code for the script - // before it has been filled in, as we could segv before the runtime's - // patchable backedges have been fully updated. - JSRuntime::AutoLockForInterrupt lock(cx->runtime()); - - // Make sure we don't segv while filling in the code, to avoid deadlocking - // inside the signal handler. - cx->runtime()->jitRuntime()->ensureIonCodeAccessible(cx->runtime()); - - // Implicit interrupts are used only for sequential code. In parallel mode - // use the normal executable allocator so that we cannot segv during - // execution off the main thread. - // // Also, note that creating the code here during an incremental GC will // trace the code and mark all GC things it refers to. This captures any // read barriers which were skipped while compiling the script off thread. diff --git a/js/src/jit/ExecutableAllocator.cpp b/js/src/jit/ExecutableAllocator.cpp index 6ae24b7f10ff..a6afe9618164 100644 --- a/js/src/jit/ExecutableAllocator.cpp +++ b/js/src/jit/ExecutableAllocator.cpp @@ -62,29 +62,3 @@ ExecutableAllocator::addSizeOfCode(JS::CodeSizes *sizes) const } } -void -ExecutableAllocator::toggleAllCodeAsAccessible(bool accessible) -{ - if (!m_pools.initialized()) - return; - - for (ExecPoolHashSet::Range r = m_pools.all(); !r.empty(); r.popFront()) { - ExecutablePool* pool = r.front(); - pool->toggleAllCodeAsAccessible(accessible); - } -} - -bool -ExecutableAllocator::codeContains(char* address) -{ - if (!m_pools.initialized()) - return false; - - for (ExecPoolHashSet::Range r = m_pools.all(); !r.empty(); r.popFront()) { - ExecutablePool* pool = r.front(); - if (pool->codeContains(address)) - return true; - } - - return false; -} diff --git a/js/src/jit/ExecutableAllocator.h b/js/src/jit/ExecutableAllocator.h index 6268acc96bf3..aae98903557b 100644 --- a/js/src/jit/ExecutableAllocator.h +++ b/js/src/jit/ExecutableAllocator.h @@ -170,12 +170,6 @@ private: MOZ_ASSERT(m_end >= m_freePtr); return m_end - m_freePtr; } - - void toggleAllCodeAsAccessible(bool accessible); - - bool codeContains(char* address) { - return address >= m_allocation.pages && address < m_freePtr; - } }; class ExecutableAllocator { @@ -260,8 +254,6 @@ public: } void addSizeOfCode(JS::CodeSizes *sizes) const; - void toggleAllCodeAsAccessible(bool accessible); - bool codeContains(char* address); void setDestroyCallback(DestroyCallback destroyCallback) { this->destroyCallback = destroyCallback; diff --git a/js/src/jit/ExecutableAllocatorPosix.cpp b/js/src/jit/ExecutableAllocatorPosix.cpp index 950667e325c1..6f79cd348178 100644 --- a/js/src/jit/ExecutableAllocatorPosix.cpp +++ b/js/src/jit/ExecutableAllocatorPosix.cpp @@ -91,18 +91,3 @@ void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSe } #endif -void -ExecutablePool::toggleAllCodeAsAccessible(bool accessible) -{ - char* begin = m_allocation.pages; - size_t size = m_freePtr - begin; - - if (size) { - // N.B. Some systems, like 32bit Mac OS 10.6, implicitly add PROT_EXEC - // when mprotect'ing memory with any flag other than PROT_NONE. Be - // sure to use PROT_NONE when making inaccessible. - int flags = accessible ? PROT_READ | PROT_WRITE | PROT_EXEC : PROT_NONE; - if (mprotect(begin, size, flags)) - MOZ_CRASH(); - } -} diff --git a/js/src/jit/ExecutableAllocatorWin.cpp b/js/src/jit/ExecutableAllocatorWin.cpp index e18eb34b62c2..3c9add304d74 100644 --- a/js/src/jit/ExecutableAllocatorWin.cpp +++ b/js/src/jit/ExecutableAllocatorWin.cpp @@ -251,22 +251,6 @@ void ExecutableAllocator::systemRelease(const ExecutablePool::Allocation& alloc) DeallocateExecutableMemory(alloc.pages, alloc.size, pageSize); } -void -ExecutablePool::toggleAllCodeAsAccessible(bool accessible) -{ - char* begin = m_allocation.pages; - size_t size = m_freePtr - begin; - - if (size) { - // N.B. DEP is not on automatically in Windows XP, so be sure to use - // PAGE_NOACCESS instead of PAGE_READWRITE when making inaccessible. - DWORD oldProtect; - int flags = accessible ? PAGE_EXECUTE_READWRITE : PAGE_NOACCESS; - if (!VirtualProtect(begin, size, flags, &oldProtect)) - MOZ_CRASH(); - } -} - #if ENABLE_ASSEMBLER_WX_EXCLUSIVE #error "ASSEMBLER_WX_EXCLUSIVE not yet suported on this platform." #endif diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 7dfeb7e52408..6a4f458c3289 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -167,7 +167,7 @@ JitRuntime::JitRuntime() baselineDebugModeOSRHandler_(nullptr), functionWrappers_(nullptr), osrTempData_(nullptr), - ionCodeProtected_(false), + mutatingBackedgeList_(false), ionReturnOverride_(MagicValue(JS_ARG_POISON)), jitcodeGlobalTable_(nullptr) { @@ -191,7 +191,6 @@ bool JitRuntime::initialize(JSContext *cx) { MOZ_ASSERT(cx->runtime()->currentThreadHasExclusiveAccess()); - MOZ_ASSERT(cx->runtime()->currentThreadOwnsInterruptLock()); AutoCompartment ac(cx, cx->atomsCompartment()); @@ -366,85 +365,17 @@ JitRuntime::freeOsrTempData() ExecutableAllocator * JitRuntime::createIonAlloc(JSContext *cx) { - MOZ_ASSERT(cx->runtime()->currentThreadOwnsInterruptLock()); - ionAlloc_ = js_new(); if (!ionAlloc_) js_ReportOutOfMemory(cx); return ionAlloc_; } -void -JitRuntime::ensureIonCodeProtected(JSRuntime *rt) -{ - MOZ_ASSERT(rt->currentThreadOwnsInterruptLock()); - - if (!rt->signalHandlersInstalled() || ionCodeProtected_ || !ionAlloc_) - return; - - // Protect all Ion code in the runtime to trigger an access violation the - // next time any of it runs on the main thread. - ionAlloc_->toggleAllCodeAsAccessible(false); - ionCodeProtected_ = true; -} - -bool -JitRuntime::handleAccessViolation(JSRuntime *rt, void *faultingAddress) -{ - if (!rt->signalHandlersInstalled() || !ionAlloc_ || !ionAlloc_->codeContains((char *) faultingAddress)) - return false; - - // All places where the interrupt lock is taken must either ensure that Ion - // code memory won't be accessed within, or call ensureIonCodeAccessible to - // render the memory safe for accessing. Otherwise taking the lock below - // will deadlock the process. - MOZ_ASSERT(!rt->currentThreadOwnsInterruptLock()); - - // Taking this lock is necessary to prevent the interrupting thread from marking - // the memory as inaccessible while we are patching backedges. This will cause us - // to SEGV while still inside the signal handler, and the process will terminate. - JSRuntime::AutoLockForInterrupt lock(rt); - - // Ion code in the runtime faulted after it was made inaccessible. Reset - // the code privileges and patch all loop backedges to perform an interrupt - // check instead. - ensureIonCodeAccessible(rt); - return true; -} - -void -JitRuntime::ensureIonCodeAccessible(JSRuntime *rt) -{ - MOZ_ASSERT(rt->currentThreadOwnsInterruptLock()); - - // This can only be called on the main thread and while handling signals, - // which happens on a separate thread in OS X. -#ifndef XP_MACOSX - MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt)); -#endif - - if (ionCodeProtected_) { - ionAlloc_->toggleAllCodeAsAccessible(true); - ionCodeProtected_ = false; - } - - if (rt->hasPendingInterrupt()) { - // The interrupt handler needs to be invoked by this thread, but we may - // be inside a signal handler and have no idea what is above us on the - // stack (probably we are executing Ion code at an arbitrary point, but - // we could be elsewhere, say repatching a jump for an IonCache). - // Patch all backedges in the runtime so they will invoke the interrupt - // handler the next time they execute. - patchIonBackedges(rt, BackedgeInterruptCheck); - } -} - void JitRuntime::patchIonBackedges(JSRuntime *rt, BackedgeTarget target) { -#ifndef XP_MACOSX - MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt)); -#endif + MOZ_ASSERT_IF(target == BackedgeLoopHeader, mutatingBackedgeList_); + MOZ_ASSERT_IF(target == BackedgeInterruptCheck, !mutatingBackedgeList_); // Patch all loop backedges in Ion code so that they either jump to the // normal loop header or to an interrupt handler each time they run. @@ -460,47 +391,6 @@ JitRuntime::patchIonBackedges(JSRuntime *rt, BackedgeTarget target) } } -void -jit::RequestInterruptForIonCode(JSRuntime *rt, JSRuntime::InterruptMode mode) -{ - JitRuntime *jitRuntime = rt->jitRuntime(); - if (!jitRuntime) - return; - - MOZ_ASSERT(rt->currentThreadOwnsInterruptLock()); - - // The mechanism for interrupting normal ion code varies depending on how - // the interrupt is being requested. - switch (mode) { - case JSRuntime::RequestInterruptMainThread: - // When requesting an interrupt from the main thread, Ion loop - // backedges can be patched directly. Make sure we don't segv while - // patching the backedges, to avoid deadlocking inside the signal - // handler. - MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt)); - jitRuntime->ensureIonCodeAccessible(rt); - break; - - case JSRuntime::RequestInterruptAnyThread: - // When requesting an interrupt from off the main thread, protect - // Ion code memory so that the main thread will fault and enter a - // signal handler when trying to execute the code. The signal - // handler will unprotect the code and patch loop backedges so - // that the interrupt handler is invoked afterwards. - jitRuntime->ensureIonCodeProtected(rt); - break; - - case JSRuntime::RequestInterruptAnyThreadDontStopIon: - case JSRuntime::RequestInterruptAnyThreadForkJoin: - // The caller does not require Ion code to be interrupted. - // Nothing more needs to be done. - break; - - default: - MOZ_CRASH("Bad interrupt mode"); - } -} - JitCompartment::JitCompartment() : stubCodes_(nullptr), baselineCallReturnAddr_(nullptr), @@ -870,10 +760,6 @@ JitCode::trace(JSTracer *trc) void JitCode::finalize(FreeOp *fop) { - // Make sure this can't race with an interrupting thread, which may try - // to read the contents of the pool we are releasing references in. - MOZ_ASSERT(fop->runtime()->currentThreadOwnsInterruptLock()); - // If this jitcode has a bytecode map, de-register it. if (hasBytecodeMap_) { MOZ_ASSERT(fop->runtime()->jitRuntime()->hasJitcodeGlobalTable()); @@ -883,7 +769,7 @@ JitCode::finalize(FreeOp *fop) // Buffer can be freed at any time hereafter. Catch use-after-free bugs. // Don't do this if the Ion code is protected, as the signal handler will // deadlock trying to reacquire the interrupt lock. - if (fop->runtime()->jitRuntime() && !fop->runtime()->jitRuntime()->ionCodeProtected()) + if (fop->runtime()->jitRuntime()) memset(code_, JS_SWEPT_CODE_PATTERN, bufferSize_); code_ = nullptr; @@ -1144,6 +1030,9 @@ IonScript::copyPatchableBackedges(JSContext *cx, JitCode *code, PatchableBackedgeInfo *backedges, MacroAssembler &masm) { + JitRuntime *jrt = cx->runtime()->jitRuntime(); + JitRuntime::AutoMutateBackedges amb(jrt); + for (size_t i = 0; i < backedgeEntries_; i++) { PatchableBackedgeInfo &info = backedges[i]; PatchableBackedge *patchableBackedge = &backedgeList()[i]; @@ -1167,7 +1056,7 @@ IonScript::copyPatchableBackedges(JSContext *cx, JitCode *code, else PatchBackedge(backedge, loopHeader, JitRuntime::BackedgeLoopHeader); - cx->runtime()->jitRuntime()->addPatchableBackedge(patchableBackedge); + jrt->addPatchableBackedge(patchableBackedge); } } @@ -1358,11 +1247,10 @@ IonScript::unlinkFromRuntime(FreeOp *fop) // The writes to the executable buffer below may clobber backedge jumps, so // make sure that those backedges are unlinked from the runtime and not // reclobbered with garbage if an interrupt is requested. - JSRuntime *rt = fop->runtime(); - for (size_t i = 0; i < backedgeEntries_; i++) { - PatchableBackedge *backedge = &backedgeList()[i]; - rt->jitRuntime()->removePatchableBackedge(backedge); - } + JitRuntime *jrt = fop->runtime()->jitRuntime(); + JitRuntime::AutoMutateBackedges amb(jrt); + for (size_t i = 0; i < backedgeEntries_; i++) + jrt->removePatchableBackedge(&backedgeList()[i]); // Clear the list of backedges, so that this method is idempotent. It is // called during destruction, and may be additionally called when the diff --git a/js/src/jit/Ion.h b/js/src/jit/Ion.h index 30d4daf06fd5..95093821b59a 100644 --- a/js/src/jit/Ion.h +++ b/js/src/jit/Ion.h @@ -201,8 +201,6 @@ size_t SizeOfIonData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf); void DestroyIonScripts(FreeOp *fop, JSScript *script); void TraceIonScripts(JSTracer* trc, JSScript *script); -void RequestInterruptForIonCode(JSRuntime *rt, JSRuntime::InterruptMode mode); - bool RematerializeAllFrames(JSContext *cx, JSCompartment *comp); bool UpdateForDebugMode(JSContext *maybecx, JSCompartment *comp, AutoDebugModeInvalidation &invalidate); diff --git a/js/src/jit/IonLinker.h b/js/src/jit/IonLinker.h index de97815f8f48..fa63b7ce046f 100644 --- a/js/src/jit/IonLinker.h +++ b/js/src/jit/IonLinker.h @@ -82,10 +82,6 @@ class Linker } JitCode *newCodeForIonScript(JSContext *cx) { - // The caller must lock the runtime against interrupt requests, as the - // thread requesting an interrupt may use the executable allocator below. - MOZ_ASSERT(cx->runtime()->currentThreadOwnsInterruptLock()); - ExecutableAllocator *alloc = cx->runtime()->jitRuntime()->getIonAlloc(cx); if (!alloc) return nullptr; diff --git a/js/src/jit/JitCompartment.h b/js/src/jit/JitCompartment.h index 718373896884..a76999230068 100644 --- a/js/src/jit/JitCompartment.h +++ b/js/src/jit/JitCompartment.h @@ -217,12 +217,11 @@ class JitRuntime // (after returning from JIT code). uint8_t *osrTempData_; - // Whether all Ion code in the runtime is protected, and will fault if it - // is accessed. - bool ionCodeProtected_; - - // If signal handlers are installed, this contains all loop backedges for - // IonScripts in the runtime. + // List of all backedges in all Ion code. The backedge edge list is accessed + // asynchronously when the main thread is paused and mutatingBackedgeList_ + // is false. Thus, the list must only be mutated while mutatingBackedgeList_ + // is true. + volatile bool mutatingBackedgeList_; InlineList backedgeList_; // In certain cases, we want to optimize certain opcodes to typed instructions, @@ -274,29 +273,39 @@ class JitRuntime ExecutableAllocator *execAlloc() const { return execAlloc_; } - ExecutableAllocator *getIonAlloc(JSContext *cx) { - MOZ_ASSERT(cx->runtime()->currentThreadOwnsInterruptLock()); return ionAlloc_ ? ionAlloc_ : createIonAlloc(cx); } - ExecutableAllocator *ionAlloc(JSRuntime *rt) { - MOZ_ASSERT(rt->currentThreadOwnsInterruptLock()); return ionAlloc_; } - bool hasIonAlloc() const { return !!ionAlloc_; } - bool ionCodeProtected() { - return ionCodeProtected_; - } + class AutoMutateBackedges + { + JitRuntime *jrt_; + public: + AutoMutateBackedges(JitRuntime *jrt) : jrt_(jrt) { + MOZ_ASSERT(!jrt->mutatingBackedgeList_); + jrt->mutatingBackedgeList_ = true; + } + ~AutoMutateBackedges() { + MOZ_ASSERT(jrt_->mutatingBackedgeList_); + jrt_->mutatingBackedgeList_ = false; + } + }; + bool mutatingBackedgeList() const { + return mutatingBackedgeList_; + } void addPatchableBackedge(PatchableBackedge *backedge) { + MOZ_ASSERT(mutatingBackedgeList_); backedgeList_.pushFront(backedge); } void removePatchableBackedge(PatchableBackedge *backedge) { + MOZ_ASSERT(mutatingBackedgeList_); backedgeList_.remove(backedge); } @@ -305,12 +314,8 @@ class JitRuntime BackedgeInterruptCheck }; - void ensureIonCodeProtected(JSRuntime *rt); - void ensureIonCodeAccessible(JSRuntime *rt); void patchIonBackedges(JSRuntime *rt, BackedgeTarget target); - bool handleAccessViolation(JSRuntime *rt, void *faultingAddress); - JitCode *getVMWrapper(const VMFunction &f) const; JitCode *debugTrapHandler(JSContext *cx); JitCode *getBaselineDebugModeOSRHandler(JSContext *cx); diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 501562c5b663..0a0d2d4d2541 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -522,15 +522,11 @@ InterruptCheck(JSContext *cx) { gc::MaybeVerifyBarriers(cx); - // Fix loop backedges so that they do not invoke the interrupt again. - // No lock is held here and it's possible we could segv in the middle here - // and end up with a state where some fraction of the backedges point to - // the interrupt handler and some don't. This is ok since the interrupt - // is definitely about to be handled; if there are still backedges - // afterwards which point to the interrupt handler, the next time they are - // taken the backedges will just be reset again. - cx->runtime()->jitRuntime()->patchIonBackedges(cx->runtime(), - JitRuntime::BackedgeLoopHeader); + { + JitRuntime *jrt = cx->runtime()->jitRuntime(); + JitRuntime::AutoMutateBackedges amb(jrt); + jrt->patchIonBackedges(cx->runtime(), JitRuntime::BackedgeLoopHeader); + } return CheckForInterrupt(cx); } diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index a913b3d7958a..2db98984532a 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -5072,7 +5072,7 @@ JS_GetInterruptCallback(JSRuntime *rt) JS_PUBLIC_API(void) JS_RequestInterruptCallback(JSRuntime *rt) { - rt->requestInterrupt(JSRuntime::RequestInterruptAnyThread); + rt->requestInterrupt(JSRuntime::RequestInterruptUrgent); } JS_PUBLIC_API(bool) diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 4c81f3febbd0..9f9dd119dbcd 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -293,7 +293,6 @@ struct ThreadSafeContext : ContextFriendFields, void *stackLimitAddress(StackKind kind) { return &runtime_->mainThread.nativeStackLimit[kind]; } void *stackLimitAddressForJitCode(StackKind kind); size_t gcSystemPageSize() { return gc::SystemPageSize(); } - bool signalHandlersInstalled() const { return runtime_->signalHandlersInstalled(); } bool canUseSignalHandlers() const { return runtime_->canUseSignalHandlers(); } bool jitSupportsFloatingPoint() const { return runtime_->jitSupportsFloatingPoint; } bool jitSupportsSimd() const { return runtime_->jitSupportsSimd; } diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 826e42167da2..fd54b3b5f8bc 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -33,6 +33,7 @@ using namespace js; using namespace js::gc; +using namespace js::jit; using mozilla::DebugOnly; @@ -125,18 +126,18 @@ JSRuntime::createJitRuntime(JSContext *cx) // accessed by other threads with an exclusive context. AutoLockForExclusiveAccess atomsLock(cx); - // The runtime will only be created on its owning thread, but reads of a - // runtime's jitRuntime() can occur when another thread is requesting an - // interrupt. - AutoLockForInterrupt lock(this); - MOZ_ASSERT(!jitRuntime_); - jitRuntime_ = cx->new_(); - - if (!jitRuntime_) + jit::JitRuntime *jrt = cx->new_(); + if (!jrt) return nullptr; + // Protect jitRuntime_ from being observed (by InterruptRunningJitCode) + // while it is being initialized. Unfortunately, initialization depends on + // jitRuntime_ being non-null, so we can't just wait to assign jitRuntime_. + JitRuntime::AutoMutateBackedges amb(jrt); + jitRuntime_ = jrt; + if (!jitRuntime_->initialize(cx)) { js_delete(jitRuntime_); jitRuntime_ = nullptr; diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 49d40c039003..2a79db8e1e3e 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -645,12 +645,7 @@ FinalizeArenas(FreeOp *fop, case FINALIZE_SYMBOL: return FinalizeTypedArenas(fop, src, dest, thingKind, budget, keepArenas); case FINALIZE_JITCODE: - { - // JitCode finalization may release references on an executable - // allocator that is accessed when requesting interrupts. - JSRuntime::AutoLockForInterrupt lock(fop->runtime()); return FinalizeTypedArenas(fop, src, dest, thingKind, budget, keepArenas); - } default: MOZ_CRASH("Invalid alloc kind"); } @@ -1056,7 +1051,7 @@ class js::gc::AutoMaybeStartBackgroundAllocation } ~AutoMaybeStartBackgroundAllocation() { - if (runtime && !runtime->currentThreadOwnsInterruptLock()) + if (runtime) runtime->gc.startBackgroundAllocTaskIfIdle(); } }; @@ -2993,7 +2988,7 @@ GCRuntime::requestMajorGC(JS::gcreason::Reason reason) majorGCRequested = true; majorGCTriggerReason = reason; - rt->requestInterrupt(JSRuntime::RequestInterruptMainThread); + rt->requestInterrupt(JSRuntime::RequestInterruptUrgent); } void @@ -3005,7 +3000,7 @@ GCRuntime::requestMinorGC(JS::gcreason::Reason reason) minorGCRequested = true; minorGCTriggerReason = reason; - rt->requestInterrupt(JSRuntime::RequestInterruptMainThread); + rt->requestInterrupt(JSRuntime::RequestInterruptUrgent); } bool @@ -3024,10 +3019,6 @@ GCRuntime::triggerGC(JS::gcreason::Reason reason) if (!CurrentThreadCanAccessRuntime(rt)) return false; - /* Don't trigger GCs when allocating under the interrupt callback lock. */ - if (rt->currentThreadOwnsInterruptLock()) - return false; - /* GC is already running. */ if (rt->isHeapCollecting()) return false; @@ -3087,10 +3078,6 @@ GCRuntime::triggerZoneGC(Zone *zone, JS::gcreason::Reason reason) if (zone->usedByExclusiveThread) return false; - /* Don't trigger GCs when allocating under the interrupt callback lock. */ - if (rt->currentThreadOwnsInterruptLock()) - return false; - /* GC is already running. */ if (rt->isHeapCollecting()) return false; @@ -5318,10 +5305,8 @@ GCRuntime::endSweepPhase(bool lastGC) if (jit::ExecutableAllocator *execAlloc = rt->maybeExecAlloc()) execAlloc->purge(); - if (rt->jitRuntime() && rt->jitRuntime()->hasIonAlloc()) { - JSRuntime::AutoLockForInterrupt lock(rt); + if (rt->jitRuntime() && rt->jitRuntime()->hasIonAlloc()) rt->jitRuntime()->ionAlloc(rt)->purge(); - } /* * This removes compartments from rt->compartment, so we do it last to make diff --git a/js/src/vm/ForkJoin.cpp b/js/src/vm/ForkJoin.cpp index 7e1471311716..529e510f1510 100644 --- a/js/src/vm/ForkJoin.cpp +++ b/js/src/vm/ForkJoin.cpp @@ -1667,9 +1667,7 @@ ForkJoinShared::setAbortFlagAndRequestInterrupt(bool fatal) abort_ = true; fatal_ = fatal_ || fatal; - // Note: The ForkJoin trigger here avoids the expensive memory protection needed to - // interrupt Ion code compiled for sequential execution. - cx_->runtime()->requestInterrupt(JSRuntime::RequestInterruptAnyThreadForkJoin); + cx_->runtime()->requestInterrupt(JSRuntime::RequestInterruptCanWait); } void diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index 37cfea2863a3..a4a27d2b4ac4 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -1065,7 +1065,7 @@ HelperThread::handleIonWorkload() // at the next interrupt callback. Don't interrupt Ion code for this, as // this incorporation can be delayed indefinitely without affecting // performance as long as the main thread is actually executing Ion code. - rt->requestInterrupt(JSRuntime::RequestInterruptAnyThreadDontStopIon); + rt->requestInterrupt(JSRuntime::RequestInterruptCanWait); // Notify the main thread in case it is waiting for the compilation to finish. HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER); diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 44b5516380e5..66acf33b3a0e 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -27,6 +27,7 @@ #include "jsobj.h" #include "jsscript.h" #include "jswatchpoint.h" +#include "jswin.h" #include "jswrapper.h" #include "asmjs/AsmJSSignalHandlers.h" @@ -140,8 +141,6 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime) interruptPar_(false), handlingSignal(false), interruptCallback(nullptr), - interruptLock(nullptr), - interruptLockOwner(nullptr), exclusiveAccessLock(nullptr), exclusiveAccessOwner(nullptr), mainThreadHasExclusiveAccess(false), @@ -152,6 +151,7 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime) defaultVersion_(JSVERSION_DEFAULT), futexAPI_(nullptr), ownerThread_(nullptr), + ownerThreadNative_(0), tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), execAlloc_(nullptr), jitRuntime_(nullptr), @@ -256,9 +256,19 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes) { ownerThread_ = PR_GetCurrentThread(); - interruptLock = PR_NewLock(); - if (!interruptLock) - return false; + // Get a platform-native handle for the owner thread, used by + // js::InterruptRunningJitCode to halt the runtime's main thread. +#ifdef XP_WIN + size_t openFlags = THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME; + HANDLE self = OpenThread(openFlags, false, GetCurrentThreadId()); + if (!self) + MOZ_CRASH("Unable to open thread handle"); + static_assert(sizeof(HANDLE) <= sizeof(ownerThreadNative_), "need bigger field"); + ownerThreadNative_ = (size_t)self; +#else + static_assert(sizeof(pthread_t) <= sizeof(ownerThreadNative_), "need bigger field"); + ownerThreadNative_ = (size_t)pthread_self(); +#endif exclusiveAccessLock = PR_NewLock(); if (!exclusiveAccessLock) @@ -325,7 +335,7 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes) jitSupportsFloatingPoint = js::jit::JitSupportsFloatingPoint(); jitSupportsSimd = js::jit::JitSupportsSimd(); - signalHandlersInstalled_ = EnsureAsmJSSignalHandlersInstalled(this); + signalHandlersInstalled_ = EnsureSignalHandlersInstalled(this); canUseSignalHandlers_ = signalHandlersInstalled_ && !SignalBasedTriggersDisabled(); if (!spsProfiler.init()) @@ -391,10 +401,6 @@ JSRuntime::~JSRuntime() MOZ_ASSERT(!numExclusiveThreads); mainThreadHasExclusiveAccess = true; - MOZ_ASSERT(!interruptLockOwner); - if (interruptLock) - PR_DestroyLock(interruptLock); - /* * Even though all objects in the compartment are dead, we may have keep * some filenames around because of gcKeepAtoms. @@ -444,6 +450,11 @@ JSRuntime::~JSRuntime() MOZ_ASSERT(oldCount > 0); js::TlsPerThreadData.set(nullptr); + +#ifdef XP_WIN + if (ownerThreadNative_) + CloseHandle((HANDLE)ownerThreadNative_); +#endif } void @@ -500,13 +511,9 @@ JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Runtim if (execAlloc_) execAlloc_->addSizeOfCode(&rtSizes->code); - { - AutoLockForInterrupt lock(this); - if (jitRuntime()) { - if (jit::ExecutableAllocator *ionAlloc = jitRuntime()->ionAlloc(this)) - ionAlloc->addSizeOfCode(&rtSizes->code); - } - } + + if (jitRuntime() && jitRuntime()->ionAlloc(this)) + jitRuntime()->ionAlloc(this)->addSizeOfCode(&rtSizes->code); rtSizes->gc.marker += gc.marker.sizeOfExcludingThis(mallocSizeOf); #ifdef JSGC_GENERATIONAL @@ -611,11 +618,8 @@ JSRuntime::requestInterrupt(InterruptMode mode) interruptPar_ = true; mainThread.jitStackLimit_ = UINTPTR_MAX; - if (canUseSignalHandlers()) { - AutoLockForInterrupt lock(this); - RequestInterruptForAsmJSCode(this, mode); - jit::RequestInterruptForIonCode(this, mode); - } + if (mode == JSRuntime::RequestInterruptUrgent) + InterruptRunningJitCode(this); } bool @@ -836,8 +840,6 @@ JSRuntime::assertCanLock(RuntimeLock which) MOZ_ASSERT(exclusiveAccessOwner != PR_GetCurrentThread()); case HelperThreadStateLock: MOZ_ASSERT(!HelperThreadState().isLocked()); - case InterruptLock: - MOZ_ASSERT(!currentThreadOwnsInterruptLock()); case GCLock: gc.assertCanLock(); break; diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 3735e3140fec..204fa3bc6c1c 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -452,7 +452,6 @@ AtomStateOffsetToName(const JSAtomState &atomState, size_t offset) enum RuntimeLock { ExclusiveAccessLock, HelperThreadStateLock, - InterruptLock, GCLock }; @@ -541,14 +540,6 @@ class PerThreadData : public PerThreadDataFriendFields TraceLogger *traceLogger; #endif - /* - * asm.js maintains a stack of AsmJSModule activations (see AsmJS.h). This - * stack is used by JSRuntime::requestInterrupt to stop long-running asm.js - * without requiring dynamic polling operations in the generated - * code. Since requestInterrupt may run on a separate thread than the - * JSRuntime's owner thread all reads/writes must be synchronized (by - * rt->interruptLock). - */ private: friend class js::Activation; friend class js::ActivationIterator; @@ -566,11 +557,11 @@ class PerThreadData : public PerThreadDataFriendFields /* * Points to the most recent profiling activation running on the - * thread. Protected by rt->interruptLock. + * thread. */ js::Activation * volatile profilingActivation_; - /* See AsmJSActivation comment. Protected by rt->interruptLock. */ + /* See AsmJSActivation comment. */ js::AsmJSActivation * volatile asmJSActivationStack_; /* Pointer to the current AutoFlushICache. */ @@ -714,10 +705,8 @@ struct JSRuntime : public JS::shadow::Runtime, public: enum InterruptMode { - RequestInterruptMainThread, - RequestInterruptAnyThread, - RequestInterruptAnyThreadDontStopIon, - RequestInterruptAnyThreadForkJoin + RequestInterruptUrgent, + RequestInterruptCanWait }; // Any thread can call requestInterrupt() to request that the main JS thread @@ -770,37 +759,6 @@ struct JSRuntime : public JS::shadow::Runtime, void assertCanLock(js::RuntimeLock which) {} #endif - private: - /* - * Lock taken when triggering an interrupt from another thread. - * Protects all data that is touched in this process. - */ - PRLock *interruptLock; - PRThread *interruptLockOwner; - - public: - class AutoLockForInterrupt { - JSRuntime *rt; - public: - explicit AutoLockForInterrupt(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : rt(rt) { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - rt->assertCanLock(js::InterruptLock); - PR_Lock(rt->interruptLock); - rt->interruptLockOwner = PR_GetCurrentThread(); - } - ~AutoLockForInterrupt() { - MOZ_ASSERT(rt->currentThreadOwnsInterruptLock()); - rt->interruptLockOwner = nullptr; - PR_Unlock(rt->interruptLock); - } - - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER - }; - - bool currentThreadOwnsInterruptLock() { - return interruptLockOwner == PR_GetCurrentThread(); - } - private: /* * Lock taken when using per-runtime or per-zone data that could otherwise @@ -852,9 +810,14 @@ struct JSRuntime : public JS::shadow::Runtime, private: /* See comment for JS_AbortIfWrongThread in jsapi.h. */ void *ownerThread_; + size_t ownerThreadNative_; friend bool js::CurrentThreadCanAccessRuntime(JSRuntime *rt); public: + size_t ownerThreadNative() const { + return ownerThreadNative_; + } + /* Temporary arena pool used while compiling and decompiling. */ static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4 * 1024; js::LifoAlloc tempLifoAlloc; @@ -1089,16 +1052,15 @@ struct JSRuntime : public JS::shadow::Runtime, #endif private: - // Whether asm.js signal handlers have been installed and can be used for - // performing interrupt checks in loops. + // Whether EnsureSignalHandlersInstalled succeeded in installing all the + // relevant handlers for this platform. bool signalHandlersInstalled_; + // Whether we should use them or they have been disabled for making // debugging easier. If signal handlers aren't installed, it is set to false. bool canUseSignalHandlers_; + public: - bool signalHandlersInstalled() const { - return signalHandlersInstalled_; - } bool canUseSignalHandlers() const { return canUseSignalHandlers_; } diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 49a992a662bc..02d119e606cd 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -1556,11 +1556,7 @@ AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module) module.activation() = this; prevAsmJS_ = cx->mainThread().asmJSActivationStack_; - - { - JSRuntime::AutoLockForInterrupt lock(cx->runtime()); - cx->mainThread().asmJSActivationStack_ = this; - } + cx->mainThread().asmJSActivationStack_ = this; // Now that the AsmJSActivation is fully initialized, make it visible to // asynchronous profiling. @@ -1583,7 +1579,6 @@ AsmJSActivation::~AsmJSActivation() JSContext *cx = cx_->asJSContext(); MOZ_ASSERT(cx->mainThread().asmJSActivationStack_ == this); - JSRuntime::AutoLockForInterrupt lock(cx->runtime()); cx->mainThread().asmJSActivationStack_ = prevAsmJS_; } @@ -1607,7 +1602,6 @@ void Activation::registerProfiling() { MOZ_ASSERT(isProfiling()); - JSRuntime::AutoLockForInterrupt lock(cx_->asJSContext()->runtime()); cx_->perThreadData->profilingActivation_ = this; } @@ -1615,7 +1609,6 @@ void Activation::unregisterProfiling() { MOZ_ASSERT(isProfiling()); - JSRuntime::AutoLockForInterrupt lock(cx_->asJSContext()->runtime()); MOZ_ASSERT(cx_->perThreadData->profilingActivation_ == this); cx_->perThreadData->profilingActivation_ = prevProfiling_; } From 61637f46a50fc481f66e5b62f8e80b8235ef0405 Mon Sep 17 00:00:00 2001 From: Alexander Surkov Date: Tue, 11 Nov 2014 10:56:40 -0500 Subject: [PATCH 17/47] Bug 1096930 - Crash while trying to enter the password for my Firefox account, r=marcoz --- accessible/xpcom/xpcAccessible.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/accessible/xpcom/xpcAccessible.cpp b/accessible/xpcom/xpcAccessible.cpp index da6d42d6084b..66abcc7cfd6f 100644 --- a/accessible/xpcom/xpcAccessible.cpp +++ b/accessible/xpcom/xpcAccessible.cpp @@ -199,8 +199,12 @@ NS_IMETHODIMP xpcAccessible::GetState(uint32_t* aState, uint32_t* aExtraState) { NS_ENSURE_ARG_POINTER(aState); + + if (!Intl()) + nsAccUtils::To32States(states::DEFUNCT, aState, aExtraState); + else + nsAccUtils::To32States(Intl()->State(), aState, aExtraState); - nsAccUtils::To32States(Intl()->State(), aState, aExtraState); return NS_OK; } From 5c12f0340a329c1b991075c4f16c27bf0f2ae940 Mon Sep 17 00:00:00 2001 From: David Burns Date: Tue, 11 Nov 2014 15:55:23 +0000 Subject: [PATCH 18/47] Bug 1073732: Allow Marionette to have sessions ids that are unique for that session; r=jgriffin --HG-- extra : rebase_source : 4ce931fcb6accc581867febe061151cdddf17ece --- testing/marionette/client/marionette/marionette.py | 14 +++++++++----- .../client/marionette/tests/unit/test_session.py | 12 ++++++++++++ testing/marionette/marionette-server.js | 12 +++++++++++- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/testing/marionette/client/marionette/marionette.py b/testing/marionette/client/marionette/marionette.py index d1b71c61b142..66458dd08ab6 100644 --- a/testing/marionette/client/marionette/marionette.py +++ b/testing/marionette/client/marionette/marionette.py @@ -479,6 +479,7 @@ class Marionette(object): self.bin = bin self.instance = None self.session = None + self.session_id = None self.window = None self.runner = None self.emulator = None @@ -607,12 +608,12 @@ class Marionette(object): @do_crash_check def _send_message(self, command, response_key="ok", **kwargs): - if not self.session and command != "newSession": + if not self.session_id and command != "newSession": raise errors.MarionetteException("Please start a session") message = {"name": command} - if self.session: - message["sessionId"] = self.session + if self.session_id: + message["sessionId"] = self.session_id if kwargs: message["parameters"] = kwargs @@ -637,6 +638,8 @@ class Marionette(object): continue; break; + if not self.session_id: + self.session_id = response.get("sessionId", None) if response_key in response: return response[response_key] @@ -811,7 +814,7 @@ class Marionette(object): ''' return "%s%s" % (self.baseurl, relative_url) - def start_session(self, desired_capabilities=None): + def start_session(self, desired_capabilities=None, session_id=None): """Create a new Marionette session. This method must be called before performing any other action. @@ -820,7 +823,7 @@ class Marionette(object): capabilities. This is currently ignored. :returns: A dict of the capabilities offered.""" - self.session = self._send_message('newSession', 'value', capabilities=desired_capabilities) + self.session = self._send_message('newSession', 'value', capabilities=desired_capabilities, session_id=session_id) self.b2g = 'b2g' in self.session return self.session @@ -836,6 +839,7 @@ class Marionette(object): def delete_session(self): """Close the current session and disconnect from the server.""" response = self._send_message('deleteSession', 'ok') + self.session_id = None self.session = None self.window = None self.client.close() diff --git a/testing/marionette/client/marionette/tests/unit/test_session.py b/testing/marionette/client/marionette/tests/unit/test_session.py index 16eec76d3a59..6ef600e48821 100644 --- a/testing/marionette/client/marionette/tests/unit/test_session.py +++ b/testing/marionette/client/marionette/tests/unit/test_session.py @@ -29,4 +29,16 @@ class TestSession(marionette_test.MarionetteTestCase): self.assertIn("takesScreenshot", caps) self.assertIn("version", caps) + def test_we_can_get_the_session_id(self): + # Sends newSession + caps = self.marionette.start_session() + self.assertTrue(self.marionette.session_id is not None) + self.assertTrue(isinstance(self.marionette.session_id, unicode)) + + def test_we_can_set_the_session_id(self): + # Sends newSession + caps = self.marionette.start_session(session_id="ILoveCheese") + + self.assertEqual(self.marionette.session_id, "ILoveCheese") + self.assertTrue(isinstance(self.marionette.session_id, unicode)) \ No newline at end of file diff --git a/testing/marionette/marionette-server.js b/testing/marionette/marionette-server.js index 810b7f3c7fdd..3279b7485bd6 100644 --- a/testing/marionette/marionette-server.js +++ b/testing/marionette/marionette-server.js @@ -127,6 +127,7 @@ function MarionetteServerConnection(aPrefix, aTransport, aServer) // passing back "actor ids" with responses. unlike the debugger server, // we don't have multiple actors, so just use a dummy value of "0" here this.actorID = "0"; + this.sessionId = null; this.globalMessageManager = Cc["@mozilla.org/globalmessagemanager;1"] .getService(Ci.nsIMessageBroadcaster); @@ -330,7 +331,9 @@ MarionetteServerConnection.prototype = { sendResponse: function MDA_sendResponse(value, command_id) { if (typeof(value) == 'undefined') value = null; - this.sendToClient({from:this.actorID, value: value}, command_id); + this.sendToClient({from:this.actorID, + sessionId: this.sessionId, + value: value}, command_id); }, sayHello: function MDA_sayHello() { @@ -553,6 +556,8 @@ MarionetteServerConnection.prototype = { this.scriptTimeout = 10000; if (aRequest && aRequest.parameters) { + this.sessionId = aRequest.parameters.session_id ? aRequest.parameters.session_id : null; + logger.info("Session Id is set to: " + this.sessionId); this.setSessionCapabilities(aRequest.parameters.capabilities); } @@ -625,6 +630,10 @@ MarionetteServerConnection.prototype = { getSessionCapabilities: function MDA_getSessionCapabilities() { this.command_id = this.getCommandId(); + if (!this.sessionId) { + this.sessionId = this.uuidGen.generateUUID().toString(); + } + // eideticker (bug 965297) and mochitest (bug 965304) // compatibility. They only check for the presence of this // property and should so not be in caps if not on a B2G device. @@ -2277,6 +2286,7 @@ MarionetteServerConnection.prototype = { if (this.mainFrame) { this.mainFrame.focus(); } + this.sessionId = null; this.deleteFile('marionetteChromeScripts'); this.deleteFile('marionetteContentScripts'); }, From fce2d16101d009a05c56c585c378ba0985a020a8 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Fri, 7 Nov 2014 06:32:00 -0500 Subject: [PATCH 19/47] Bug 619521 - Part 1: Send a notification of any scripts for which font coverage is lacking. r=jdaggett --- dom/canvas/CanvasRenderingContext2D.cpp | 23 +++++- gfx/src/nsFontMetrics.cpp | 6 +- gfx/thebes/gfxTextRun.cpp | 90 ++++++++++++++++++--- gfx/thebes/gfxTextRun.h | 69 ++++++++++++++-- layout/base/nsPresContext.cpp | 30 +++++++ layout/base/nsPresContext.h | 6 ++ layout/base/nsPresShell.cpp | 2 + layout/generic/MathMLTextRunFactory.cpp | 7 +- layout/generic/MathMLTextRunFactory.h | 3 +- layout/generic/nsTextFrame.cpp | 25 +++--- layout/generic/nsTextRunTransformations.cpp | 6 +- layout/generic/nsTextRunTransformations.h | 13 ++- layout/mathml/nsMathMLChar.cpp | 7 +- modules/libpref/init/all.js | 4 + 14 files changed, 246 insertions(+), 45 deletions(-) diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index e9efda6bf5ad..c2897312165a 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -3083,6 +3083,22 @@ CanvasRenderingContext2D::GetHitRegionRect(Element* aElement, nsRect& aRect) */ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcessor { + CanvasBidiProcessor() + : nsBidiPresUtils::BidiProcessor() + { + if (Preferences::GetBool(GFX_MISSING_FONTS_NOTIFY_PREF)) { + mMissingFonts = new gfxMissingFontRecorder(); + } + } + + ~CanvasBidiProcessor() + { + // notify front-end code if we encountered missing glyphs in any script + if (mMissingFonts) { + mMissingFonts->Flush(); + } + } + typedef CanvasRenderingContext2D::ContextState ContextState; virtual void SetText(const char16_t* text, int32_t length, nsBidiDirection direction) @@ -3099,7 +3115,8 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess length, mThebes, mAppUnitsPerDevPixel, - flags); + flags, + mMissingFonts); } virtual nscoord GetWidth() @@ -3337,6 +3354,10 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess // current font gfxFontGroup* mFontgrp; + // to record any unsupported characters found in the text, + // and notify front-end if it is interested + nsAutoPtr mMissingFonts; + // dev pixel conversion factor int32_t mAppUnitsPerDevPixel; diff --git a/gfx/src/nsFontMetrics.cpp b/gfx/src/nsFontMetrics.cpp index 95f2c4c5a30c..f8d2fcbfb933 100644 --- a/gfx/src/nsFontMetrics.cpp +++ b/gfx/src/nsFontMetrics.cpp @@ -33,7 +33,8 @@ public: reinterpret_cast(aString), aLength, aRC->ThebesContext(), aMetrics->AppUnitsPerDevPixel(), - ComputeFlags(aMetrics)); + ComputeFlags(aMetrics), + nullptr); } AutoTextRun(nsFontMetrics* aMetrics, nsRenderingContext* aRC, @@ -43,7 +44,8 @@ public: aString, aLength, aRC->ThebesContext(), aMetrics->AppUnitsPerDevPixel(), - ComputeFlags(aMetrics)); + ComputeFlags(aMetrics), + nullptr); } gfxTextRun *get() { return mTextRun; } diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index 21ce71f129ee..0c98ed6839b2 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -28,6 +28,7 @@ using namespace mozilla; using namespace mozilla::gfx; using namespace mozilla::unicode; +using mozilla::services::GetObserverService; static const char16_t kEllipsisChar[] = { 0x2026, 0x0 }; static const char16_t kASCIIPeriodsChar[] = { '.', '.', '.', 0x0 }; @@ -2038,12 +2039,12 @@ gfxFontGroup::MakeHyphenTextRun(gfxContext *aCtx, uint32_t aAppUnitsPerDevUnit) gfxFont *font = GetFirstValidFont(uint32_t(hyphen)); if (font->HasCharacter(hyphen)) { return MakeTextRun(&hyphen, 1, aCtx, aAppUnitsPerDevUnit, - gfxFontGroup::TEXT_IS_PERSISTENT); + gfxFontGroup::TEXT_IS_PERSISTENT, nullptr); } static const uint8_t dash = '-'; return MakeTextRun(&dash, 1, aCtx, aAppUnitsPerDevUnit, - gfxFontGroup::TEXT_IS_PERSISTENT); + gfxFontGroup::TEXT_IS_PERSISTENT, nullptr); } gfxFloat @@ -2064,7 +2065,8 @@ gfxFontGroup::GetHyphenWidth(gfxTextRun::PropertyProvider *aProvider) gfxTextRun * gfxFontGroup::MakeTextRun(const uint8_t *aString, uint32_t aLength, - const Parameters *aParams, uint32_t aFlags) + const Parameters *aParams, uint32_t aFlags, + gfxMissingFontRecorder *aMFR) { if (aLength == 0) { return MakeEmptyTextRun(aParams, aFlags); @@ -2088,7 +2090,7 @@ gfxFontGroup::MakeTextRun(const uint8_t *aString, uint32_t aLength, return nullptr; } - InitTextRun(aParams->mContext, textRun, aString, aLength); + InitTextRun(aParams->mContext, textRun, aString, aLength, aMFR); textRun->FetchGlyphExtents(aParams->mContext); @@ -2097,7 +2099,8 @@ gfxFontGroup::MakeTextRun(const uint8_t *aString, uint32_t aLength, gfxTextRun * gfxFontGroup::MakeTextRun(const char16_t *aString, uint32_t aLength, - const Parameters *aParams, uint32_t aFlags) + const Parameters *aParams, uint32_t aFlags, + gfxMissingFontRecorder *aMFR) { if (aLength == 0) { return MakeEmptyTextRun(aParams, aFlags); @@ -2115,7 +2118,7 @@ gfxFontGroup::MakeTextRun(const char16_t *aString, uint32_t aLength, return nullptr; } - InitTextRun(aParams->mContext, textRun, aString, aLength); + InitTextRun(aParams->mContext, textRun, aString, aLength, aMFR); textRun->FetchGlyphExtents(aParams->mContext); @@ -2127,7 +2130,8 @@ void gfxFontGroup::InitTextRun(gfxContext *aContext, gfxTextRun *aTextRun, const T *aString, - uint32_t aLength) + uint32_t aLength, + gfxMissingFontRecorder *aMFR) { NS_ASSERTION(aLength > 0, "don't call InitTextRun for a zero-length run"); @@ -2207,7 +2211,7 @@ gfxFontGroup::InitTextRun(gfxContext *aContext, // the text is still purely 8-bit; bypass the script-run itemizer // and treat it as a single Latin run InitScriptRun(aContext, aTextRun, aString, - 0, aLength, MOZ_SCRIPT_LATIN); + 0, aLength, MOZ_SCRIPT_LATIN, aMFR); } else { const char16_t *textPtr; if (transformedString) { @@ -2255,7 +2259,7 @@ gfxFontGroup::InitTextRun(gfxContext *aContext, #endif InitScriptRun(aContext, aTextRun, textPtr + runStart, - runStart, runLimit - runStart, runScript); + runStart, runLimit - runStart, runScript, aMFR); } } @@ -2291,6 +2295,14 @@ gfxFontGroup::InitTextRun(gfxContext *aContext, aTextRun->SortGlyphRuns(); } +static inline bool +IsPUA(uint32_t aUSV) +{ + // We could look up the General Category of the codepoint here, + // but it's simpler to check PUA codepoint ranges. + return (aUSV >= 0xE000 && aUSV <= 0xF8FF) || (aUSV >= 0xF0000); +} + template void gfxFontGroup::InitScriptRun(gfxContext *aContext, @@ -2300,7 +2312,8 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext, uint32_t aOffset, // position of the script run // within the textrun uint32_t aLength, // length of the script run - int32_t aRunScript) + int32_t aRunScript, + gfxMissingFontRecorder *aMFR) { NS_ASSERTION(aLength > 0, "don't call InitScriptRun for a 0-length run"); NS_ASSERTION(aTextRun->GetShapingState() != gfxTextRun::eShapingState_Aborted, @@ -2321,6 +2334,7 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext, ComputeRanges(fontRanges, aString, aLength, aRunScript, aTextRun->GetFlags() & gfxTextRunFactory::TEXT_ORIENT_MASK); uint32_t numRanges = fontRanges.Length(); + bool missingChars = false; for (uint32_t r = 0; r < numRanges; r++) { const gfxTextRange& range = fontRanges[r]; @@ -2467,11 +2481,15 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext, index + 1 < aLength && NS_IS_LOW_SURROGATE(aString[index + 1])) { + uint32_t usv = + SURROGATE_TO_UCS4(ch, aString[index + 1]); aTextRun->SetMissingGlyph(aOffset + index, - SURROGATE_TO_UCS4(ch, - aString[index + 1]), + usv, mainFont); index++; + if (!mSkipDrawing && !IsPUA(usv)) { + missingChars = true; + } continue; } @@ -2506,11 +2524,18 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext, // record char code so we can draw a box with the Unicode value aTextRun->SetMissingGlyph(aOffset + index, ch, mainFont); + if (!mSkipDrawing && !IsPUA(ch)) { + missingChars = true; + } } } runStart += matchedLength; } + + if (aMFR && missingChars) { + aMFR->RecordScript(aRunScript); + } } gfxTextRun * @@ -2536,7 +2561,8 @@ gfxFontGroup::GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel, refCtx, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevPixel }; gfxTextRun* textRun = - MakeTextRun(ellipsis.get(), ellipsis.Length(), ¶ms, TEXT_IS_PERSISTENT); + MakeTextRun(ellipsis.get(), ellipsis.Length(), ¶ms, + TEXT_IS_PERSISTENT, nullptr); if (!textRun) { return nullptr; } @@ -3108,3 +3134,41 @@ gfxFontGroup::Shutdown() } nsILanguageAtomService* gfxFontGroup::gLangService = nullptr; + +void +gfxMissingFontRecorder::Flush() +{ + static bool mNotifiedFontsInitialized = false; + static uint32_t mNotifiedFonts[gfxMissingFontRecorder::kNumScriptBitsWords]; + if (!mNotifiedFontsInitialized) { + memset(&mNotifiedFonts, 0, sizeof(mNotifiedFonts)); + mNotifiedFontsInitialized = true; + } + + nsAutoString fontNeeded; + for (uint32_t i = 0; i < kNumScriptBitsWords; ++i) { + mMissingFonts[i] &= ~mNotifiedFonts[i]; + if (!mMissingFonts[i]) { + continue; + } + for (uint32_t j = 0; j < 32; ++j) { + if (!(mMissingFonts[i] & (1 << j))) { + continue; + } + mNotifiedFonts[i] |= (1 << j); + if (!fontNeeded.IsEmpty()) { + fontNeeded.Append(PRUnichar(',')); + } + uint32_t tag = GetScriptTagForCode(i * 32 + j); + fontNeeded.Append(char16_t(tag >> 24)); + fontNeeded.Append(char16_t((tag >> 16) & 0xff)); + fontNeeded.Append(char16_t((tag >> 8) & 0xff)); + fontNeeded.Append(char16_t(tag & 0xff)); + } + mMissingFonts[i] = 0; + } + if (!fontNeeded.IsEmpty()) { + nsCOMPtr service = GetObserverService(); + service->NotifyObservers(nullptr, "font-needed", fontNeeded.get()); + } +} diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index c94d966689ec..6ed9c7a4cd37 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -16,6 +16,7 @@ #include "mozilla/MemoryReporting.h" #include "DrawMode.h" #include "harfbuzz/hb.h" +#include "nsUnicodeScriptCodes.h" #ifdef DEBUG #include @@ -27,6 +28,7 @@ class gfxUserFontSet; class gfxTextContextPaint; class nsIAtom; class nsILanguageAtomService; +class gfxMissingFontRecorder; /** * Callback for Draw() to use when drawing text with mode @@ -764,7 +766,8 @@ public: * This calls FetchGlyphExtents on the textrun. */ virtual gfxTextRun *MakeTextRun(const char16_t *aString, uint32_t aLength, - const Parameters *aParams, uint32_t aFlags); + const Parameters *aParams, uint32_t aFlags, + gfxMissingFontRecorder *aMFR); /** * Make a textrun for a given string. * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the @@ -772,7 +775,8 @@ public: * This calls FetchGlyphExtents on the textrun. */ virtual gfxTextRun *MakeTextRun(const uint8_t *aString, uint32_t aLength, - const Parameters *aParams, uint32_t aFlags); + const Parameters *aParams, uint32_t aFlags, + gfxMissingFontRecorder *aMFR); /** * Textrun creation helper for clients that don't want to pass @@ -782,12 +786,13 @@ public: gfxTextRun *MakeTextRun(const T *aString, uint32_t aLength, gfxContext *aRefContext, int32_t aAppUnitsPerDevUnit, - uint32_t aFlags) + uint32_t aFlags, + gfxMissingFontRecorder *aMFR) { gfxTextRunFactory::Parameters params = { aRefContext, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevUnit }; - return MakeTextRun(aString, aLength, ¶ms, aFlags); + return MakeTextRun(aString, aLength, ¶ms, aFlags, aMFR); } /** @@ -1083,7 +1088,8 @@ protected: void InitTextRun(gfxContext *aContext, gfxTextRun *aTextRun, const T *aString, - uint32_t aLength); + uint32_t aLength, + gfxMissingFontRecorder *aMFR); // InitTextRun helper to handle a single script run, by finding font ranges // and calling each font's InitTextRun() as appropriate @@ -1093,7 +1099,8 @@ protected: const T *aString, uint32_t aScriptRunStart, uint32_t aScriptRunEnd, - int32_t aRunScript); + int32_t aRunScript, + gfxMissingFontRecorder *aMFR); // Helper for font-matching: // When matching the italic case, allow use of the regular face @@ -1119,4 +1126,54 @@ protected: static nsILanguageAtomService* gLangService; }; + +// A "missing font recorder" is to be used during text-run creation to keep +// a record of any scripts encountered for which font coverage was lacking; +// when Flush() is called, it sends a notification that front-end code can use +// to download fonts on demand (or whatever else it wants to do). + +#define GFX_MISSING_FONTS_NOTIFY_PREF "gfx.missing_fonts.notify" + +class gfxMissingFontRecorder { +public: + gfxMissingFontRecorder() + { + memset(&mMissingFonts, 0, sizeof(mMissingFonts)); + } + + ~gfxMissingFontRecorder() + { +#ifdef DEBUG + for (uint32_t i = 0; i < kNumScriptBitsWords; i++) { + NS_ASSERTION(mMissingFonts[i] == 0, + "failed to flush the missing-font recorder"); + } +#endif + } + + // record this script code in our mMissingFonts bitset + void RecordScript(int32_t aScriptCode) + { + mMissingFonts[uint32_t(aScriptCode) >> 5] |= + (1 << (uint32_t(aScriptCode) & 0x1f)); + } + + // send a notification of any missing-scripts that have been + // recorded, and clear the mMissingFonts set for re-use + void Flush(); + + // forget any missing-scripts that have been recorded up to now; + // called before discarding a recorder we no longer care about + void Clear() + { + memset(&mMissingFonts, 0, sizeof(mMissingFonts)); + } + +private: + // Number of 32-bit words needed for the missing-script flags + static const uint32_t kNumScriptBitsWords = + ((MOZ_NUM_SCRIPT_CODES + 31) / 32); + uint32_t mMissingFonts[kNumScriptBitsWords]; +}; + #endif diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index c83c558cfe9b..df1d56d170fd 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -64,6 +64,7 @@ #include "nsContentUtils.h" #include "nsPIWindowRoot.h" #include "mozilla/Preferences.h" +#include "gfxTextRun.h" // Needed for Start/Stop of Image Animation #include "imgIContainer.h" @@ -249,6 +250,10 @@ nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType) mTextPerf = new gfxTextPerfMetrics(); } + if (Preferences::GetBool(GFX_MISSING_FONTS_NOTIFY_PREF)) { + mMissingFonts = new gfxMissingFontRecorder(); + } + PR_INIT_CLIST(&mDOMMediaQueryLists); } @@ -345,6 +350,9 @@ nsPresContext::LastRelease() if (IsRoot()) { static_cast(this)->CancelDidPaintTimer(); } + if (mMissingFonts) { + mMissingFonts->Clear(); + } } NS_IMPL_CYCLE_COLLECTION_CLASS(nsPresContext) @@ -880,6 +888,20 @@ nsPresContext::PreferenceChanged(const char* aPrefName) } return; } + if (prefName.EqualsLiteral(GFX_MISSING_FONTS_NOTIFY_PREF)) { + if (Preferences::GetBool(GFX_MISSING_FONTS_NOTIFY_PREF)) { + if (!mMissingFonts) { + mMissingFonts = new gfxMissingFontRecorder(); + // trigger reflow to detect missing fonts on the current page + mPrefChangePendingNeedsReflow = true; + } + } else { + if (mMissingFonts) { + mMissingFonts->Clear(); + } + mMissingFonts = nullptr; + } + } if (StringBeginsWith(prefName, NS_LITERAL_CSTRING("font."))) { // Changes to font family preferences don't change anything in the // computed style data, so the style system won't generate a reflow @@ -2237,6 +2259,14 @@ nsPresContext::RebuildCounterStyles() } } +void +nsPresContext::NotifyMissingFonts() +{ + if (mMissingFonts) { + mMissingFonts->Flush(); + } +} + void nsPresContext::EnsureSafeToHandOutCSSRules() { diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h index 59c6c02eadc4..5b01fabdfcf1 100644 --- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -65,6 +65,7 @@ class nsAnimationManager; class nsRefreshDriver; class nsIWidget; class nsDeviceContext; +class gfxMissingFontRecorder; namespace mozilla { class EventStateManager; @@ -889,6 +890,9 @@ public: // user font set is changed and fonts become unavailable). void UserFontSetUpdated(); + gfxMissingFontRecorder *MissingFontRecorder() { return mMissingFonts; } + void NotifyMissingFonts(); + mozilla::dom::FontFaceSet* Fonts(); void FlushCounterStyles(); @@ -1266,6 +1270,8 @@ protected: // text performance metrics nsAutoPtr mTextPerf; + nsAutoPtr mMissingFonts; + nsRect mVisibleArea; nsSize mPageSize; float mPageScale; diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index ac8193b28937..68ebfb50ebac 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -9072,6 +9072,8 @@ PresShell::DidDoReflow(bool aInterruptible, bool aWasInterrupted) mTouchCaret->UpdatePositionIfNeeded(); } + mPresContext->NotifyMissingFonts(); + if (!aWasInterrupted) { ClearReflowOnZoomPending(); } diff --git a/layout/generic/MathMLTextRunFactory.cpp b/layout/generic/MathMLTextRunFactory.cpp index 9ab9f5665384..ed4b31d021fc 100644 --- a/layout/generic/MathMLTextRunFactory.cpp +++ b/layout/generic/MathMLTextRunFactory.cpp @@ -529,7 +529,8 @@ MathVariant(uint32_t aCh, uint8_t aMathVar) void MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, - gfxContext* aRefContext) + gfxContext* aRefContext, + gfxMissingFontRecorder* aMFR) { gfxFontGroup* fontGroup = aTextRun->GetFontGroup(); @@ -764,7 +765,7 @@ MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, } else { cachedChild = newFontGroup->MakeTextRun( convertedString.BeginReading(), convertedString.Length(), - &innerParams, flags); + &innerParams, flags, aMFR); child = cachedChild.get(); } if (!child) @@ -776,7 +777,7 @@ MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, child->SetPotentialLineBreaks(0, canBreakBeforeArray.Length(), canBreakBeforeArray.Elements(), aRefContext); if (transformedChild) { - transformedChild->FinishSettingProperties(aRefContext); + transformedChild->FinishSettingProperties(aRefContext, aMFR); } if (mergeNeeded) { diff --git a/layout/generic/MathMLTextRunFactory.h b/layout/generic/MathMLTextRunFactory.h index 4de229694b1a..5783672e07f9 100644 --- a/layout/generic/MathMLTextRunFactory.h +++ b/layout/generic/MathMLTextRunFactory.h @@ -22,7 +22,8 @@ public: mSSTYScriptLevel(aSSTYScriptLevel) {} virtual void RebuildTextRun(nsTransformedTextRun* aTextRun, - gfxContext* aRefContext) MOZ_OVERRIDE; + gfxContext* aRefContext, + gfxMissingFontRecorder* aMFR) MOZ_OVERRIDE; enum { // Style effects which may override single character behaviour MATH_FONT_STYLING_NORMAL = 0x1, // fontstyle="normal" has been set. diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index aac55f276729..855baaa559b2 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -561,10 +561,11 @@ template gfxTextRun * MakeTextRun(const T *aText, uint32_t aLength, gfxFontGroup *aFontGroup, const gfxFontGroup::Parameters* aParams, - uint32_t aFlags) + uint32_t aFlags, gfxMissingFontRecorder *aMFR) { nsAutoPtr textRun(aFontGroup->MakeTextRun(aText, aLength, - aParams, aFlags)); + aParams, aFlags, + aMFR)); if (!textRun) { return nullptr; } @@ -842,6 +843,7 @@ public: mCurrentFramesAllSameTextRun(nullptr), mContext(aContext), mLineContainer(aLineContainer), + mMissingFonts(aPresContext->MissingFontRecorder()), mBidiEnabled(aPresContext->BidiEnabled()), mSkipIncompleteTextRuns(false), mWhichTextRun(aWhichTextRun), @@ -971,7 +973,7 @@ public: aCapitalize, mContext); } - void Finish() { + void Finish(gfxMissingFontRecorder* aMFR) { NS_ASSERTION(!(mTextRun->GetFlags() & (gfxTextRunFactory::TEXT_UNUSED_FLAGS | nsTextFrameUtils::TEXT_UNUSED_FLAG)), @@ -979,7 +981,7 @@ public: if (mTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_TRANSFORMED) { nsTransformedTextRun* transformedTextRun = static_cast(mTextRun); - transformedTextRun->FinishSettingProperties(mContext); + transformedTextRun->FinishSettingProperties(mContext, aMFR); } // The way nsTransformedTextRun is implemented, its glyph runs aren't // available until after nsTransformedTextRun::FinishSettingProperties() @@ -1007,6 +1009,7 @@ private: // The common ancestor of the current frame and the previous leaf frame // on the line, or null if there was no previous leaf frame. nsIFrame* mCommonAncestorWithLastFrame; + gfxMissingFontRecorder* mMissingFonts; // mMaxTextLength is an upper bound on the size of the text in all mapped frames // The value UINT32_MAX represents overflow; text will be discarded uint32_t mMaxTextLength; @@ -1506,7 +1509,7 @@ void BuildTextRunsScanner::FlushLineBreaks(gfxTextRun* aTrailingTextRun) // TODO cause frames associated with the textrun to be reflowed, if they // aren't being reflowed already! } - mBreakSinks[i]->Finish(); + mBreakSinks[i]->Finish(mMissingFonts); } mBreakSinks.Clear(); @@ -2138,26 +2141,30 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) const char16_t* text = static_cast(textPtr); if (transformingFactory) { textRun = transformingFactory->MakeTextRun(text, transformedLength, ¶ms, - fontGroup, textFlags, styles.Elements()); + fontGroup, textFlags, styles.Elements(), + mMissingFonts); if (textRun) { // ownership of the factory has passed to the textrun transformingFactory.forget(); } } else { - textRun = MakeTextRun(text, transformedLength, fontGroup, ¶ms, textFlags); + textRun = MakeTextRun(text, transformedLength, fontGroup, ¶ms, + textFlags, mMissingFonts); } } else { const uint8_t* text = static_cast(textPtr); textFlags |= gfxFontGroup::TEXT_IS_8BIT; if (transformingFactory) { textRun = transformingFactory->MakeTextRun(text, transformedLength, ¶ms, - fontGroup, textFlags, styles.Elements()); + fontGroup, textFlags, styles.Elements(), + mMissingFonts); if (textRun) { // ownership of the factory has passed to the textrun transformingFactory.forget(); } } else { - textRun = MakeTextRun(text, transformedLength, fontGroup, ¶ms, textFlags); + textRun = MakeTextRun(text, transformedLength, fontGroup, ¶ms, + textFlags, mMissingFonts); } } if (!textRun) { diff --git a/layout/generic/nsTextRunTransformations.cpp b/layout/generic/nsTextRunTransformations.cpp index f43d100da7e5..9ae0ce1dd96e 100644 --- a/layout/generic/nsTextRunTransformations.cpp +++ b/layout/generic/nsTextRunTransformations.cpp @@ -593,7 +593,7 @@ nsCaseTransformTextRunFactory::TransformString( void nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, - gfxContext* aRefContext) + gfxContext* aRefContext, gfxMissingFontRecorder *aMFR) { nsAutoString convertedString; nsAutoTArray charsToMergeArray; @@ -628,7 +628,7 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, } else { cachedChild = fontGroup->MakeTextRun( convertedString.BeginReading(), convertedString.Length(), - &innerParams, flags); + &innerParams, flags, aMFR); child = cachedChild.get(); } if (!child) @@ -640,7 +640,7 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, child->SetPotentialLineBreaks(0, canBreakBeforeArray.Length(), canBreakBeforeArray.Elements(), aRefContext); if (transformedChild) { - transformedChild->FinishSettingProperties(aRefContext); + transformedChild->FinishSettingProperties(aRefContext, aMFR); } if (mergeNeeded) { diff --git a/layout/generic/nsTextRunTransformations.h b/layout/generic/nsTextRunTransformations.h index 3a434238210a..12f7f1f06aad 100644 --- a/layout/generic/nsTextRunTransformations.h +++ b/layout/generic/nsTextRunTransformations.h @@ -27,7 +27,9 @@ public: gfxFontGroup* aFontGroup, uint32_t aFlags, nsStyleContext** aStyles, bool aOwnsFactory = true); - virtual void RebuildTextRun(nsTransformedTextRun* aTextRun, gfxContext* aRefContext) = 0; + virtual void RebuildTextRun(nsTransformedTextRun* aTextRun, + gfxContext* aRefContext, + gfxMissingFontRecorder* aMFR) = 0; }; /** @@ -48,7 +50,9 @@ public: : mInnerTransformingTextRunFactory(aInnerTransformingTextRunFactory), mAllUppercase(aAllUppercase) {} - virtual void RebuildTextRun(nsTransformedTextRun* aTextRun, gfxContext* aRefContext) MOZ_OVERRIDE; + virtual void RebuildTextRun(nsTransformedTextRun* aTextRun, + gfxContext* aRefContext, + gfxMissingFontRecorder* aMFR) MOZ_OVERRIDE; // Perform a transformation on the given string, writing the result into // aConvertedString. If aAllUppercase is true, the transform is (global) @@ -105,11 +109,12 @@ public: * are done and before we request any data from the textrun. Also always * called after a Create. */ - void FinishSettingProperties(gfxContext* aRefContext) + void FinishSettingProperties(gfxContext* aRefContext, + gfxMissingFontRecorder* aMFR) { if (mNeedsRebuild) { mNeedsRebuild = false; - mFactory->RebuildTextRun(this, aRefContext); + mFactory->RebuildTextRun(this, aRefContext, aMFR); } } diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp index 4d444c6ea628..f8141fd02a2c 100644 --- a/layout/mathml/nsMathMLChar.cpp +++ b/layout/mathml/nsMathMLChar.cpp @@ -389,7 +389,7 @@ nsPropertiesTable::MakeTextRun(gfxContext* aThebesContext, "nsPropertiesTable can only access glyphs by code point"); return aFontGroup-> MakeTextRun(aGlyph.code, aGlyph.Length(), aThebesContext, - aAppUnitsPerDevPixel, 0); + aAppUnitsPerDevPixel, 0, nullptr); } // An instance of nsOpenTypeTable is associated with one gfxFontEntry that @@ -470,7 +470,7 @@ nsOpenTypeTable::UpdateCache(gfxContext* aThebesContext, if (mCharCache != aChar) { nsAutoPtr textRun; textRun = aFontGroup-> - MakeTextRun(&aChar, 1, aThebesContext, aAppUnitsPerDevPixel, 0); + MakeTextRun(&aChar, 1, aThebesContext, aAppUnitsPerDevPixel, 0, nullptr); const gfxTextRun::CompressedGlyph& data = textRun->GetCharacterGlyphs()[0]; if (data.IsSimpleGlyph()) { mGlyphID = data.GetSimpleGlyph(); @@ -1549,7 +1549,8 @@ nsMathMLChar::StretchInternal(nsPresContext* aPresContext, nsAutoPtr textRun; textRun = fm->GetThebesFontGroup()-> MakeTextRun(static_cast(mData.get()), len, aThebesContext, - aPresContext->AppUnitsPerDevPixel(), 0); + aPresContext->AppUnitsPerDevPixel(), 0, + aPresContext->MissingFontRecorder()); aDesiredStretchSize = MeasureTextRun(aThebesContext, textRun); mGlyphs[0] = textRun; diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 767f1b9bf729..eb8856b67872 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -572,6 +572,10 @@ pref("gfx.bundled_fonts.enabled", true); pref("gfx.bundled_fonts.force-enabled", false); #endif +// Do we fire a notification about missing fonts, so the front-end can decide +// whether to try and do something about it (e.g. download additional fonts)? +pref("gfx.missing_fonts.notify", false); + pref("gfx.filter.nearest.force-enabled", false); // prefs controlling the font (name/cmap) loader that runs shortly after startup From 8cfba1533e2228c05491ce962b5539582fe8b919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Wang?= Date: Tue, 11 Nov 2014 02:37:00 -0500 Subject: [PATCH 20/47] Bug 619521 - Part 3: Send a notification for missing math fonts. r=jkitch --- layout/generic/MathMLTextRunFactory.cpp | 4 ++++ layout/mathml/nsMathMLChar.cpp | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/layout/generic/MathMLTextRunFactory.cpp b/layout/generic/MathMLTextRunFactory.cpp index ed4b31d021fc..0be1effde5ae 100644 --- a/layout/generic/MathMLTextRunFactory.cpp +++ b/layout/generic/MathMLTextRunFactory.cpp @@ -13,6 +13,7 @@ #include "nsTextFrameUtils.h" #include "nsFontMetrics.h" #include "nsDeviceContext.h" +#include "nsUnicodeScriptCodes.h" using namespace mozilla; @@ -678,6 +679,9 @@ MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, } else { // We fallback to the original character. ch2 = ch; + if (aMFR) { + aMFR->RecordScript(MOZ_SCRIPT_MATHEMATICAL_NOTATION); + } } } } diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp index f8141fd02a2c..f239ec9201a1 100644 --- a/layout/mathml/nsMathMLChar.cpp +++ b/layout/mathml/nsMathMLChar.cpp @@ -37,6 +37,7 @@ #include #include "gfxMathTable.h" +#include "nsUnicodeScriptCodes.h" using namespace mozilla; using namespace mozilla::gfx; @@ -1690,6 +1691,14 @@ nsMathMLChar::StretchInternal(nsPresContext* aPresContext, return NS_OK; } + // We did not find a size variant or a glyph assembly to stretch this + // operator. Verify whether a font with an OpenType MATH table is available + // and record missing math script otherwise. + gfxMissingFontRecorder* MFR = aPresContext->MissingFontRecorder(); + if (MFR && !fm->GetThebesFontGroup()->GetFirstMathFont()) { + MFR->RecordScript(MOZ_SCRIPT_MATHEMATICAL_NOTATION); + } + // stretchy character if (stretchy) { if (isVertical) { From 36057e75f9bca0ef0b2544e3b180f7e6ff5d87d9 Mon Sep 17 00:00:00 2001 From: Cykesiopka Date: Mon, 27 Oct 2014 21:06:00 -0400 Subject: [PATCH 21/47] Bug 1057035 - Fix terminology used in the certificate exception dialog. r=keeler --- .../locales/en-US/chrome/pippki/pippki.properties | 10 +++++----- .../manager/pki/resources/content/exceptionDialog.js | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/security/manager/locales/en-US/chrome/pippki/pippki.properties b/security/manager/locales/en-US/chrome/pippki/pippki.properties index 23f0be0dd8d9..85c29536ed65 100644 --- a/security/manager/locales/en-US/chrome/pippki/pippki.properties +++ b/security/manager/locales/en-US/chrome/pippki/pippki.properties @@ -147,17 +147,17 @@ writeFileUnknownError=Unknown error addExceptionBrandedWarning2=You are about to override how %S identifies this site. addExceptionInvalidHeader=This site attempts to identify itself with invalid information. addExceptionDomainMismatchShort=Wrong Site -addExceptionDomainMismatchLong=Certificate belongs to a different site, which could indicate an identity theft. +addExceptionDomainMismatchLong2=The certificate belongs to a different site, which could mean that someone is trying to impersonate this site. addExceptionExpiredShort=Outdated Information -addExceptionExpiredLong=Certificate is not currently valid. It is impossible to verify whether this identity was reported as stolen or lost. +addExceptionExpiredLong2=The certificate is not currently valid. It may have been stolen or lost, and could be used by someone to impersonate this site. addExceptionUnverifiedOrBadSignatureShort=Unknown Identity -addExceptionUnverifiedOrBadSignatureLong=Certificate is not trusted, because it hasn't been verified by a recognized authority using a secure signature. +addExceptionUnverifiedOrBadSignatureLong2=The certificate is not trusted because it hasn't been verified as issued by a trusted authority using a secure signature. addExceptionValidShort=Valid Certificate addExceptionValidLong=This site provides valid, verified identification. There is no need to add an exception. addExceptionCheckingShort=Checking Information -addExceptionCheckingLong=Attempting to identify the site… +addExceptionCheckingLong2=Attempting to identify this site… addExceptionNoCertShort=No Information Available -addExceptionNoCertLong=Unable to obtain identification status for the given site. +addExceptionNoCertLong2=Unable to obtain identification status for this site. addExceptionConnectionFailed=Connection Failed #Certificate Exists in database diff --git a/security/manager/pki/resources/content/exceptionDialog.js b/security/manager/pki/resources/content/exceptionDialog.js index 229500b0fe09..640791f898fc 100644 --- a/security/manager/pki/resources/content/exceptionDialog.js +++ b/security/manager/pki/resources/content/exceptionDialog.js @@ -187,11 +187,11 @@ function updateCertStatus() { if(gCert) { if(gBroken) { var mms = "addExceptionDomainMismatchShort"; - var mml = "addExceptionDomainMismatchLong"; + var mml = "addExceptionDomainMismatchLong2"; var exs = "addExceptionExpiredShort"; - var exl = "addExceptionExpiredLong"; + var exl = "addExceptionExpiredLong2"; var uts = "addExceptionUnverifiedOrBadSignatureShort"; - var utl = "addExceptionUnverifiedOrBadSignatureLong"; + var utl = "addExceptionUnverifiedOrBadSignatureLong2"; var use1 = false; if (gSSLStatus.isDomainMismatch) { bucketId += gNsISecTel.WARNING_BAD_CERT_TOP_ADD_EXCEPTION_FLAG_DOMAIN; @@ -263,7 +263,7 @@ function updateCertStatus() { } else if (gChecking) { shortDesc = "addExceptionCheckingShort"; - longDesc = "addExceptionCheckingLong"; + longDesc = "addExceptionCheckingLong2"; // We're checking the certificate, so we disable the Get Certificate // button to make sure that the user can't interrupt the process and // trigger another certificate fetch. @@ -274,7 +274,7 @@ function updateCertStatus() { } else { shortDesc = "addExceptionNoCertShort"; - longDesc = "addExceptionNoCertLong"; + longDesc = "addExceptionNoCertLong2"; // We're done checking the certificate, so allow the user to check it again. document.getElementById("checkCertButton").disabled = false; document.getElementById("viewCertButton").disabled = true; From 87c2435185aaa1dd4406a19b69e26454e91480fa Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 29 Sep 2014 03:43:00 -0400 Subject: [PATCH 22/47] Bug 1073615 - One MediaStreamGraph singleton per audioChannel. r=roc --- dom/media/MediaStreamGraph.cpp | 49 ++++++++++++++----- dom/media/MediaStreamGraphImpl.h | 5 ++ dom/media/webaudio/AudioContext.cpp | 6 --- dom/media/webaudio/AudioContext.h | 1 - .../webaudio/test/test_mozaudiochannel.html | 18 +++---- dom/webidl/AudioContext.webidl | 4 +- 6 files changed, 50 insertions(+), 33 deletions(-) diff --git a/dom/media/MediaStreamGraph.cpp b/dom/media/MediaStreamGraph.cpp index d73dc3280f73..b6ca0bbec680 100644 --- a/dom/media/MediaStreamGraph.cpp +++ b/dom/media/MediaStreamGraph.cpp @@ -65,7 +65,7 @@ PRLogModuleInfo* gMediaStreamGraphLog; /** * The singleton graph instance. */ -static MediaStreamGraphImpl* gGraph; +static nsDataHashtable gGraphs; MediaStreamGraphImpl::~MediaStreamGraphImpl() { @@ -1636,9 +1636,10 @@ MediaStreamGraphImpl::RunInStableState(bool aSourceIsMSG) NS_DispatchToMainThread(event); LIFECYCLE_LOG("Disconnecting MediaStreamGraph %p", this); - if (this == gGraph) { + MediaStreamGraphImpl* graph; + if (gGraphs.Get(mAudioChannel, &graph) && graph == this) { // null out gGraph if that's the graph being shut down - gGraph = nullptr; + gGraphs.Remove(mAudioChannel); } } } else { @@ -1789,9 +1790,12 @@ MediaStreamGraphImpl::AppendMessage(ControlMessage* aMessage) delete aMessage; if (IsEmpty() && mLifecycleState >= LIFECYCLE_WAITING_FOR_STREAM_DESTRUCTION) { - if (gGraph == this) { - gGraph = nullptr; + + MediaStreamGraphImpl* graph; + if (gGraphs.Get(mAudioChannel, &graph) && graph == this) { + gGraphs.Remove(mAudioChannel); } + Destroy(); } return; @@ -2741,6 +2745,7 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(bool aRealtime, #ifdef DEBUG , mCanRunMessagesSynchronously(false) #endif + , mAudioChannel(static_cast(aChannel)) { #ifdef PR_LOGGING if (!gMediaStreamGraphLog) { @@ -2779,15 +2784,26 @@ NS_IMPL_ISUPPORTS(MediaStreamGraphShutdownObserver, nsIObserver) static bool gShutdownObserverRegistered = false; +namespace { + +PLDHashOperator +ForceShutdownEnumerator(const uint32_t& /* aAudioChannel */, + MediaStreamGraphImpl* aGraph, + void* /* aUnused */) +{ + aGraph->ForceShutDown(); + return PL_DHASH_NEXT; +} + +} // anonymous namespace + NS_IMETHODIMP MediaStreamGraphShutdownObserver::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData) { if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) { - if (gGraph) { - gGraph->ForceShutDown(); - } + gGraphs.EnumerateRead(ForceShutdownEnumerator, nullptr); nsContentUtils::UnregisterShutdownObserver(this); gShutdownObserverRegistered = false; } @@ -2799,7 +2815,10 @@ MediaStreamGraph::GetInstance(DOMMediaStream::TrackTypeHints aHint, dom::AudioCh { NS_ASSERTION(NS_IsMainThread(), "Main thread only"); - if (!gGraph) { + uint32_t channel = static_cast(aChannel); + MediaStreamGraphImpl* graph = nullptr; + + if (!gGraphs.Get(channel, &graph)) { if (!gShutdownObserverRegistered) { gShutdownObserverRegistered = true; nsContentUtils::RegisterShutdownObserver(new MediaStreamGraphShutdownObserver()); @@ -2807,12 +2826,13 @@ MediaStreamGraph::GetInstance(DOMMediaStream::TrackTypeHints aHint, dom::AudioCh CubebUtils::InitPreferredSampleRate(); - gGraph = new MediaStreamGraphImpl(true, CubebUtils::PreferredSampleRate(), aHint, aChannel); + graph = new MediaStreamGraphImpl(true, CubebUtils::PreferredSampleRate(), aHint, aChannel); + gGraphs.Put(channel, graph); - STREAM_LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", gGraph)); + STREAM_LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", graph)); } - return gGraph; + return graph; } MediaStreamGraph* @@ -2995,7 +3015,10 @@ MediaStreamGraph::CreateAudioNodeStream(AudioNodeEngine* aEngine, bool MediaStreamGraph::IsNonRealtime() const { - return this != gGraph; + const MediaStreamGraphImpl* impl = static_cast(this); + MediaStreamGraphImpl* graph; + + return !gGraphs.Get(impl->AudioChannel(), &graph) || graph != impl; } void diff --git a/dom/media/MediaStreamGraphImpl.h b/dom/media/MediaStreamGraphImpl.h index 628f327557b8..f7fbe2887cde 100644 --- a/dom/media/MediaStreamGraphImpl.h +++ b/dom/media/MediaStreamGraphImpl.h @@ -661,6 +661,8 @@ public: nsRefPtr mFarendObserverRef; #endif + uint32_t AudioChannel() const { return mAudioChannel; } + private: virtual ~MediaStreamGraphImpl(); @@ -694,6 +696,9 @@ private: bool mCanRunMessagesSynchronously; #endif + // We use uint32_t instead AudioChannel because this is just used as key for + // the hashtable gGraphs. + uint32_t mAudioChannel; }; } diff --git a/dom/media/webaudio/AudioContext.cpp b/dom/media/webaudio/AudioContext.cpp index 8cfb65de65bf..8fc28b368a65 100644 --- a/dom/media/webaudio/AudioContext.cpp +++ b/dom/media/webaudio/AudioContext.cpp @@ -654,12 +654,6 @@ AudioContext::MozAudioChannelType() const return mDestination->MozAudioChannelType(); } -void -AudioContext::SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv) -{ - mDestination->SetMozAudioChannelType(aValue, aRv); -} - AudioChannel AudioContext::TestAudioChannelInAudioNodeStream() { diff --git a/dom/media/webaudio/AudioContext.h b/dom/media/webaudio/AudioContext.h index 42dda249ca4b..ecac9ae107f6 100644 --- a/dom/media/webaudio/AudioContext.h +++ b/dom/media/webaudio/AudioContext.h @@ -222,7 +222,6 @@ public: JSObject* GetGlobalJSObject() const; AudioChannel MozAudioChannelType() const; - void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv); AudioChannel TestAudioChannelInAudioNodeStream(); diff --git a/dom/media/webaudio/test/test_mozaudiochannel.html b/dom/media/webaudio/test/test_mozaudiochannel.html index bfe19b33bb34..be6794432bea 100644 --- a/dom/media/webaudio/test/test_mozaudiochannel.html +++ b/dom/media/webaudio/test/test_mozaudiochannel.html @@ -18,27 +18,23 @@ function test_basic() { // Default is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); - // random wrong channel - ac.mozAudioChannelType = "foo"; - is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); - // Unpermitted channels - ac.mozAudioChannelType = "content"; + ac = new AudioContext("content"); is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); - ac.mozAudioChannelType = "notification"; + ac = new AudioContext("notification"); is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); - ac.mozAudioChannelType = "alarm"; + ac = new AudioContext("alarm"); is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); - ac.mozAudioChannelType = "telephony"; + ac = new AudioContext("telephony"); is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); - ac.mozAudioChannelType = "ringer"; + ac = new AudioContext("ringer"); is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); - ac.mozAudioChannelType = "publicnotification"; + ac = new AudioContext("publicnotification"); is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); runTest(); @@ -56,7 +52,7 @@ function test_permission(aChannel) { SpecialPowers.pushPermissions( [{ "type": "audio-channel-" + aChannel, "allow": true, "context": document }], function() { - ac.mozAudioChannelType = aChannel; + var ac = new AudioContext(aChannel); is(ac.mozAudioChannelType, aChannel, "Default ac channel == '" + aChannel + "'"); var channel = SpecialPowers.wrap(ac).testAudioChannelInAudioNodeStream(); diff --git a/dom/webidl/AudioContext.webidl b/dom/webidl/AudioContext.webidl index bf51646abfee..6ad60b850a8b 100644 --- a/dom/webidl/AudioContext.webidl +++ b/dom/webidl/AudioContext.webidl @@ -78,8 +78,8 @@ interface AudioContext : EventTarget { // Mozilla extensions partial interface AudioContext { // Read AudioChannel.webidl for more information about this attribute. - [Pref="media.useAudioChannelService", SetterThrows] - attribute AudioChannel mozAudioChannelType; + [Pref="media.useAudioChannelService"] + readonly attribute AudioChannel mozAudioChannelType; // These 2 events are dispatched when the AudioContext object is muted by // the AudioChannelService. It's call 'interrupt' because when this event is From 86f277bb366e416a0d7fccacb6ef410a606160e6 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Mon, 3 Nov 2014 16:50:00 -0500 Subject: [PATCH 23/47] Bug 1093278 - Null check in nsPurpleBuffer::VisitEntries. r=smaug --- xpcom/base/nsCycleCollector.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 60fa05a7fb42..1d5c09943c83 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -998,7 +998,8 @@ private: { nsPurpleBufferEntry* eEnd = ArrayEnd(mEntries); for (nsPurpleBufferEntry* e = mEntries; e != eEnd; ++e) { - if (!(uintptr_t(e->mObject) & uintptr_t(1))) { + MOZ_ASSERT(e->mObject, "There should be no null mObject when we iterate over the purple buffer"); + if (!(uintptr_t(e->mObject) & uintptr_t(1)) && e->mObject) { aVisitor.Visit(aBuffer, e); } } From 8814819fc4a5a9620c54a25c8dd1d504bc842cd5 Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Sat, 8 Nov 2014 16:32:00 -0500 Subject: [PATCH 24/47] Bug 1095299 - Change a few 'const' to 'var' since they are used in other scopes. r=efaust --- toolkit/components/filepicker/content/filepicker.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/toolkit/components/filepicker/content/filepicker.js b/toolkit/components/filepicker/content/filepicker.js index e6552e8aaef9..117f9994a5c0 100644 --- a/toolkit/components/filepicker/content/filepicker.js +++ b/toolkit/components/filepicker/content/filepicker.js @@ -45,13 +45,13 @@ function filepickerLoad() { const title = o.title; filePickerMode = o.mode; if (o.displayDirectory) { - const directory = o.displayDirectory.path; + var directory = o.displayDirectory.path; } const initialText = o.defaultString; - const filterTitles = o.filters.titles; - const filterTypes = o.filters.types; - const numFilters = filterTitles.length; + var filterTitles = o.filters.titles; + var filterTypes = o.filters.types; + var numFilters = filterTitles.length; document.title = title; allowURLs = o.allowURLs; From e05d4dd477126fb076fda5d0361da93a89b16425 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Tue, 11 Nov 2014 08:46:06 -0800 Subject: [PATCH 25/47] (no bug) Minor whitespace cleanup in nsImageFrame.cpp. whitespace-only, so DONTBUILD --- layout/generic/nsImageFrame.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 96f97bf4f27d..b3d4e615508d 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -106,16 +106,17 @@ static bool HaveFixedSize(const nsStylePosition* aStylePosition) return aStylePosition->mWidth.IsCoordPercentCalcUnit() && aStylePosition->mHeight.IsCoordPercentCalcUnit(); } + // use the data in the reflow state to decide if the image has a constrained size -// (i.e. width and height that are based on the containing block size and not the image size) +// (i.e. width and height that are based on the containing block size and not the image size) // so we can avoid animated GIF related reflows inline bool HaveFixedSize(const nsHTMLReflowState& aReflowState) -{ +{ NS_ASSERTION(aReflowState.mStylePosition, "crappy reflowState - null stylePosition"); - // when an image has percent css style height or width, but ComputedHeight() - // or ComputedWidth() of reflow state is NS_UNCONSTRAINEDSIZE + // when an image has percent css style height or width, but ComputedHeight() + // or ComputedWidth() of reflow state is NS_UNCONSTRAINEDSIZE // it needs to return false to cause an incremental reflow later - // if an image is inside table like bug 156731 simple testcase III, + // if an image is inside table like bug 156731 simple testcase III, // during pass 1 reflow, ComputedWidth() is NS_UNCONSTRAINEDSIZE // in pass 2 reflow, ComputedWidth() is 0, it also needs to return false // see bug 156731 @@ -127,7 +128,7 @@ inline bool HaveFixedSize(const nsHTMLReflowState& aReflowState) (NS_UNCONSTRAINEDSIZE == aReflowState.ComputedWidth() || 0 == aReflowState.ComputedWidth()))) ? false - : HaveFixedSize(aReflowState.mStylePosition); + : HaveFixedSize(aReflowState.mStylePosition); } nsIFrame* From 1d7a29d2b3eb83c4262eb948432c13ec15fb0f1c Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Tue, 11 Nov 2014 08:46:49 -0800 Subject: [PATCH 26/47] Bug 1041075 followup: Request even-longer timeout for test_value_storage.html. r=dbaron --- layout/style/test/test_value_storage.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout/style/test/test_value_storage.html b/layout/style/test/test_value_storage.html index 46985c8c8d4d..494e76f1273c 100644 --- a/layout/style/test/test_value_storage.html +++ b/layout/style/test/test_value_storage.html @@ -314,7 +314,7 @@ function runTest() { } SimpleTest.waitForExplicitFinish(); -SimpleTest.requestLongerTimeout(3); +SimpleTest.requestLongerTimeout(4); SpecialPowers.pushPrefEnv({ set: [["layout.css.variables.enabled", true]] }, runTest); From d640179104d163d2707d750306ba5d851c089f29 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Tue, 11 Nov 2014 17:50:42 +0100 Subject: [PATCH 27/47] Bug 1093573 part 7 - Allow OSR for generator scripts. r=wingo --- js/src/jit/BaselineJIT.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp index 8d9c2f55eb3c..36d3ab90ecbf 100644 --- a/js/src/jit/BaselineJIT.cpp +++ b/js/src/jit/BaselineJIT.cpp @@ -60,11 +60,6 @@ static const unsigned BASELINE_MAX_ARGS_LENGTH = 20000; static bool CheckFrame(InterpreterFrame *fp) { - if (fp->script()->isGenerator()) { - JitSpew(JitSpew_BaselineAbort, "generator frame"); - return false; - } - if (fp->isDebuggerFrame()) { // Debugger eval-in-frame. These are likely short-running scripts so // don't bother compiling them for now. From c980c9545ac08bce5c755d54dd1e57e6be52a219 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Tue, 11 Nov 2014 17:50:44 +0100 Subject: [PATCH 28/47] Bug 1093573 part 8 - Add JitFrame_Unwound_BaselineJS. r=nbp --- js/src/jit/Ion.cpp | 1 + js/src/jit/IonFrames-inl.h | 1 + js/src/jit/IonFrames.cpp | 12 ++++++++++++ js/src/jit/JitFrameIterator.h | 1 + 4 files changed, 15 insertions(+) diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 6a4f458c3289..c820f55d7b55 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -2608,6 +2608,7 @@ InvalidateActivation(FreeOp *fop, const JitActivationIterator &activations, bool JitSpew(JitSpew_IonInvalidate, "#%d rectifier frame @ %p", frameno, it.fp()); break; case JitFrame_Unwound_IonJS: + case JitFrame_Unwound_BaselineJS: case JitFrame_Unwound_BaselineStub: MOZ_CRASH("invalid"); case JitFrame_Unwound_Rectifier: diff --git a/js/src/jit/IonFrames-inl.h b/js/src/jit/IonFrames-inl.h index 47a0994fd480..f674984466c2 100644 --- a/js/src/jit/IonFrames-inl.h +++ b/js/src/jit/IonFrames-inl.h @@ -54,6 +54,7 @@ JitFrameIterator::isFakeExitFrame() const { bool res = (prevType() == JitFrame_Unwound_Rectifier || prevType() == JitFrame_Unwound_IonJS || + prevType() == JitFrame_Unwound_BaselineJS || prevType() == JitFrame_Unwound_BaselineStub || (prevType() == JitFrame_Entry && type() == JitFrame_Exit)); MOZ_ASSERT_IF(res, type() == JitFrame_Exit || type() == JitFrame_BaselineJS); diff --git a/js/src/jit/IonFrames.cpp b/js/src/jit/IonFrames.cpp index fbfc919e2f59..90faf61401d0 100644 --- a/js/src/jit/IonFrames.cpp +++ b/js/src/jit/IonFrames.cpp @@ -280,6 +280,7 @@ SizeOfFramePrefix(FrameType type) case JitFrame_BaselineJS: case JitFrame_IonJS: case JitFrame_Bailout: + case JitFrame_Unwound_BaselineJS: case JitFrame_Unwound_IonJS: return IonJSFrameLayout::Size(); case JitFrame_BaselineStub: @@ -332,6 +333,8 @@ JitFrameIterator::operator++() type_ = current()->prevType(); if (type_ == JitFrame_Unwound_IonJS) type_ = JitFrame_IonJS; + else if (type_ == JitFrame_Unwound_BaselineJS) + type_ = JitFrame_BaselineJS; else if (type_ == JitFrame_Unwound_BaselineStub) type_ = JitFrame_BaselineStub; returnAddressToFp_ = current()->returnAddress(); @@ -808,6 +811,7 @@ void EnsureExitFrame(IonCommonFrameLayout *frame) { if (frame->prevType() == JitFrame_Unwound_IonJS || + frame->prevType() == JitFrame_Unwound_BaselineJS || frame->prevType() == JitFrame_Unwound_BaselineStub || frame->prevType() == JitFrame_Unwound_Rectifier) { @@ -835,6 +839,12 @@ EnsureExitFrame(IonCommonFrameLayout *frame) return; } + + if (frame->prevType() == JitFrame_BaselineJS) { + frame->changePrevType(JitFrame_Unwound_BaselineJS); + return; + } + MOZ_ASSERT(frame->prevType() == JitFrame_IonJS); frame->changePrevType(JitFrame_Unwound_IonJS); } @@ -1357,6 +1367,7 @@ MarkJitActivation(JSTracer *trc, const JitActivationIterator &activations) MarkBailoutFrame(trc, frames); break; case JitFrame_Unwound_IonJS: + case JitFrame_Unwound_BaselineJS: MOZ_CRASH("invalid"); case JitFrame_Rectifier: MarkRectifierFrame(trc, frames); @@ -2506,6 +2517,7 @@ JitFrameIterator::dump() const fprintf(stderr, " Frame size: %u\n", unsigned(current()->prevFrameLocalSize())); break; case JitFrame_Unwound_IonJS: + case JitFrame_Unwound_BaselineJS: fprintf(stderr, "Warning! Unwound JS frames are not observable.\n"); break; case JitFrame_Exit: diff --git a/js/src/jit/JitFrameIterator.h b/js/src/jit/JitFrameIterator.h index f560969adab6..447c560fa7e5 100644 --- a/js/src/jit/JitFrameIterator.h +++ b/js/src/jit/JitFrameIterator.h @@ -45,6 +45,7 @@ enum FrameType // An unwound JS frame is a JS frame signalling that its callee frame has been // turned into an exit frame (see EnsureExitFrame). Used by Ion bailouts and // Baseline exception unwinding. + JitFrame_Unwound_BaselineJS, JitFrame_Unwound_IonJS, // Like Unwound_IonJS, but the caller is a baseline stub frame. From 3cdd90a43fb7e0f71db85f43a38f39a6249c24f1 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Tue, 11 Nov 2014 17:13:50 +0000 Subject: [PATCH 29/47] Bug 1081453 - SessionHistory should not keep alive the DOM file objects, r=smaug --- dom/base/test/mochitest.ini | 1 - dom/html/HTMLInputElement.cpp | 28 ++++++++++++++++++++-------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index 79b75df1063a..c8c813816a46 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -385,7 +385,6 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' || (os == 'linux' && debug & [test_bug340571.html] [test_bug343596.html] [test_bug345339.html] -skip-if = e10s # Bug 1081453 - shutdown leaks with e10s and WebIDL dom::File [test_bug346485.html] [test_bug352728.html] [test_bug352728.xhtml] diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index a02236377eb9..d04d54104b21 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -236,13 +236,15 @@ class HTMLInputElementState MOZ_FINAL : public nsISupports mValue = aValue; } - const nsTArray>& GetFiles() { - return mFiles; + const nsTArray>& GetFileImpls() { + return mFileImpls; } - void SetFiles(const nsTArray>& aFiles) { - mFiles.Clear(); - mFiles.AppendElements(aFiles); + void SetFileImpls(const nsTArray>& aFile) { + mFileImpls.Clear(); + for (uint32_t i = 0, len = aFile.Length(); i < len; ++i) { + mFileImpls.AppendElement(aFile[i]->Impl()); + } } HTMLInputElementState() @@ -255,7 +257,7 @@ class HTMLInputElementState MOZ_FINAL : public nsISupports ~HTMLInputElementState() {} nsString mValue; - nsTArray> mFiles; + nsTArray> mFileImpls; bool mChecked; bool mCheckedSet; }; @@ -5697,7 +5699,7 @@ HTMLInputElement::SaveState() case VALUE_MODE_FILENAME: if (!mFiles.IsEmpty()) { inputState = new HTMLInputElementState(); - inputState->SetFiles(mFiles); + inputState->SetFileImpls(mFiles); } break; case VALUE_MODE_VALUE: @@ -5900,7 +5902,17 @@ HTMLInputElement::RestoreState(nsPresState* aState) break; case VALUE_MODE_FILENAME: { - const nsTArray>& files = inputState->GetFiles(); + const nsTArray>& fileImpls = inputState->GetFileImpls(); + + nsCOMPtr global = OwnerDoc()->GetScopeObject(); + MOZ_ASSERT(global); + + nsTArray> files; + for (uint32_t i = 0, len = fileImpls.Length(); i < len; ++i) { + nsRefPtr file = new File(global, fileImpls[i]); + files.AppendElement(file); + } + SetFiles(files, true); } break; From 0e8197c00f20e3be48cfc23254a1b62e78e6ac54 Mon Sep 17 00:00:00 2001 From: Christoph Kerschbaumer Date: Wed, 5 Nov 2014 17:45:54 -0800 Subject: [PATCH 30/47] Bug 826805 - CSP: Allow http and https for scheme-less sources (r=dveditz) --- dom/base/nsCSPParser.cpp | 15 ++++++++++----- dom/base/nsCSPUtils.cpp | 23 ++++++++++++++++++++--- dom/base/nsCSPUtils.h | 3 ++- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/dom/base/nsCSPParser.cpp b/dom/base/nsCSPParser.cpp index 3fe7207492e8..9ff6c6143471 100644 --- a/dom/base/nsCSPParser.cpp +++ b/dom/base/nsCSPParser.cpp @@ -646,21 +646,26 @@ nsCSPParser::sourceExpression() // mCurValue = "" resetCurValue(); - // If mCurToken does not provide a scheme, we apply the scheme from selfURI + // If mCurToken does not provide a scheme (scheme-less source), we apply the scheme + // from selfURI but we also need to remember if the protected resource is http, in + // which case we should allow https loads, see: + // http://www.w3.org/TR/CSP2/#match-source-expression + bool allowHttps = false; if (parsedScheme.IsEmpty()) { // Resetting internal helpers, because we might already have parsed some of the host // when trying to parse a scheme. resetCurChar(mCurToken); - nsAutoCString scheme; - mSelfURI->GetScheme(scheme); - parsedScheme.AssignASCII(scheme.get()); + nsAutoCString selfScheme; + mSelfURI->GetScheme(selfScheme); + parsedScheme.AssignASCII(selfScheme.get()); + allowHttps = selfScheme.EqualsASCII("http"); } // At this point we are expecting a host to be parsed. // Trying to create a new nsCSPHost. if (nsCSPHostSrc *cspHost = hostSource()) { // Do not forget to set the parsed scheme. - cspHost->setScheme(parsedScheme); + cspHost->setScheme(parsedScheme, allowHttps); return cspHost; } // Error was reported in hostSource() diff --git a/dom/base/nsCSPUtils.cpp b/dom/base/nsCSPUtils.cpp index fb8b30e54b01..30efd02cbfa6 100644 --- a/dom/base/nsCSPUtils.cpp +++ b/dom/base/nsCSPUtils.cpp @@ -279,6 +279,7 @@ nsCSPSchemeSrc::toString(nsAString& outStr) const nsCSPHostSrc::nsCSPHostSrc(const nsAString& aHost) : mHost(aHost) + , mAllowHttps(false) { ToLowerCase(mHost); } @@ -307,7 +308,16 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected NS_ENSURE_SUCCESS(rv, false); if (!mScheme.IsEmpty() && !mScheme.EqualsASCII(scheme.get())) { - return false; + + // We should not return false for scheme-less sources where the protected resource + // is http and the load is https, see: + // http://www.w3.org/TR/CSP2/#match-source-expression + bool isHttpsScheme = + (NS_SUCCEEDED(aUri->SchemeIs("https", &isHttpsScheme)) && isHttpsScheme); + + if (!(isHttpsScheme && mAllowHttps)) { + return false; + } } // The host in nsCSpHostSrc should never be empty. In case we are enforcing @@ -386,7 +396,13 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected if (mPort.IsEmpty()) { int32_t port = NS_GetDefaultPort(NS_ConvertUTF16toUTF8(mScheme).get()); if (port != uriPort) { - return false; + // We should not return false for scheme-less sources where the protected resource + // is http and the load is https, see: http://www.w3.org/TR/CSP2/#match-source-expression + // BUT, we only allow scheme-less sources to be upgraded from http to https if CSP + // does not explicitly define a port. + if (!(uriPort == NS_GetDefaultPort("https") && mAllowHttps)) { + return false; + } } } // 4.7) Port matching: Compare the ports. @@ -431,10 +447,11 @@ nsCSPHostSrc::toString(nsAString& outStr) const } void -nsCSPHostSrc::setScheme(const nsAString& aScheme) +nsCSPHostSrc::setScheme(const nsAString& aScheme, bool aAllowHttps) { mScheme = aScheme; ToLowerCase(mScheme); + mAllowHttps = aAllowHttps; } void diff --git a/dom/base/nsCSPUtils.h b/dom/base/nsCSPUtils.h index bed6e282a52b..a1510c408153 100644 --- a/dom/base/nsCSPUtils.h +++ b/dom/base/nsCSPUtils.h @@ -220,7 +220,7 @@ class nsCSPHostSrc : public nsCSPBaseSrc { bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const; void toString(nsAString& outStr) const; - void setScheme(const nsAString& aScheme); + void setScheme(const nsAString& aScheme, bool aAllowHttps = false); void setPort(const nsAString& aPort); void appendPath(const nsAString &aPath); @@ -229,6 +229,7 @@ class nsCSPHostSrc : public nsCSPBaseSrc { nsString mHost; nsString mPort; nsString mPath; + bool mAllowHttps; }; /* =============== nsCSPKeywordSrc ============ */ From 10bf435a3724164593c8cc905e39dc9bfe324b02 Mon Sep 17 00:00:00 2001 From: Christoph Kerschbaumer Date: Wed, 5 Nov 2014 20:46:41 -0800 Subject: [PATCH 31/47] Bug 826805 - CSP: Allow http and https for scheme-less sources, tests (r=dveditz) --- .../csp/file_csp_allow_https_schemes.html | 14 ++++ dom/base/test/csp/mochitest.ini | 3 + .../csp/test_csp_allow_https_schemes.html | 71 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 dom/base/test/csp/file_csp_allow_https_schemes.html create mode 100644 dom/base/test/csp/test_csp_allow_https_schemes.html diff --git a/dom/base/test/csp/file_csp_allow_https_schemes.html b/dom/base/test/csp/file_csp_allow_https_schemes.html new file mode 100644 index 000000000000..96dab5013a98 --- /dev/null +++ b/dom/base/test/csp/file_csp_allow_https_schemes.html @@ -0,0 +1,14 @@ + + + + Bug 826805 - CSP: Allow http and https for scheme-less sources + + +
blocked
+ + + + diff --git a/dom/base/test/csp/mochitest.ini b/dom/base/test/csp/mochitest.ini index 6c99d1bf46d1..3c717dc4bc27 100644 --- a/dom/base/test/csp/mochitest.ini +++ b/dom/base/test/csp/mochitest.ini @@ -4,6 +4,7 @@ support-files = file_connect-src.html file_CSP.css file_CSP.sjs + file_csp_allow_https_schemes.html file_CSP_bug663567.xsl file_CSP_bug663567_allows.xml file_CSP_bug663567_allows.xml^headers^ @@ -103,6 +104,8 @@ support-files = [test_base-uri.html] [test_connect-src.html] [test_CSP.html] +[test_csp_allow_https_schemes.html] +skip-if = buildapp == 'b2g' #no ssl support [test_CSP_bug663567.html] [test_CSP_bug802872.html] [test_CSP_bug885433.html] diff --git a/dom/base/test/csp/test_csp_allow_https_schemes.html b/dom/base/test/csp/test_csp_allow_https_schemes.html new file mode 100644 index 000000000000..a7784f5d2073 --- /dev/null +++ b/dom/base/test/csp/test_csp_allow_https_schemes.html @@ -0,0 +1,71 @@ + + + + Bug 826805 - Allow http and https for scheme-less sources + + + + + +

+ + + + + From 05c89cfccf1b5b8d5589943cc681200582a6c66b Mon Sep 17 00:00:00 2001 From: Christoph Kerschbaumer Date: Mon, 10 Nov 2014 08:51:39 -0800 Subject: [PATCH 32/47] Bug 1096396 - CSP: Fix test_connect-src by adding return after SimpleTest.finish() (r=dveditz) --- dom/base/test/csp/test_connect-src.html | 1 + 1 file changed, 1 insertion(+) diff --git a/dom/base/test/csp/test_connect-src.html b/dom/base/test/csp/test_connect-src.html index f271917afac4..837065e976b3 100644 --- a/dom/base/test/csp/test_connect-src.html +++ b/dom/base/test/csp/test_connect-src.html @@ -91,6 +91,7 @@ function loadNextTest() { if (counter == tests.length) { window.ConnectSrcExaminer.remove(); SimpleTest.finish(); + return; } var src = "file_csp_testserver.sjs"; From be9296a80d31822f66123396008374263d25763e Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Tue, 11 Nov 2014 12:47:36 -0500 Subject: [PATCH 33/47] Bug 1090616. Don't assume that the nodes we just pasted are still in the DOM, because mutation listeners suck like that. r=smaug --- editor/libeditor/nsHTMLDataTransfer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/editor/libeditor/nsHTMLDataTransfer.cpp b/editor/libeditor/nsHTMLDataTransfer.cpp index 381bba35dd20..85b630bd410f 100644 --- a/editor/libeditor/nsHTMLDataTransfer.cpp +++ b/editor/libeditor/nsHTMLDataTransfer.cpp @@ -655,6 +655,9 @@ nsHTMLEditor::DoInsertHTMLWithContext(const nsAString & aInputString, { tmp = selNode; selNode = GetNodeLocation(tmp, &selOffset); + // selNode might be null in case a mutation listener removed + // the stuff we just inserted from the DOM. + NS_ENSURE_STATE(selNode); ++selOffset; // want to be *after* last leaf node in paste } From 6dd0aff8b660ac4187d125afb159e745d42b1c7e Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Tue, 11 Nov 2014 12:50:43 -0500 Subject: [PATCH 34/47] Bug 1095870. Don't generate baseline set IC stubs for primitive 'this' values, since all the stubs only work on objects. r=jandem --- js/src/jit-test/tests/baseline/bug1095870.js | 4 ++++ js/src/jit/BaselineIC.cpp | 2 ++ 2 files changed, 6 insertions(+) create mode 100644 js/src/jit-test/tests/baseline/bug1095870.js diff --git a/js/src/jit-test/tests/baseline/bug1095870.js b/js/src/jit-test/tests/baseline/bug1095870.js new file mode 100644 index 000000000000..e75cbbe5dc00 --- /dev/null +++ b/js/src/jit-test/tests/baseline/bug1095870.js @@ -0,0 +1,4 @@ +// |jit-test| ion-eager; +for (var j = 0; j < 2; j++) { + (false).__proto__ = 0 +} diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index d0322d190fdc..497a45a2f3a7 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -7921,6 +7921,7 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_ // end up attaching a stub for the exact same access later. bool isTemporarilyUnoptimizable = false; if (stub->numOptimizedStubs() < ICSetProp_Fallback::MAX_OPTIMIZED_STUBS && + lhs.isObject() && !TryAttachSetAccessorPropStub(cx, script, pc, stub, obj, oldShape, name, id, rhs, &attached, &isTemporarilyUnoptimizable)) { @@ -7963,6 +7964,7 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_ } if (!attached && + lhs.isObject() && !TryAttachSetValuePropStub(cx, script, pc, stub, obj, oldShape, oldType, oldSlots, name, id, rhs, &attached)) { From 8d432fef904c44acf721c2c34e49d9564ede639f Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Tue, 11 Nov 2014 13:10:56 -0500 Subject: [PATCH 35/47] Backed out changesets 857063c82323 and a19479860eb4 (bug 619521) for Valgrind failures. CLOSED TREE --- dom/canvas/CanvasRenderingContext2D.cpp | 23 +----- gfx/src/nsFontMetrics.cpp | 6 +- gfx/thebes/gfxTextRun.cpp | 90 +++------------------ gfx/thebes/gfxTextRun.h | 69 ++-------------- layout/base/nsPresContext.cpp | 30 ------- layout/base/nsPresContext.h | 6 -- layout/base/nsPresShell.cpp | 2 - layout/generic/MathMLTextRunFactory.cpp | 11 +-- layout/generic/MathMLTextRunFactory.h | 3 +- layout/generic/nsTextFrame.cpp | 25 +++--- layout/generic/nsTextRunTransformations.cpp | 6 +- layout/generic/nsTextRunTransformations.h | 13 +-- layout/mathml/nsMathMLChar.cpp | 16 +--- modules/libpref/init/all.js | 4 - 14 files changed, 45 insertions(+), 259 deletions(-) diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index c2897312165a..e9efda6bf5ad 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -3083,22 +3083,6 @@ CanvasRenderingContext2D::GetHitRegionRect(Element* aElement, nsRect& aRect) */ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcessor { - CanvasBidiProcessor() - : nsBidiPresUtils::BidiProcessor() - { - if (Preferences::GetBool(GFX_MISSING_FONTS_NOTIFY_PREF)) { - mMissingFonts = new gfxMissingFontRecorder(); - } - } - - ~CanvasBidiProcessor() - { - // notify front-end code if we encountered missing glyphs in any script - if (mMissingFonts) { - mMissingFonts->Flush(); - } - } - typedef CanvasRenderingContext2D::ContextState ContextState; virtual void SetText(const char16_t* text, int32_t length, nsBidiDirection direction) @@ -3115,8 +3099,7 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess length, mThebes, mAppUnitsPerDevPixel, - flags, - mMissingFonts); + flags); } virtual nscoord GetWidth() @@ -3354,10 +3337,6 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess // current font gfxFontGroup* mFontgrp; - // to record any unsupported characters found in the text, - // and notify front-end if it is interested - nsAutoPtr mMissingFonts; - // dev pixel conversion factor int32_t mAppUnitsPerDevPixel; diff --git a/gfx/src/nsFontMetrics.cpp b/gfx/src/nsFontMetrics.cpp index f8d2fcbfb933..95f2c4c5a30c 100644 --- a/gfx/src/nsFontMetrics.cpp +++ b/gfx/src/nsFontMetrics.cpp @@ -33,8 +33,7 @@ public: reinterpret_cast(aString), aLength, aRC->ThebesContext(), aMetrics->AppUnitsPerDevPixel(), - ComputeFlags(aMetrics), - nullptr); + ComputeFlags(aMetrics)); } AutoTextRun(nsFontMetrics* aMetrics, nsRenderingContext* aRC, @@ -44,8 +43,7 @@ public: aString, aLength, aRC->ThebesContext(), aMetrics->AppUnitsPerDevPixel(), - ComputeFlags(aMetrics), - nullptr); + ComputeFlags(aMetrics)); } gfxTextRun *get() { return mTextRun; } diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index 0c98ed6839b2..21ce71f129ee 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -28,7 +28,6 @@ using namespace mozilla; using namespace mozilla::gfx; using namespace mozilla::unicode; -using mozilla::services::GetObserverService; static const char16_t kEllipsisChar[] = { 0x2026, 0x0 }; static const char16_t kASCIIPeriodsChar[] = { '.', '.', '.', 0x0 }; @@ -2039,12 +2038,12 @@ gfxFontGroup::MakeHyphenTextRun(gfxContext *aCtx, uint32_t aAppUnitsPerDevUnit) gfxFont *font = GetFirstValidFont(uint32_t(hyphen)); if (font->HasCharacter(hyphen)) { return MakeTextRun(&hyphen, 1, aCtx, aAppUnitsPerDevUnit, - gfxFontGroup::TEXT_IS_PERSISTENT, nullptr); + gfxFontGroup::TEXT_IS_PERSISTENT); } static const uint8_t dash = '-'; return MakeTextRun(&dash, 1, aCtx, aAppUnitsPerDevUnit, - gfxFontGroup::TEXT_IS_PERSISTENT, nullptr); + gfxFontGroup::TEXT_IS_PERSISTENT); } gfxFloat @@ -2065,8 +2064,7 @@ gfxFontGroup::GetHyphenWidth(gfxTextRun::PropertyProvider *aProvider) gfxTextRun * gfxFontGroup::MakeTextRun(const uint8_t *aString, uint32_t aLength, - const Parameters *aParams, uint32_t aFlags, - gfxMissingFontRecorder *aMFR) + const Parameters *aParams, uint32_t aFlags) { if (aLength == 0) { return MakeEmptyTextRun(aParams, aFlags); @@ -2090,7 +2088,7 @@ gfxFontGroup::MakeTextRun(const uint8_t *aString, uint32_t aLength, return nullptr; } - InitTextRun(aParams->mContext, textRun, aString, aLength, aMFR); + InitTextRun(aParams->mContext, textRun, aString, aLength); textRun->FetchGlyphExtents(aParams->mContext); @@ -2099,8 +2097,7 @@ gfxFontGroup::MakeTextRun(const uint8_t *aString, uint32_t aLength, gfxTextRun * gfxFontGroup::MakeTextRun(const char16_t *aString, uint32_t aLength, - const Parameters *aParams, uint32_t aFlags, - gfxMissingFontRecorder *aMFR) + const Parameters *aParams, uint32_t aFlags) { if (aLength == 0) { return MakeEmptyTextRun(aParams, aFlags); @@ -2118,7 +2115,7 @@ gfxFontGroup::MakeTextRun(const char16_t *aString, uint32_t aLength, return nullptr; } - InitTextRun(aParams->mContext, textRun, aString, aLength, aMFR); + InitTextRun(aParams->mContext, textRun, aString, aLength); textRun->FetchGlyphExtents(aParams->mContext); @@ -2130,8 +2127,7 @@ void gfxFontGroup::InitTextRun(gfxContext *aContext, gfxTextRun *aTextRun, const T *aString, - uint32_t aLength, - gfxMissingFontRecorder *aMFR) + uint32_t aLength) { NS_ASSERTION(aLength > 0, "don't call InitTextRun for a zero-length run"); @@ -2211,7 +2207,7 @@ gfxFontGroup::InitTextRun(gfxContext *aContext, // the text is still purely 8-bit; bypass the script-run itemizer // and treat it as a single Latin run InitScriptRun(aContext, aTextRun, aString, - 0, aLength, MOZ_SCRIPT_LATIN, aMFR); + 0, aLength, MOZ_SCRIPT_LATIN); } else { const char16_t *textPtr; if (transformedString) { @@ -2259,7 +2255,7 @@ gfxFontGroup::InitTextRun(gfxContext *aContext, #endif InitScriptRun(aContext, aTextRun, textPtr + runStart, - runStart, runLimit - runStart, runScript, aMFR); + runStart, runLimit - runStart, runScript); } } @@ -2295,14 +2291,6 @@ gfxFontGroup::InitTextRun(gfxContext *aContext, aTextRun->SortGlyphRuns(); } -static inline bool -IsPUA(uint32_t aUSV) -{ - // We could look up the General Category of the codepoint here, - // but it's simpler to check PUA codepoint ranges. - return (aUSV >= 0xE000 && aUSV <= 0xF8FF) || (aUSV >= 0xF0000); -} - template void gfxFontGroup::InitScriptRun(gfxContext *aContext, @@ -2312,8 +2300,7 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext, uint32_t aOffset, // position of the script run // within the textrun uint32_t aLength, // length of the script run - int32_t aRunScript, - gfxMissingFontRecorder *aMFR) + int32_t aRunScript) { NS_ASSERTION(aLength > 0, "don't call InitScriptRun for a 0-length run"); NS_ASSERTION(aTextRun->GetShapingState() != gfxTextRun::eShapingState_Aborted, @@ -2334,7 +2321,6 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext, ComputeRanges(fontRanges, aString, aLength, aRunScript, aTextRun->GetFlags() & gfxTextRunFactory::TEXT_ORIENT_MASK); uint32_t numRanges = fontRanges.Length(); - bool missingChars = false; for (uint32_t r = 0; r < numRanges; r++) { const gfxTextRange& range = fontRanges[r]; @@ -2481,15 +2467,11 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext, index + 1 < aLength && NS_IS_LOW_SURROGATE(aString[index + 1])) { - uint32_t usv = - SURROGATE_TO_UCS4(ch, aString[index + 1]); aTextRun->SetMissingGlyph(aOffset + index, - usv, + SURROGATE_TO_UCS4(ch, + aString[index + 1]), mainFont); index++; - if (!mSkipDrawing && !IsPUA(usv)) { - missingChars = true; - } continue; } @@ -2524,18 +2506,11 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext, // record char code so we can draw a box with the Unicode value aTextRun->SetMissingGlyph(aOffset + index, ch, mainFont); - if (!mSkipDrawing && !IsPUA(ch)) { - missingChars = true; - } } } runStart += matchedLength; } - - if (aMFR && missingChars) { - aMFR->RecordScript(aRunScript); - } } gfxTextRun * @@ -2561,8 +2536,7 @@ gfxFontGroup::GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel, refCtx, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevPixel }; gfxTextRun* textRun = - MakeTextRun(ellipsis.get(), ellipsis.Length(), ¶ms, - TEXT_IS_PERSISTENT, nullptr); + MakeTextRun(ellipsis.get(), ellipsis.Length(), ¶ms, TEXT_IS_PERSISTENT); if (!textRun) { return nullptr; } @@ -3134,41 +3108,3 @@ gfxFontGroup::Shutdown() } nsILanguageAtomService* gfxFontGroup::gLangService = nullptr; - -void -gfxMissingFontRecorder::Flush() -{ - static bool mNotifiedFontsInitialized = false; - static uint32_t mNotifiedFonts[gfxMissingFontRecorder::kNumScriptBitsWords]; - if (!mNotifiedFontsInitialized) { - memset(&mNotifiedFonts, 0, sizeof(mNotifiedFonts)); - mNotifiedFontsInitialized = true; - } - - nsAutoString fontNeeded; - for (uint32_t i = 0; i < kNumScriptBitsWords; ++i) { - mMissingFonts[i] &= ~mNotifiedFonts[i]; - if (!mMissingFonts[i]) { - continue; - } - for (uint32_t j = 0; j < 32; ++j) { - if (!(mMissingFonts[i] & (1 << j))) { - continue; - } - mNotifiedFonts[i] |= (1 << j); - if (!fontNeeded.IsEmpty()) { - fontNeeded.Append(PRUnichar(',')); - } - uint32_t tag = GetScriptTagForCode(i * 32 + j); - fontNeeded.Append(char16_t(tag >> 24)); - fontNeeded.Append(char16_t((tag >> 16) & 0xff)); - fontNeeded.Append(char16_t((tag >> 8) & 0xff)); - fontNeeded.Append(char16_t(tag & 0xff)); - } - mMissingFonts[i] = 0; - } - if (!fontNeeded.IsEmpty()) { - nsCOMPtr service = GetObserverService(); - service->NotifyObservers(nullptr, "font-needed", fontNeeded.get()); - } -} diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index 6ed9c7a4cd37..c94d966689ec 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -16,7 +16,6 @@ #include "mozilla/MemoryReporting.h" #include "DrawMode.h" #include "harfbuzz/hb.h" -#include "nsUnicodeScriptCodes.h" #ifdef DEBUG #include @@ -28,7 +27,6 @@ class gfxUserFontSet; class gfxTextContextPaint; class nsIAtom; class nsILanguageAtomService; -class gfxMissingFontRecorder; /** * Callback for Draw() to use when drawing text with mode @@ -766,8 +764,7 @@ public: * This calls FetchGlyphExtents on the textrun. */ virtual gfxTextRun *MakeTextRun(const char16_t *aString, uint32_t aLength, - const Parameters *aParams, uint32_t aFlags, - gfxMissingFontRecorder *aMFR); + const Parameters *aParams, uint32_t aFlags); /** * Make a textrun for a given string. * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the @@ -775,8 +772,7 @@ public: * This calls FetchGlyphExtents on the textrun. */ virtual gfxTextRun *MakeTextRun(const uint8_t *aString, uint32_t aLength, - const Parameters *aParams, uint32_t aFlags, - gfxMissingFontRecorder *aMFR); + const Parameters *aParams, uint32_t aFlags); /** * Textrun creation helper for clients that don't want to pass @@ -786,13 +782,12 @@ public: gfxTextRun *MakeTextRun(const T *aString, uint32_t aLength, gfxContext *aRefContext, int32_t aAppUnitsPerDevUnit, - uint32_t aFlags, - gfxMissingFontRecorder *aMFR) + uint32_t aFlags) { gfxTextRunFactory::Parameters params = { aRefContext, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevUnit }; - return MakeTextRun(aString, aLength, ¶ms, aFlags, aMFR); + return MakeTextRun(aString, aLength, ¶ms, aFlags); } /** @@ -1088,8 +1083,7 @@ protected: void InitTextRun(gfxContext *aContext, gfxTextRun *aTextRun, const T *aString, - uint32_t aLength, - gfxMissingFontRecorder *aMFR); + uint32_t aLength); // InitTextRun helper to handle a single script run, by finding font ranges // and calling each font's InitTextRun() as appropriate @@ -1099,8 +1093,7 @@ protected: const T *aString, uint32_t aScriptRunStart, uint32_t aScriptRunEnd, - int32_t aRunScript, - gfxMissingFontRecorder *aMFR); + int32_t aRunScript); // Helper for font-matching: // When matching the italic case, allow use of the regular face @@ -1126,54 +1119,4 @@ protected: static nsILanguageAtomService* gLangService; }; - -// A "missing font recorder" is to be used during text-run creation to keep -// a record of any scripts encountered for which font coverage was lacking; -// when Flush() is called, it sends a notification that front-end code can use -// to download fonts on demand (or whatever else it wants to do). - -#define GFX_MISSING_FONTS_NOTIFY_PREF "gfx.missing_fonts.notify" - -class gfxMissingFontRecorder { -public: - gfxMissingFontRecorder() - { - memset(&mMissingFonts, 0, sizeof(mMissingFonts)); - } - - ~gfxMissingFontRecorder() - { -#ifdef DEBUG - for (uint32_t i = 0; i < kNumScriptBitsWords; i++) { - NS_ASSERTION(mMissingFonts[i] == 0, - "failed to flush the missing-font recorder"); - } -#endif - } - - // record this script code in our mMissingFonts bitset - void RecordScript(int32_t aScriptCode) - { - mMissingFonts[uint32_t(aScriptCode) >> 5] |= - (1 << (uint32_t(aScriptCode) & 0x1f)); - } - - // send a notification of any missing-scripts that have been - // recorded, and clear the mMissingFonts set for re-use - void Flush(); - - // forget any missing-scripts that have been recorded up to now; - // called before discarding a recorder we no longer care about - void Clear() - { - memset(&mMissingFonts, 0, sizeof(mMissingFonts)); - } - -private: - // Number of 32-bit words needed for the missing-script flags - static const uint32_t kNumScriptBitsWords = - ((MOZ_NUM_SCRIPT_CODES + 31) / 32); - uint32_t mMissingFonts[kNumScriptBitsWords]; -}; - #endif diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index df1d56d170fd..c83c558cfe9b 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -64,7 +64,6 @@ #include "nsContentUtils.h" #include "nsPIWindowRoot.h" #include "mozilla/Preferences.h" -#include "gfxTextRun.h" // Needed for Start/Stop of Image Animation #include "imgIContainer.h" @@ -250,10 +249,6 @@ nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType) mTextPerf = new gfxTextPerfMetrics(); } - if (Preferences::GetBool(GFX_MISSING_FONTS_NOTIFY_PREF)) { - mMissingFonts = new gfxMissingFontRecorder(); - } - PR_INIT_CLIST(&mDOMMediaQueryLists); } @@ -350,9 +345,6 @@ nsPresContext::LastRelease() if (IsRoot()) { static_cast(this)->CancelDidPaintTimer(); } - if (mMissingFonts) { - mMissingFonts->Clear(); - } } NS_IMPL_CYCLE_COLLECTION_CLASS(nsPresContext) @@ -888,20 +880,6 @@ nsPresContext::PreferenceChanged(const char* aPrefName) } return; } - if (prefName.EqualsLiteral(GFX_MISSING_FONTS_NOTIFY_PREF)) { - if (Preferences::GetBool(GFX_MISSING_FONTS_NOTIFY_PREF)) { - if (!mMissingFonts) { - mMissingFonts = new gfxMissingFontRecorder(); - // trigger reflow to detect missing fonts on the current page - mPrefChangePendingNeedsReflow = true; - } - } else { - if (mMissingFonts) { - mMissingFonts->Clear(); - } - mMissingFonts = nullptr; - } - } if (StringBeginsWith(prefName, NS_LITERAL_CSTRING("font."))) { // Changes to font family preferences don't change anything in the // computed style data, so the style system won't generate a reflow @@ -2259,14 +2237,6 @@ nsPresContext::RebuildCounterStyles() } } -void -nsPresContext::NotifyMissingFonts() -{ - if (mMissingFonts) { - mMissingFonts->Flush(); - } -} - void nsPresContext::EnsureSafeToHandOutCSSRules() { diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h index 5b01fabdfcf1..59c6c02eadc4 100644 --- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -65,7 +65,6 @@ class nsAnimationManager; class nsRefreshDriver; class nsIWidget; class nsDeviceContext; -class gfxMissingFontRecorder; namespace mozilla { class EventStateManager; @@ -890,9 +889,6 @@ public: // user font set is changed and fonts become unavailable). void UserFontSetUpdated(); - gfxMissingFontRecorder *MissingFontRecorder() { return mMissingFonts; } - void NotifyMissingFonts(); - mozilla::dom::FontFaceSet* Fonts(); void FlushCounterStyles(); @@ -1270,8 +1266,6 @@ protected: // text performance metrics nsAutoPtr mTextPerf; - nsAutoPtr mMissingFonts; - nsRect mVisibleArea; nsSize mPageSize; float mPageScale; diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 68ebfb50ebac..ac8193b28937 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -9072,8 +9072,6 @@ PresShell::DidDoReflow(bool aInterruptible, bool aWasInterrupted) mTouchCaret->UpdatePositionIfNeeded(); } - mPresContext->NotifyMissingFonts(); - if (!aWasInterrupted) { ClearReflowOnZoomPending(); } diff --git a/layout/generic/MathMLTextRunFactory.cpp b/layout/generic/MathMLTextRunFactory.cpp index 0be1effde5ae..9ab9f5665384 100644 --- a/layout/generic/MathMLTextRunFactory.cpp +++ b/layout/generic/MathMLTextRunFactory.cpp @@ -13,7 +13,6 @@ #include "nsTextFrameUtils.h" #include "nsFontMetrics.h" #include "nsDeviceContext.h" -#include "nsUnicodeScriptCodes.h" using namespace mozilla; @@ -530,8 +529,7 @@ MathVariant(uint32_t aCh, uint8_t aMathVar) void MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, - gfxContext* aRefContext, - gfxMissingFontRecorder* aMFR) + gfxContext* aRefContext) { gfxFontGroup* fontGroup = aTextRun->GetFontGroup(); @@ -679,9 +677,6 @@ MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, } else { // We fallback to the original character. ch2 = ch; - if (aMFR) { - aMFR->RecordScript(MOZ_SCRIPT_MATHEMATICAL_NOTATION); - } } } } @@ -769,7 +764,7 @@ MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, } else { cachedChild = newFontGroup->MakeTextRun( convertedString.BeginReading(), convertedString.Length(), - &innerParams, flags, aMFR); + &innerParams, flags); child = cachedChild.get(); } if (!child) @@ -781,7 +776,7 @@ MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, child->SetPotentialLineBreaks(0, canBreakBeforeArray.Length(), canBreakBeforeArray.Elements(), aRefContext); if (transformedChild) { - transformedChild->FinishSettingProperties(aRefContext, aMFR); + transformedChild->FinishSettingProperties(aRefContext); } if (mergeNeeded) { diff --git a/layout/generic/MathMLTextRunFactory.h b/layout/generic/MathMLTextRunFactory.h index 5783672e07f9..4de229694b1a 100644 --- a/layout/generic/MathMLTextRunFactory.h +++ b/layout/generic/MathMLTextRunFactory.h @@ -22,8 +22,7 @@ public: mSSTYScriptLevel(aSSTYScriptLevel) {} virtual void RebuildTextRun(nsTransformedTextRun* aTextRun, - gfxContext* aRefContext, - gfxMissingFontRecorder* aMFR) MOZ_OVERRIDE; + gfxContext* aRefContext) MOZ_OVERRIDE; enum { // Style effects which may override single character behaviour MATH_FONT_STYLING_NORMAL = 0x1, // fontstyle="normal" has been set. diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 855baaa559b2..aac55f276729 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -561,11 +561,10 @@ template gfxTextRun * MakeTextRun(const T *aText, uint32_t aLength, gfxFontGroup *aFontGroup, const gfxFontGroup::Parameters* aParams, - uint32_t aFlags, gfxMissingFontRecorder *aMFR) + uint32_t aFlags) { nsAutoPtr textRun(aFontGroup->MakeTextRun(aText, aLength, - aParams, aFlags, - aMFR)); + aParams, aFlags)); if (!textRun) { return nullptr; } @@ -843,7 +842,6 @@ public: mCurrentFramesAllSameTextRun(nullptr), mContext(aContext), mLineContainer(aLineContainer), - mMissingFonts(aPresContext->MissingFontRecorder()), mBidiEnabled(aPresContext->BidiEnabled()), mSkipIncompleteTextRuns(false), mWhichTextRun(aWhichTextRun), @@ -973,7 +971,7 @@ public: aCapitalize, mContext); } - void Finish(gfxMissingFontRecorder* aMFR) { + void Finish() { NS_ASSERTION(!(mTextRun->GetFlags() & (gfxTextRunFactory::TEXT_UNUSED_FLAGS | nsTextFrameUtils::TEXT_UNUSED_FLAG)), @@ -981,7 +979,7 @@ public: if (mTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_TRANSFORMED) { nsTransformedTextRun* transformedTextRun = static_cast(mTextRun); - transformedTextRun->FinishSettingProperties(mContext, aMFR); + transformedTextRun->FinishSettingProperties(mContext); } // The way nsTransformedTextRun is implemented, its glyph runs aren't // available until after nsTransformedTextRun::FinishSettingProperties() @@ -1009,7 +1007,6 @@ private: // The common ancestor of the current frame and the previous leaf frame // on the line, or null if there was no previous leaf frame. nsIFrame* mCommonAncestorWithLastFrame; - gfxMissingFontRecorder* mMissingFonts; // mMaxTextLength is an upper bound on the size of the text in all mapped frames // The value UINT32_MAX represents overflow; text will be discarded uint32_t mMaxTextLength; @@ -1509,7 +1506,7 @@ void BuildTextRunsScanner::FlushLineBreaks(gfxTextRun* aTrailingTextRun) // TODO cause frames associated with the textrun to be reflowed, if they // aren't being reflowed already! } - mBreakSinks[i]->Finish(mMissingFonts); + mBreakSinks[i]->Finish(); } mBreakSinks.Clear(); @@ -2141,30 +2138,26 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) const char16_t* text = static_cast(textPtr); if (transformingFactory) { textRun = transformingFactory->MakeTextRun(text, transformedLength, ¶ms, - fontGroup, textFlags, styles.Elements(), - mMissingFonts); + fontGroup, textFlags, styles.Elements()); if (textRun) { // ownership of the factory has passed to the textrun transformingFactory.forget(); } } else { - textRun = MakeTextRun(text, transformedLength, fontGroup, ¶ms, - textFlags, mMissingFonts); + textRun = MakeTextRun(text, transformedLength, fontGroup, ¶ms, textFlags); } } else { const uint8_t* text = static_cast(textPtr); textFlags |= gfxFontGroup::TEXT_IS_8BIT; if (transformingFactory) { textRun = transformingFactory->MakeTextRun(text, transformedLength, ¶ms, - fontGroup, textFlags, styles.Elements(), - mMissingFonts); + fontGroup, textFlags, styles.Elements()); if (textRun) { // ownership of the factory has passed to the textrun transformingFactory.forget(); } } else { - textRun = MakeTextRun(text, transformedLength, fontGroup, ¶ms, - textFlags, mMissingFonts); + textRun = MakeTextRun(text, transformedLength, fontGroup, ¶ms, textFlags); } } if (!textRun) { diff --git a/layout/generic/nsTextRunTransformations.cpp b/layout/generic/nsTextRunTransformations.cpp index 9ae0ce1dd96e..f43d100da7e5 100644 --- a/layout/generic/nsTextRunTransformations.cpp +++ b/layout/generic/nsTextRunTransformations.cpp @@ -593,7 +593,7 @@ nsCaseTransformTextRunFactory::TransformString( void nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, - gfxContext* aRefContext, gfxMissingFontRecorder *aMFR) + gfxContext* aRefContext) { nsAutoString convertedString; nsAutoTArray charsToMergeArray; @@ -628,7 +628,7 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, } else { cachedChild = fontGroup->MakeTextRun( convertedString.BeginReading(), convertedString.Length(), - &innerParams, flags, aMFR); + &innerParams, flags); child = cachedChild.get(); } if (!child) @@ -640,7 +640,7 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, child->SetPotentialLineBreaks(0, canBreakBeforeArray.Length(), canBreakBeforeArray.Elements(), aRefContext); if (transformedChild) { - transformedChild->FinishSettingProperties(aRefContext, aMFR); + transformedChild->FinishSettingProperties(aRefContext); } if (mergeNeeded) { diff --git a/layout/generic/nsTextRunTransformations.h b/layout/generic/nsTextRunTransformations.h index 12f7f1f06aad..3a434238210a 100644 --- a/layout/generic/nsTextRunTransformations.h +++ b/layout/generic/nsTextRunTransformations.h @@ -27,9 +27,7 @@ public: gfxFontGroup* aFontGroup, uint32_t aFlags, nsStyleContext** aStyles, bool aOwnsFactory = true); - virtual void RebuildTextRun(nsTransformedTextRun* aTextRun, - gfxContext* aRefContext, - gfxMissingFontRecorder* aMFR) = 0; + virtual void RebuildTextRun(nsTransformedTextRun* aTextRun, gfxContext* aRefContext) = 0; }; /** @@ -50,9 +48,7 @@ public: : mInnerTransformingTextRunFactory(aInnerTransformingTextRunFactory), mAllUppercase(aAllUppercase) {} - virtual void RebuildTextRun(nsTransformedTextRun* aTextRun, - gfxContext* aRefContext, - gfxMissingFontRecorder* aMFR) MOZ_OVERRIDE; + virtual void RebuildTextRun(nsTransformedTextRun* aTextRun, gfxContext* aRefContext) MOZ_OVERRIDE; // Perform a transformation on the given string, writing the result into // aConvertedString. If aAllUppercase is true, the transform is (global) @@ -109,12 +105,11 @@ public: * are done and before we request any data from the textrun. Also always * called after a Create. */ - void FinishSettingProperties(gfxContext* aRefContext, - gfxMissingFontRecorder* aMFR) + void FinishSettingProperties(gfxContext* aRefContext) { if (mNeedsRebuild) { mNeedsRebuild = false; - mFactory->RebuildTextRun(this, aRefContext, aMFR); + mFactory->RebuildTextRun(this, aRefContext); } } diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp index f239ec9201a1..4d444c6ea628 100644 --- a/layout/mathml/nsMathMLChar.cpp +++ b/layout/mathml/nsMathMLChar.cpp @@ -37,7 +37,6 @@ #include #include "gfxMathTable.h" -#include "nsUnicodeScriptCodes.h" using namespace mozilla; using namespace mozilla::gfx; @@ -390,7 +389,7 @@ nsPropertiesTable::MakeTextRun(gfxContext* aThebesContext, "nsPropertiesTable can only access glyphs by code point"); return aFontGroup-> MakeTextRun(aGlyph.code, aGlyph.Length(), aThebesContext, - aAppUnitsPerDevPixel, 0, nullptr); + aAppUnitsPerDevPixel, 0); } // An instance of nsOpenTypeTable is associated with one gfxFontEntry that @@ -471,7 +470,7 @@ nsOpenTypeTable::UpdateCache(gfxContext* aThebesContext, if (mCharCache != aChar) { nsAutoPtr textRun; textRun = aFontGroup-> - MakeTextRun(&aChar, 1, aThebesContext, aAppUnitsPerDevPixel, 0, nullptr); + MakeTextRun(&aChar, 1, aThebesContext, aAppUnitsPerDevPixel, 0); const gfxTextRun::CompressedGlyph& data = textRun->GetCharacterGlyphs()[0]; if (data.IsSimpleGlyph()) { mGlyphID = data.GetSimpleGlyph(); @@ -1550,8 +1549,7 @@ nsMathMLChar::StretchInternal(nsPresContext* aPresContext, nsAutoPtr textRun; textRun = fm->GetThebesFontGroup()-> MakeTextRun(static_cast(mData.get()), len, aThebesContext, - aPresContext->AppUnitsPerDevPixel(), 0, - aPresContext->MissingFontRecorder()); + aPresContext->AppUnitsPerDevPixel(), 0); aDesiredStretchSize = MeasureTextRun(aThebesContext, textRun); mGlyphs[0] = textRun; @@ -1691,14 +1689,6 @@ nsMathMLChar::StretchInternal(nsPresContext* aPresContext, return NS_OK; } - // We did not find a size variant or a glyph assembly to stretch this - // operator. Verify whether a font with an OpenType MATH table is available - // and record missing math script otherwise. - gfxMissingFontRecorder* MFR = aPresContext->MissingFontRecorder(); - if (MFR && !fm->GetThebesFontGroup()->GetFirstMathFont()) { - MFR->RecordScript(MOZ_SCRIPT_MATHEMATICAL_NOTATION); - } - // stretchy character if (stretchy) { if (isVertical) { diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index eb8856b67872..767f1b9bf729 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -572,10 +572,6 @@ pref("gfx.bundled_fonts.enabled", true); pref("gfx.bundled_fonts.force-enabled", false); #endif -// Do we fire a notification about missing fonts, so the front-end can decide -// whether to try and do something about it (e.g. download additional fonts)? -pref("gfx.missing_fonts.notify", false); - pref("gfx.filter.nearest.force-enabled", false); // prefs controlling the font (name/cmap) loader that runs shortly after startup From f5421a2329aa8211c251c7e652de7231c8edfa51 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Tue, 11 Nov 2014 14:16:40 -0500 Subject: [PATCH 36/47] Backed out changeset 51572056e797 (bug 1091912) for frequent Android 4.0 crashes. CLOSED TREE --- js/src/asmjs/AsmJSModule.cpp | 95 ++++- js/src/asmjs/AsmJSModule.h | 10 + js/src/asmjs/AsmJSSignalHandlers.cpp | 538 ++++++++++++------------ js/src/asmjs/AsmJSSignalHandlers.h | 13 +- js/src/jit/CodeGenerator.cpp | 14 + js/src/jit/ExecutableAllocator.cpp | 26 ++ js/src/jit/ExecutableAllocator.h | 8 + js/src/jit/ExecutableAllocatorPosix.cpp | 15 + js/src/jit/ExecutableAllocatorWin.cpp | 16 + js/src/jit/Ion.cpp | 136 +++++- js/src/jit/Ion.h | 2 + js/src/jit/IonLinker.h | 4 + js/src/jit/JitCompartment.h | 41 +- js/src/jit/VMFunctions.cpp | 14 +- js/src/jsapi.cpp | 2 +- js/src/jscntxt.h | 1 + js/src/jscompartment.cpp | 17 +- js/src/jsgc.cpp | 23 +- js/src/vm/ForkJoin.cpp | 4 +- js/src/vm/HelperThreads.cpp | 2 +- js/src/vm/Runtime.cpp | 50 ++- js/src/vm/Runtime.h | 64 ++- js/src/vm/Stack.cpp | 9 +- 23 files changed, 720 insertions(+), 384 deletions(-) diff --git a/js/src/asmjs/AsmJSModule.cpp b/js/src/asmjs/AsmJSModule.cpp index bed659926a5a..ae86f8fb05c6 100644 --- a/js/src/asmjs/AsmJSModule.cpp +++ b/js/src/asmjs/AsmJSModule.cpp @@ -54,6 +54,36 @@ using mozilla::PodEqual; using mozilla::Compression::LZ4; using mozilla::Swap; +// At any time, the executable code of an asm.js module can be protected (as +// part of RequestInterruptForAsmJSCode). When we touch the executable outside +// of executing it (which the AsmJSFaultHandler will correctly handle), we need +// to guard against this by unprotecting the code (if it has been protected) and +// preventing it from being protected while we are touching it. +class AutoUnprotectCode +{ + JSRuntime *rt_; + JSRuntime::AutoLockForInterrupt lock_; + const AsmJSModule &module_; + const bool protectedBefore_; + + public: + AutoUnprotectCode(JSContext *cx, const AsmJSModule &module) + : rt_(cx->runtime()), + lock_(rt_), + module_(module), + protectedBefore_(module_.codeIsProtected(rt_)) + { + if (protectedBefore_) + module_.unprotectCode(rt_); + } + + ~AutoUnprotectCode() + { + if (protectedBefore_) + module_.protectCode(rt_); + } +}; + static uint8_t * AllocateExecutableMemory(ExclusiveContext *cx, size_t bytes) { @@ -83,7 +113,8 @@ AsmJSModule::AsmJSModule(ScriptSource *scriptSource, uint32_t srcStart, uint32_t dynamicallyLinked_(false), loadedFromCache_(false), profilingEnabled_(false), - interrupted_(false) + interrupted_(false), + codeIsProtected_(false) { mozilla::PodZero(&pod); pod.funcPtrTableAndExitBytes_ = SIZE_MAX; @@ -799,6 +830,7 @@ AsmJSModule::initHeap(Handle heap, JSContext *cx #endif } +// This method assumes the caller has a live AutoUnprotectCode. void AsmJSModule::restoreHeapToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer) { @@ -820,6 +852,7 @@ AsmJSModule::restoreHeapToInitialState(ArrayBufferObjectMaybeShared *maybePrevBu heapDatum() = nullptr; } +// This method assumes the caller has a live AutoUnprotectCode. void AsmJSModule::restoreToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer, uint8_t *prevCode, @@ -874,6 +907,7 @@ AsmJSModule::detachHeap(JSContext *cx) MOZ_ASSERT_IF(active(), activation()->exitReason() == AsmJSExit::Reason_IonFFI || activation()->exitReason() == AsmJSExit::Reason_SlowFFI); + AutoUnprotectCode auc(cx, *this); restoreHeapToInitialState(maybeHeap_); MOZ_ASSERT(hasDetachedHeap()); @@ -1534,6 +1568,8 @@ AsmJSModule::deserialize(ExclusiveContext *cx, const uint8_t *cursor) bool AsmJSModule::clone(JSContext *cx, ScopedJSDeletePtr *moduleOut) const { + AutoUnprotectCode auc(cx, *this); + *moduleOut = cx->new_(scriptSource_, srcStart_, srcBodyStart_, pod.strict_, pod.usesSignalHandlers_); if (!*moduleOut) @@ -1592,6 +1628,7 @@ AsmJSModule::changeHeap(Handle newHeap, JSContext *cx) if (interrupted_) return false; + AutoUnprotectCode auc(cx, *this); restoreHeapToInitialState(maybeHeap_); initHeap(newHeap, cx); return true; @@ -1632,6 +1669,9 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext *cx) AutoFlushICache afc("AsmJSModule::setProfilingEnabled"); setAutoFlushICacheRange(); + // To enable profiling, we need to patch 3 kinds of things: + AutoUnprotectCode auc(cx, *this); + // Patch all internal (asm.js->asm.js) callsites to call the profiling // prologues: for (size_t i = 0; i < callSites_.length(); i++) { @@ -1778,6 +1818,59 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext *cx) profilingEnabled_ = enabled; } +void +AsmJSModule::protectCode(JSRuntime *rt) const +{ + MOZ_ASSERT(isDynamicallyLinked()); + MOZ_ASSERT(rt->currentThreadOwnsInterruptLock()); + + codeIsProtected_ = true; + + if (!pod.functionBytes_) + return; + + // Technically, we should be able to only take away the execute permissions, + // however this seems to break our emulators which don't always check + // execute permissions while executing code. +#if defined(XP_WIN) + DWORD oldProtect; + if (!VirtualProtect(codeBase(), functionBytes(), PAGE_NOACCESS, &oldProtect)) + MOZ_CRASH(); +#else // assume Unix + if (mprotect(codeBase(), functionBytes(), PROT_NONE)) + MOZ_CRASH(); +#endif +} + +void +AsmJSModule::unprotectCode(JSRuntime *rt) const +{ + MOZ_ASSERT(isDynamicallyLinked()); + MOZ_ASSERT(rt->currentThreadOwnsInterruptLock()); + + codeIsProtected_ = false; + + if (!pod.functionBytes_) + return; + +#if defined(XP_WIN) + DWORD oldProtect; + if (!VirtualProtect(codeBase(), functionBytes(), PAGE_EXECUTE_READWRITE, &oldProtect)) + MOZ_CRASH(); +#else // assume Unix + if (mprotect(codeBase(), functionBytes(), PROT_READ | PROT_WRITE | PROT_EXEC)) + MOZ_CRASH(); +#endif +} + +bool +AsmJSModule::codeIsProtected(JSRuntime *rt) const +{ + MOZ_ASSERT(isDynamicallyLinked()); + MOZ_ASSERT(rt->currentThreadOwnsInterruptLock()); + return codeIsProtected_; +} + static bool GetCPUID(uint32_t *cpuId) { diff --git a/js/src/asmjs/AsmJSModule.h b/js/src/asmjs/AsmJSModule.h index 2491b0289ea1..129e1b3c5dbe 100644 --- a/js/src/asmjs/AsmJSModule.h +++ b/js/src/asmjs/AsmJSModule.h @@ -826,6 +826,10 @@ class AsmJSModule bool profilingEnabled_; bool interrupted_; + // This field is accessed concurrently when requesting an interrupt. + // Access must be synchronized via the runtime's interrupt lock. + mutable bool codeIsProtected_; + void restoreHeapToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer); void restoreToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer, uint8_t *prevCode, ExclusiveContext *cx); @@ -1525,6 +1529,12 @@ class AsmJSModule MOZ_ASSERT(isDynamicallyLinked()); interrupted_ = interrupted; } + + // Additionally, these functions may only be called while holding the + // runtime's interrupt lock. + void protectCode(JSRuntime *rt) const; + void unprotectCode(JSRuntime *rt) const; + bool codeIsProtected(JSRuntime *rt) const; }; // Store the just-parsed module in the cache using AsmJSCacheOps. diff --git a/js/src/asmjs/AsmJSSignalHandlers.cpp b/js/src/asmjs/AsmJSSignalHandlers.cpp index 7f09247f4cda..2fae613a9abd 100644 --- a/js/src/asmjs/AsmJSSignalHandlers.cpp +++ b/js/src/asmjs/AsmJSSignalHandlers.cpp @@ -19,7 +19,6 @@ #include "asmjs/AsmJSSignalHandlers.h" #include "mozilla/DebugOnly.h" -#include "mozilla/PodOperations.h" #include "asmjs/AsmJSModule.h" #include "vm/Runtime.h" @@ -29,81 +28,6 @@ using namespace js::jit; using JS::GenericNaN; using mozilla::DebugOnly; -using mozilla::PodArrayZero; - -#if defined(ANDROID) -# include -# if defined(MOZ_LINKER) -extern "C" MFBT_API bool IsSignalHandlingBroken(); -# endif - -static bool -IsSignalHandlingBrokenOnAndroid() -{ - // pthread_kill appears to cause memory corruption on Android 2.3 (SDK - // version 9-10) on tinderbox. It's possible the bug is just in the - // emulator, so if we end up wanting signal-handler-based optimizations for - // non-emulated Android 2.3, we could refine this test to only report - // failure if on an emulator. Most phones are on a newer Android version. - char version_string[PROP_VALUE_MAX]; - PodArrayZero(version_string); - if (__system_property_get("ro.build.version.sdk", version_string) > 0) { - long version = atol(version_string); - if (version && version <= 10) - return true; - } - -# if defined(MOZ_LINKER) - // Apparently, on some Android systems, the signal handler is always passed - // nullptr as the faulting address. This would cause the asm.js signal - // handler to think that a safe out-of-bounds access was a nullptr-deref. - // This brokenness is already detected by ElfLoader (enabled by MOZ_LINKER), - // so reuse that check to disable asm.js compilation on systems where the - // signal handler is broken. - if (IsSignalHandlingBroken()) - return true; -# endif - - return false; -} -#endif - -// For platforms where the signal/exception handler runs on the same -// thread/stack as the victim (Unix and Windows), we can use TLS to find any -// currently executing asm.js code. -static JSRuntime * -RuntimeForCurrentThread() -{ - PerThreadData *threadData = TlsPerThreadData.get(); - if (!threadData) - return nullptr; - - return threadData->runtimeIfOnOwnerThread(); -} - -// Crashing inside the signal handler can cause the handler to be recursively -// invoked, eventually blowing the stack without actually showing a crash -// report dialog via Breakpad. To guard against this we watch for such -// recursion and fall through to the next handler immediately rather than -// trying to handle it. -class AutoSetHandlingSignal -{ - JSRuntime *rt; - - public: - explicit AutoSetHandlingSignal(JSRuntime *rt) - : rt(rt) - { - MOZ_ASSERT(!rt->handlingSignal); - rt->handlingSignal = true; - } - - ~AutoSetHandlingSignal() - { - MOZ_ASSERT(rt->handlingSignal); - rt->handlingSignal = false; - } -}; #if defined(XP_WIN) # define XMM_sig(p,i) ((p)->Xmm##i) @@ -228,12 +152,71 @@ class AutoSetHandlingSignal # define R15_sig(p) ((p)->uc_mcontext.mc_r15) # endif #elif defined(XP_MACOSX) -# define EIP_sig(p) ((p)->uc_mcontext->__ss.__eip) -# define RIP_sig(p) ((p)->uc_mcontext->__ss.__rip) +// Mach requires special treatment. #else # error "Don't know how to read/write to the thread state via the mcontext_t." #endif +// For platforms where the signal/exception handler runs on the same +// thread/stack as the victim (Unix and Windows), we can use TLS to find any +// currently executing asm.js code. +#if !defined(XP_MACOSX) +static JSRuntime * +RuntimeForCurrentThread() +{ + PerThreadData *threadData = TlsPerThreadData.get(); + if (!threadData) + return nullptr; + + return threadData->runtimeIfOnOwnerThread(); +} +#endif // !defined(XP_MACOSX) + +// Crashing inside the signal handler can cause the handler to be recursively +// invoked, eventually blowing the stack without actually showing a crash +// report dialog via Breakpad. To guard against this we watch for such +// recursion and fall through to the next handler immediately rather than +// trying to handle it. +class AutoSetHandlingSignal +{ + JSRuntime *rt; + + public: + explicit AutoSetHandlingSignal(JSRuntime *rt) + : rt(rt) + { + MOZ_ASSERT(!rt->handlingSignal); + rt->handlingSignal = true; + } + + ~AutoSetHandlingSignal() + { + MOZ_ASSERT(rt->handlingSignal); + rt->handlingSignal = false; + } +}; + +#if defined(JS_CODEGEN_X64) +template +static void +SetXMMRegToNaN(bool isFloat32, T *xmm_reg) +{ + if (isFloat32) { + JS_STATIC_ASSERT(sizeof(T) == 4 * sizeof(float)); + float *floats = reinterpret_cast(xmm_reg); + floats[0] = GenericNaN(); + floats[1] = 0; + floats[2] = 0; + floats[3] = 0; + } else { + JS_STATIC_ASSERT(sizeof(T) == 2 * sizeof(double)); + double *dbls = reinterpret_cast(xmm_reg); + dbls[0] = GenericNaN(); + dbls[1] = 0; + } +} +#endif + #if defined(XP_WIN) # include "jswin.h" #else @@ -245,7 +228,7 @@ class AutoSetHandlingSignal # include // for ucontext_t, mcontext_t #endif -#if defined(JS_CPU_X64) +#if defined(JS_CODEGEN_X64) # if defined(__DragonFly__) # include // for union savefpu # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ @@ -334,6 +317,18 @@ enum { REG_EIP = 14 }; # endif // !defined(__BIONIC_HAVE_UCONTEXT_T) #endif // defined(ANDROID) +#if defined(ANDROID) && defined(MOZ_LINKER) +// Apparently, on some Android systems, the signal handler is always passed +// nullptr as the faulting address. This would cause the asm.js signal handler +// to think that a safe out-of-bounds access was a nullptr-deref. This +// brokenness is already detected by ElfLoader (enabled by MOZ_LINKER), so +// reuse that check to disable asm.js compilation on systems where the signal +// handler is broken. +extern "C" MFBT_API bool IsSignalHandlingBroken(); +#else +static bool IsSignalHandlingBroken() { return false; } +#endif // defined(MOZ_LINKER) + #if !defined(XP_WIN) # define CONTEXT ucontext_t #endif @@ -348,33 +343,41 @@ enum { REG_EIP = 14 }; # define PC_sig(p) EPC_sig(p) #endif +static bool +HandleSimulatorInterrupt(JSRuntime *rt, AsmJSActivation *activation, void *faultingAddress) +{ + // If the ARM simulator is enabled, the pc is in the simulator C++ code and + // not in the generated code, so we check the simulator's pc manually. Also + // note that we can't simply use simulator->set_pc() here because the + // simulator could be in the middle of an instruction. On ARM, the signal + // handlers are currently only used for Odin code, see bug 964258. + +#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR) + const AsmJSModule &module = activation->module(); + if (module.containsFunctionPC((void *)rt->mainThread.simulator()->get_pc()) && + module.containsFunctionPC(faultingAddress)) + { + activation->setResumePC(nullptr); + int32_t nextpc = int32_t(module.interruptExit()); + rt->mainThread.simulator()->set_resume_pc(nextpc); + return true; + } +#endif + return false; +} + +#if !defined(XP_MACOSX) static uint8_t ** ContextToPC(CONTEXT *context) { +#ifdef JS_CODEGEN_NONE + MOZ_CRASH(); +#else return reinterpret_cast(&PC_sig(context)); +#endif } -#if defined(JS_CPU_X64) -template -static void -SetXMMRegToNaN(bool isFloat32, T *xmm_reg) -{ - if (isFloat32) { - JS_STATIC_ASSERT(sizeof(T) == 4 * sizeof(float)); - float *floats = reinterpret_cast(xmm_reg); - floats[0] = GenericNaN(); - floats[1] = 0; - floats[2] = 0; - floats[3] = 0; - } else { - JS_STATIC_ASSERT(sizeof(T) == 2 * sizeof(double)); - double *dbls = reinterpret_cast(xmm_reg); - dbls[0] = GenericNaN(); - dbls[1] = 0; - } -} - -# if !defined(XP_MACOSX) +# if defined(JS_CODEGEN_X64) static void SetRegisterToCoercedUndefined(CONTEXT *context, bool isFloat32, AnyRegister reg) { @@ -420,13 +423,13 @@ SetRegisterToCoercedUndefined(CONTEXT *context, bool isFloat32, AnyRegister reg) } } } -# endif // !XP_MACOSX -#endif // JS_CPU_X64 +# endif // JS_CODEGEN_X64 +#endif // !XP_MACOSX #if defined(XP_WIN) static bool -HandleFault(PEXCEPTION_POINTERS exception) +HandleException(PEXCEPTION_POINTERS exception) { EXCEPTION_RECORD *record = exception->ExceptionRecord; CONTEXT *context = exception->ContextRecord; @@ -441,13 +444,19 @@ HandleFault(PEXCEPTION_POINTERS exception) if (record->NumberParameters < 2) return false; - // Don't allow recursive handling of signals, see AutoSetHandlingSignal. + void *faultingAddress = (void*)record->ExceptionInformation[1]; + JSRuntime *rt = RuntimeForCurrentThread(); + + // Don't allow recursive handling of signals, see AutoSetHandlingSignal. if (!rt || rt->handlingSignal) return false; AutoSetHandlingSignal handling(rt); - AsmJSActivation *activation = rt->mainThread.asmJSActivationStack(); + if (rt->jitRuntime() && rt->jitRuntime()->handleAccessViolation(rt, faultingAddress)) + return true; + + AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation(); if (!activation) return false; @@ -455,10 +464,23 @@ HandleFault(PEXCEPTION_POINTERS exception) if (!module.containsFunctionPC(pc)) return false; -# if defined(JS_CPU_X64) + // If we faulted trying to execute code in 'module', this must be an + // interrupt callback (see RequestInterruptForAsmJSCode). Redirect + // execution to a trampoline which will call js::HandleExecutionInterrupt. + // The trampoline will jump to activation->resumePC if execution isn't + // interrupted. + if (module.containsFunctionPC(faultingAddress)) { + activation->setResumePC(pc); + *ppc = module.interruptExit(); + + JSRuntime::AutoLockForInterrupt lock(rt); + module.unprotectCode(rt); + return true; + } + +# if defined(JS_CODEGEN_X64) // These checks aren't necessary, but, since we can, check anyway to make // sure we aren't covering up a real bug. - void *faultingAddress = (void*)record->ExceptionInformation[1]; if (!module.maybeHeap() || faultingAddress < module.maybeHeap() || faultingAddress >= module.maybeHeap() + AsmJSMappedSize) @@ -490,9 +512,9 @@ HandleFault(PEXCEPTION_POINTERS exception) } static LONG WINAPI -AsmJSFaultHandler(LPEXCEPTION_POINTERS exception) +AsmJSExceptionHandler(LPEXCEPTION_POINTERS exception) { - if (HandleFault(exception)) + if (HandleException(exception)) return EXCEPTION_CONTINUE_EXECUTION; // No need to worry about calling other handlers, the OS does this for us. @@ -505,16 +527,18 @@ AsmJSFaultHandler(LPEXCEPTION_POINTERS exception) static uint8_t ** ContextToPC(x86_thread_state_t &state) { -# if defined(JS_CPU_X64) +# if defined(JS_CODEGEN_X64) JS_STATIC_ASSERT(sizeof(state.uts.ts64.__rip) == sizeof(void*)); return reinterpret_cast(&state.uts.ts64.__rip); +# elif defined(JS_CODEGEN_NONE) + MOZ_CRASH(); # else JS_STATIC_ASSERT(sizeof(state.uts.ts32.__eip) == sizeof(void*)); return reinterpret_cast(&state.uts.ts32.__eip); # endif } -# if defined(JS_CPU_X64) +# if defined(JS_CODEGEN_X64) static bool SetRegisterToCoercedUndefined(mach_port_t rtThread, x86_thread_state64_t &state, const AsmJSHeapAccess &heapAccess) @@ -626,18 +650,45 @@ HandleMachException(JSRuntime *rt, const ExceptionRequest &request) if (request.body.exception != EXC_BAD_ACCESS || request.body.codeCnt != 2) return false; + void *faultingAddress = (void*)request.body.code[1]; + + if (rt->jitRuntime() && rt->jitRuntime()->handleAccessViolation(rt, faultingAddress)) + return true; + AsmJSActivation *activation = rt->mainThread.asmJSActivationStack(); if (!activation) return false; const AsmJSModule &module = activation->module(); + if (HandleSimulatorInterrupt(rt, activation, faultingAddress)) { + JSRuntime::AutoLockForInterrupt lock(rt); + module.unprotectCode(rt); + return true; + } + if (!module.containsFunctionPC(pc)) return false; -# if defined(JS_CPU_X64) + // If we faulted trying to execute code in 'module', this must be an + // interrupt callback (see RequestInterruptForAsmJSCode). Redirect + // execution to a trampoline which will call js::HandleExecutionInterrupt. + // The trampoline will jump to activation->resumePC if execution isn't + // interrupted. + if (module.containsFunctionPC(faultingAddress)) { + activation->setResumePC(pc); + *ppc = module.interruptExit(); + + JSRuntime::AutoLockForInterrupt lock(rt); + module.unprotectCode(rt); + + // Update the thread state with the new pc. + kret = thread_set_state(rtThread, x86_THREAD_STATE, (thread_state_t)&state, x86_THREAD_STATE_COUNT); + return kret == KERN_SUCCESS; + } + +# if defined(JS_CODEGEN_X64) // These checks aren't necessary, but, since we can, check anyway to make // sure we aren't covering up a real bug. - void *faultingAddress = (void*)request.body.code[1]; if (!module.maybeHeap() || faultingAddress < module.maybeHeap() || faultingAddress >= module.maybeHeap() + AsmJSMappedSize) @@ -828,30 +879,55 @@ AsmJSMachExceptionHandler::install(JSRuntime *rt) // Be very cautious and default to not handling; we don't want to accidentally // silence real crashes from real bugs. static bool -HandleFault(int signum, siginfo_t *info, void *ctx) +HandleSignal(int signum, siginfo_t *info, void *ctx) { CONTEXT *context = (CONTEXT *)ctx; uint8_t **ppc = ContextToPC(context); uint8_t *pc = *ppc; - // Don't allow recursive handling of signals, see AutoSetHandlingSignal. + void *faultingAddress = info->si_addr; + JSRuntime *rt = RuntimeForCurrentThread(); + + // Don't allow recursive handling of signals, see AutoSetHandlingSignal. if (!rt || rt->handlingSignal) return false; AutoSetHandlingSignal handling(rt); - AsmJSActivation *activation = rt->mainThread.asmJSActivationStack(); + if (rt->jitRuntime() && rt->jitRuntime()->handleAccessViolation(rt, faultingAddress)) + return true; + + AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation(); if (!activation) return false; const AsmJSModule &module = activation->module(); + if (HandleSimulatorInterrupt(rt, activation, faultingAddress)) { + JSRuntime::AutoLockForInterrupt lock(rt); + module.unprotectCode(rt); + return true; + } + if (!module.containsFunctionPC(pc)) return false; -# if defined(JS_CPU_X64) + // If we faulted trying to execute code in 'module', this must be an + // interrupt callback (see RequestInterruptForAsmJSCode). Redirect + // execution to a trampoline which will call js::HandleExecutionInterrupt. + // The trampoline will jump to activation->resumePC if execution isn't + // interrupted. + if (module.containsFunctionPC(faultingAddress)) { + activation->setResumePC(pc); + *ppc = module.interruptExit(); + + JSRuntime::AutoLockForInterrupt lock(rt); + module.unprotectCode(rt); + return true; + } + +# if defined(JS_CODEGEN_X64) // These checks aren't necessary, but, since we can, check anyway to make // sure we aren't covering up a real bug. - void *faultingAddress = info->si_addr; if (!module.maybeHeap() || faultingAddress < module.maybeHeap() || faultingAddress >= module.maybeHeap() + AsmJSMappedSize) @@ -878,12 +954,12 @@ HandleFault(int signum, siginfo_t *info, void *ctx) # endif } -static struct sigaction sPrevSEGVHandler; +static struct sigaction sPrevHandler; static void AsmJSFaultHandler(int signum, siginfo_t *info, void *context) { - if (HandleFault(signum, info, context)) + if (HandleSignal(signum, info, context)) return; // This signal is not for any asm.js code we expect, so we need to forward @@ -898,188 +974,90 @@ AsmJSFaultHandler(int signum, siginfo_t *info, void *context) // signal to it's original disposition and returning. // // Note: the order of these tests matter. - if (sPrevSEGVHandler.sa_flags & SA_SIGINFO) - sPrevSEGVHandler.sa_sigaction(signum, info, context); - else if (sPrevSEGVHandler.sa_handler == SIG_DFL || sPrevSEGVHandler.sa_handler == SIG_IGN) - sigaction(signum, &sPrevSEGVHandler, nullptr); + if (sPrevHandler.sa_flags & SA_SIGINFO) + sPrevHandler.sa_sigaction(signum, info, context); + else if (sPrevHandler.sa_handler == SIG_DFL || sPrevHandler.sa_handler == SIG_IGN) + sigaction(signum, &sPrevHandler, nullptr); else - sPrevSEGVHandler.sa_handler(signum); + sPrevHandler.sa_handler(signum); } #endif -static void -RedirectIonBackedgesToInterruptCheck(JSRuntime *rt) -{ - if (jit::JitRuntime *jitRuntime = rt->jitRuntime()) { - // If the backedge list is being mutated, the pc must be in C++ code and - // thus not in a JIT iloop. We assume that the interrupt flag will be - // checked at least once before entering JIT code (if not, no big deal; - // the browser will just request another interrupt in a second). - if (!jitRuntime->mutatingBackedgeList()) - jitRuntime->patchIonBackedges(rt, jit::JitRuntime::BackedgeInterruptCheck); - } -} - -static void -RedirectJitCodeToInterruptCheck(JSRuntime *rt, CONTEXT *context) -{ - RedirectIonBackedgesToInterruptCheck(rt); - - if (AsmJSActivation *activation = rt->mainThread.asmJSActivationStack()) { - const AsmJSModule &module = activation->module(); - -#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR) - if (module.containsFunctionPC((void*)rt->mainThread.simulator()->get_pc())) - rt->mainThread.simulator()->set_resume_pc(int32_t(module.interruptExit())); -#endif - - uint8_t **ppc = ContextToPC(context); - uint8_t *pc = *ppc; - if (module.containsFunctionPC(pc)) { - activation->setResumePC(pc); - *ppc = module.interruptExit(); - } - } -} - -#if !defined(XP_WIN) -// For the interrupt signal, pick a signal number that: -// - is not otherwise used by mozilla or standard libraries -// - defaults to nostop and noprint on gdb/lldb so that noone is bothered -// SIGVTALRM a relative of SIGALRM, so intended for user code, but, unlike -// SIGALRM, not used anywhere else in Mozilla. -static const int sInterruptSignal = SIGVTALRM; - -static void -JitInterruptHandler(int signum, siginfo_t *info, void *context) -{ - if (JSRuntime *rt = RuntimeForCurrentThread()) - RedirectJitCodeToInterruptCheck(rt, (CONTEXT*)context); -} +#if !defined(XP_MACOSX) +static bool sInstalledHandlers = false; #endif bool -js::EnsureSignalHandlersInstalled(JSRuntime *rt) +js::EnsureAsmJSSignalHandlersInstalled(JSRuntime *rt) { +#ifdef JS_CODEGEN_NONE + // Don't install signal handlers in builds with the JIT disabled. + return false; +#endif + + if (IsSignalHandlingBroken()) + return false; + #if defined(XP_MACOSX) - // On OSX, each JSRuntime gets its own handler thread. - if (!rt->asmJSMachExceptionHandler.installed() && !rt->asmJSMachExceptionHandler.install(rt)) - return false; -#endif - - // All the rest of the handlers are process-wide and thus must only be - // installed once. We assume that there are no races creating the first - // JSRuntime of the process. - static bool sTried = false; - static bool sResult = false; - if (sTried) - return sResult; - sTried = true; - -#if defined(ANDROID) - // Signal handling is broken on some android systems. - if (IsSignalHandlingBrokenOnAndroid()) - return false; -#endif - -#if defined(XP_WIN) - // Windows uses SuspendThread to stop the main thread from another thread, - // so the only handler we need is for asm.js out-of-bound faults. - if (!AddVectoredExceptionHandler(/* FirstHandler = */true, AsmJSFaultHandler)) - return false; + // On OSX, each JSRuntime gets its own handler. + return rt->asmJSMachExceptionHandler.installed() || rt->asmJSMachExceptionHandler.install(rt); #else - // The interrupt handler allows the main thread to be paused from another - // thread (see InterruptRunningJitCode). - struct sigaction interruptHandler; - interruptHandler.sa_flags = SA_SIGINFO; - interruptHandler.sa_sigaction = &JitInterruptHandler; - sigemptyset(&interruptHandler.sa_mask); - struct sigaction prev; - if (sigaction(sInterruptSignal, &interruptHandler, &prev)) - MOZ_CRASH("unable to install interrupt handler"); + // Assume Windows or Unix. For these platforms, there is a single, + // process-wide signal handler installed. Take care to only install it once. + if (sInstalledHandlers) + return true; - // There shouldn't be any other handlers installed for sInterruptSignal. If - // there are, we could always forward, but we need to understand what we're - // doing to avoid problematic interference. - if ((prev.sa_flags & SA_SIGINFO && prev.sa_sigaction) || - (prev.sa_handler != SIG_DFL && prev.sa_handler != SIG_IGN)) - { - MOZ_CRASH("contention for interrupt signal"); - } - - // Lastly, install a SIGSEGV handler to handle safely-out-of-bounds asm.js - // heap access. OSX handles seg faults via the Mach exception handler above, - // so don't install AsmJSFaultHandler. -# if !defined(XP_MACOSX) - // SA_NODEFER allows us to reenter the signal handler if we crash while - // handling the signal, and fall through to the Breakpad handler by testing - // handlingSignal. - struct sigaction faultHandler; - faultHandler.sa_flags = SA_SIGINFO | SA_NODEFER; - faultHandler.sa_sigaction = &AsmJSFaultHandler; - sigemptyset(&faultHandler.sa_mask); - if (sigaction(SIGSEGV, &faultHandler, &sPrevSEGVHandler)) +# if defined(XP_WIN) + if (!AddVectoredExceptionHandler(/* FirstHandler = */true, AsmJSExceptionHandler)) return false; -# endif // defined(XP_MACOSX) -#endif // defined(XP_WIN) +# else + // Assume Unix. SA_NODEFER allows us to reenter the signal handler if we + // crash while handling the signal, and fall through to the Breakpad + // handler by testing handlingSignal. + struct sigaction sigAction; + sigAction.sa_flags = SA_SIGINFO | SA_NODEFER; + sigAction.sa_sigaction = &AsmJSFaultHandler; + sigemptyset(&sigAction.sa_mask); + if (sigaction(SIGSEGV, &sigAction, &sPrevHandler)) + return false; +# endif - sResult = true; + sInstalledHandlers = true; +#endif return true; } -// JSRuntime::requestInterrupt sets interrupt_ (which is checked frequently by -// C++ code at every Baseline JIT loop backedge) and jitStackLimit_ (which is -// checked at every Baseline and Ion JIT function prologue). The remaining -// sources of potential iloops (Ion loop backedges and all asm.js code) are -// handled by this function: -// 1. Ion loop backedges are patched to instead point to a stub that handles the -// interrupt; -// 2. if the main thread's pc is inside asm.js code, the pc is updated to point -// to a stub that handles the interrupt. +// To interrupt execution of a JSRuntime, any thread may call +// JS_RequestInterruptCallback (JSRuntime::requestInterruptCallback from inside +// the engine). In the simplest case, this sets some state that is polled at +// regular intervals (function prologues, loop headers). For tight loops, this +// poses non-trivial overhead. For asm.js, we can do better: when another +// thread requests an interrupt, we simply mprotect all of the innermost asm.js +// module activation's code. This will trigger a SIGSEGV, taking us into +// AsmJSFaultHandler. From there, we can manually redirect execution to call +// js::HandleExecutionInterrupt. The memory is un-protected from the signal +// handler after control flow is redirected. void -js::InterruptRunningJitCode(JSRuntime *rt) +js::RequestInterruptForAsmJSCode(JSRuntime *rt, int interruptModeRaw) { - // If signal handlers weren't installed, then Ion and asm.js emit normal - // interrupt checks and don't need asynchronous interruption. - if (!rt->canUseSignalHandlers()) - return; - - // If we are on runtime's main thread, then: pc is not in asm.js code (so - // nothing to do for asm.js) and we can patch Ion backedges without any - // special synchronization. - if (rt == RuntimeForCurrentThread()) { - RedirectIonBackedgesToInterruptCheck(rt); + switch (JSRuntime::InterruptMode(interruptModeRaw)) { + case JSRuntime::RequestInterruptMainThread: + case JSRuntime::RequestInterruptAnyThread: + break; + case JSRuntime::RequestInterruptAnyThreadDontStopIon: + case JSRuntime::RequestInterruptAnyThreadForkJoin: + // It is ok to wait for asm.js execution to complete; we aren't trying + // to break an iloop or anything. Avoid the overhead of protecting all + // the code and taking a fault. return; } - // We are not on the runtime's main thread, so to do 1 and 2 above, we need - // to halt the runtime's main thread first. -#if defined(XP_WIN) - // On Windows, we can simply suspend the main thread and work directly on - // its context from this thread. - HANDLE thread = (HANDLE)rt->ownerThreadNative(); - if (SuspendThread(thread) == -1) - MOZ_CRASH("Failed to suspend main thread"); + AsmJSActivation *activation = rt->mainThread.asmJSActivationStack(); + if (!activation) + return; - CONTEXT context; - context.ContextFlags = CONTEXT_CONTROL; - if (!GetThreadContext(thread, &context)) - MOZ_CRASH("Failed to get suspended thread context"); - - RedirectJitCodeToInterruptCheck(rt, &context); - - if (!SetThreadContext(thread, &context)) - MOZ_CRASH("Failed to set suspended thread context"); - - if (ResumeThread(thread) == -1) - MOZ_CRASH("Failed to resume main thread"); -#else - // On Unix, we instead deliver an async signal to the main thread which - // halts the thread and callers our JitInterruptHandler (which has already - // been installed by EnsureSignalHandlersInstalled). - pthread_t thread = (pthread_t)rt->ownerThreadNative(); - pthread_kill(thread, sInterruptSignal); -#endif + MOZ_ASSERT(rt->currentThreadOwnsInterruptLock()); + activation->module().protectCode(rt); } // This is not supported by clang-cl yet. diff --git a/js/src/asmjs/AsmJSSignalHandlers.h b/js/src/asmjs/AsmJSSignalHandlers.h index e4133191d92b..d94ce1b611dd 100644 --- a/js/src/asmjs/AsmJSSignalHandlers.h +++ b/js/src/asmjs/AsmJSSignalHandlers.h @@ -28,16 +28,15 @@ struct JSRuntime; namespace js { -// Set up any signal/exception handlers needed to execute code in the given -// runtime. Return whether runtime can: -// - rely on fault handler support for avoiding asm.js heap bounds checks -// - rely on InterruptRunningJitCode to halt running Ion/asm.js from any thread +// Returns whether signal handlers for asm.js and for JitRuntime access +// violations have been installed. bool -EnsureSignalHandlersInstalled(JSRuntime *rt); +EnsureAsmJSSignalHandlersInstalled(JSRuntime *rt); -// Force any currently-executing asm.js code to call HandleExecutionInterrupt. +// Force any currently-executing asm.js code to call +// js::HandleExecutionInterrupt. extern void -InterruptRunningJitCode(JSRuntime *rt); +RequestInterruptForAsmJSCode(JSRuntime *rt, int interruptMode); // On OSX we are forced to use the lower-level Mach exception mechanism instead // of Unix signals. Mach exceptions are not handled on the victim's stack but diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index a323902b23b6..be05db38ac57 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -7624,6 +7624,20 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints) return false; discardIonCode.ionScript = ionScript; + // Lock the runtime against interrupt callbacks during the link. + // We don't want an interrupt request to protect the code for the script + // before it has been filled in, as we could segv before the runtime's + // patchable backedges have been fully updated. + JSRuntime::AutoLockForInterrupt lock(cx->runtime()); + + // Make sure we don't segv while filling in the code, to avoid deadlocking + // inside the signal handler. + cx->runtime()->jitRuntime()->ensureIonCodeAccessible(cx->runtime()); + + // Implicit interrupts are used only for sequential code. In parallel mode + // use the normal executable allocator so that we cannot segv during + // execution off the main thread. + // // Also, note that creating the code here during an incremental GC will // trace the code and mark all GC things it refers to. This captures any // read barriers which were skipped while compiling the script off thread. diff --git a/js/src/jit/ExecutableAllocator.cpp b/js/src/jit/ExecutableAllocator.cpp index a6afe9618164..6ae24b7f10ff 100644 --- a/js/src/jit/ExecutableAllocator.cpp +++ b/js/src/jit/ExecutableAllocator.cpp @@ -62,3 +62,29 @@ ExecutableAllocator::addSizeOfCode(JS::CodeSizes *sizes) const } } +void +ExecutableAllocator::toggleAllCodeAsAccessible(bool accessible) +{ + if (!m_pools.initialized()) + return; + + for (ExecPoolHashSet::Range r = m_pools.all(); !r.empty(); r.popFront()) { + ExecutablePool* pool = r.front(); + pool->toggleAllCodeAsAccessible(accessible); + } +} + +bool +ExecutableAllocator::codeContains(char* address) +{ + if (!m_pools.initialized()) + return false; + + for (ExecPoolHashSet::Range r = m_pools.all(); !r.empty(); r.popFront()) { + ExecutablePool* pool = r.front(); + if (pool->codeContains(address)) + return true; + } + + return false; +} diff --git a/js/src/jit/ExecutableAllocator.h b/js/src/jit/ExecutableAllocator.h index aae98903557b..6268acc96bf3 100644 --- a/js/src/jit/ExecutableAllocator.h +++ b/js/src/jit/ExecutableAllocator.h @@ -170,6 +170,12 @@ private: MOZ_ASSERT(m_end >= m_freePtr); return m_end - m_freePtr; } + + void toggleAllCodeAsAccessible(bool accessible); + + bool codeContains(char* address) { + return address >= m_allocation.pages && address < m_freePtr; + } }; class ExecutableAllocator { @@ -254,6 +260,8 @@ public: } void addSizeOfCode(JS::CodeSizes *sizes) const; + void toggleAllCodeAsAccessible(bool accessible); + bool codeContains(char* address); void setDestroyCallback(DestroyCallback destroyCallback) { this->destroyCallback = destroyCallback; diff --git a/js/src/jit/ExecutableAllocatorPosix.cpp b/js/src/jit/ExecutableAllocatorPosix.cpp index 6f79cd348178..950667e325c1 100644 --- a/js/src/jit/ExecutableAllocatorPosix.cpp +++ b/js/src/jit/ExecutableAllocatorPosix.cpp @@ -91,3 +91,18 @@ void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSe } #endif +void +ExecutablePool::toggleAllCodeAsAccessible(bool accessible) +{ + char* begin = m_allocation.pages; + size_t size = m_freePtr - begin; + + if (size) { + // N.B. Some systems, like 32bit Mac OS 10.6, implicitly add PROT_EXEC + // when mprotect'ing memory with any flag other than PROT_NONE. Be + // sure to use PROT_NONE when making inaccessible. + int flags = accessible ? PROT_READ | PROT_WRITE | PROT_EXEC : PROT_NONE; + if (mprotect(begin, size, flags)) + MOZ_CRASH(); + } +} diff --git a/js/src/jit/ExecutableAllocatorWin.cpp b/js/src/jit/ExecutableAllocatorWin.cpp index 3c9add304d74..e18eb34b62c2 100644 --- a/js/src/jit/ExecutableAllocatorWin.cpp +++ b/js/src/jit/ExecutableAllocatorWin.cpp @@ -251,6 +251,22 @@ void ExecutableAllocator::systemRelease(const ExecutablePool::Allocation& alloc) DeallocateExecutableMemory(alloc.pages, alloc.size, pageSize); } +void +ExecutablePool::toggleAllCodeAsAccessible(bool accessible) +{ + char* begin = m_allocation.pages; + size_t size = m_freePtr - begin; + + if (size) { + // N.B. DEP is not on automatically in Windows XP, so be sure to use + // PAGE_NOACCESS instead of PAGE_READWRITE when making inaccessible. + DWORD oldProtect; + int flags = accessible ? PAGE_EXECUTE_READWRITE : PAGE_NOACCESS; + if (!VirtualProtect(begin, size, flags, &oldProtect)) + MOZ_CRASH(); + } +} + #if ENABLE_ASSEMBLER_WX_EXCLUSIVE #error "ASSEMBLER_WX_EXCLUSIVE not yet suported on this platform." #endif diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index c820f55d7b55..0ea6001111d8 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -167,7 +167,7 @@ JitRuntime::JitRuntime() baselineDebugModeOSRHandler_(nullptr), functionWrappers_(nullptr), osrTempData_(nullptr), - mutatingBackedgeList_(false), + ionCodeProtected_(false), ionReturnOverride_(MagicValue(JS_ARG_POISON)), jitcodeGlobalTable_(nullptr) { @@ -191,6 +191,7 @@ bool JitRuntime::initialize(JSContext *cx) { MOZ_ASSERT(cx->runtime()->currentThreadHasExclusiveAccess()); + MOZ_ASSERT(cx->runtime()->currentThreadOwnsInterruptLock()); AutoCompartment ac(cx, cx->atomsCompartment()); @@ -365,17 +366,85 @@ JitRuntime::freeOsrTempData() ExecutableAllocator * JitRuntime::createIonAlloc(JSContext *cx) { + MOZ_ASSERT(cx->runtime()->currentThreadOwnsInterruptLock()); + ionAlloc_ = js_new(); if (!ionAlloc_) js_ReportOutOfMemory(cx); return ionAlloc_; } +void +JitRuntime::ensureIonCodeProtected(JSRuntime *rt) +{ + MOZ_ASSERT(rt->currentThreadOwnsInterruptLock()); + + if (!rt->signalHandlersInstalled() || ionCodeProtected_ || !ionAlloc_) + return; + + // Protect all Ion code in the runtime to trigger an access violation the + // next time any of it runs on the main thread. + ionAlloc_->toggleAllCodeAsAccessible(false); + ionCodeProtected_ = true; +} + +bool +JitRuntime::handleAccessViolation(JSRuntime *rt, void *faultingAddress) +{ + if (!rt->signalHandlersInstalled() || !ionAlloc_ || !ionAlloc_->codeContains((char *) faultingAddress)) + return false; + + // All places where the interrupt lock is taken must either ensure that Ion + // code memory won't be accessed within, or call ensureIonCodeAccessible to + // render the memory safe for accessing. Otherwise taking the lock below + // will deadlock the process. + MOZ_ASSERT(!rt->currentThreadOwnsInterruptLock()); + + // Taking this lock is necessary to prevent the interrupting thread from marking + // the memory as inaccessible while we are patching backedges. This will cause us + // to SEGV while still inside the signal handler, and the process will terminate. + JSRuntime::AutoLockForInterrupt lock(rt); + + // Ion code in the runtime faulted after it was made inaccessible. Reset + // the code privileges and patch all loop backedges to perform an interrupt + // check instead. + ensureIonCodeAccessible(rt); + return true; +} + +void +JitRuntime::ensureIonCodeAccessible(JSRuntime *rt) +{ + MOZ_ASSERT(rt->currentThreadOwnsInterruptLock()); + + // This can only be called on the main thread and while handling signals, + // which happens on a separate thread in OS X. +#ifndef XP_MACOSX + MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt)); +#endif + + if (ionCodeProtected_) { + ionAlloc_->toggleAllCodeAsAccessible(true); + ionCodeProtected_ = false; + } + + if (rt->hasPendingInterrupt()) { + // The interrupt handler needs to be invoked by this thread, but we may + // be inside a signal handler and have no idea what is above us on the + // stack (probably we are executing Ion code at an arbitrary point, but + // we could be elsewhere, say repatching a jump for an IonCache). + // Patch all backedges in the runtime so they will invoke the interrupt + // handler the next time they execute. + patchIonBackedges(rt, BackedgeInterruptCheck); + } +} + void JitRuntime::patchIonBackedges(JSRuntime *rt, BackedgeTarget target) { - MOZ_ASSERT_IF(target == BackedgeLoopHeader, mutatingBackedgeList_); - MOZ_ASSERT_IF(target == BackedgeInterruptCheck, !mutatingBackedgeList_); +#ifndef XP_MACOSX + MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt)); +#endif // Patch all loop backedges in Ion code so that they either jump to the // normal loop header or to an interrupt handler each time they run. @@ -391,6 +460,47 @@ JitRuntime::patchIonBackedges(JSRuntime *rt, BackedgeTarget target) } } +void +jit::RequestInterruptForIonCode(JSRuntime *rt, JSRuntime::InterruptMode mode) +{ + JitRuntime *jitRuntime = rt->jitRuntime(); + if (!jitRuntime) + return; + + MOZ_ASSERT(rt->currentThreadOwnsInterruptLock()); + + // The mechanism for interrupting normal ion code varies depending on how + // the interrupt is being requested. + switch (mode) { + case JSRuntime::RequestInterruptMainThread: + // When requesting an interrupt from the main thread, Ion loop + // backedges can be patched directly. Make sure we don't segv while + // patching the backedges, to avoid deadlocking inside the signal + // handler. + MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt)); + jitRuntime->ensureIonCodeAccessible(rt); + break; + + case JSRuntime::RequestInterruptAnyThread: + // When requesting an interrupt from off the main thread, protect + // Ion code memory so that the main thread will fault and enter a + // signal handler when trying to execute the code. The signal + // handler will unprotect the code and patch loop backedges so + // that the interrupt handler is invoked afterwards. + jitRuntime->ensureIonCodeProtected(rt); + break; + + case JSRuntime::RequestInterruptAnyThreadDontStopIon: + case JSRuntime::RequestInterruptAnyThreadForkJoin: + // The caller does not require Ion code to be interrupted. + // Nothing more needs to be done. + break; + + default: + MOZ_CRASH("Bad interrupt mode"); + } +} + JitCompartment::JitCompartment() : stubCodes_(nullptr), baselineCallReturnAddr_(nullptr), @@ -760,6 +870,10 @@ JitCode::trace(JSTracer *trc) void JitCode::finalize(FreeOp *fop) { + // Make sure this can't race with an interrupting thread, which may try + // to read the contents of the pool we are releasing references in. + MOZ_ASSERT(fop->runtime()->currentThreadOwnsInterruptLock()); + // If this jitcode has a bytecode map, de-register it. if (hasBytecodeMap_) { MOZ_ASSERT(fop->runtime()->jitRuntime()->hasJitcodeGlobalTable()); @@ -769,7 +883,7 @@ JitCode::finalize(FreeOp *fop) // Buffer can be freed at any time hereafter. Catch use-after-free bugs. // Don't do this if the Ion code is protected, as the signal handler will // deadlock trying to reacquire the interrupt lock. - if (fop->runtime()->jitRuntime()) + if (fop->runtime()->jitRuntime() && !fop->runtime()->jitRuntime()->ionCodeProtected()) memset(code_, JS_SWEPT_CODE_PATTERN, bufferSize_); code_ = nullptr; @@ -1030,9 +1144,6 @@ IonScript::copyPatchableBackedges(JSContext *cx, JitCode *code, PatchableBackedgeInfo *backedges, MacroAssembler &masm) { - JitRuntime *jrt = cx->runtime()->jitRuntime(); - JitRuntime::AutoMutateBackedges amb(jrt); - for (size_t i = 0; i < backedgeEntries_; i++) { PatchableBackedgeInfo &info = backedges[i]; PatchableBackedge *patchableBackedge = &backedgeList()[i]; @@ -1056,7 +1167,7 @@ IonScript::copyPatchableBackedges(JSContext *cx, JitCode *code, else PatchBackedge(backedge, loopHeader, JitRuntime::BackedgeLoopHeader); - jrt->addPatchableBackedge(patchableBackedge); + cx->runtime()->jitRuntime()->addPatchableBackedge(patchableBackedge); } } @@ -1247,10 +1358,11 @@ IonScript::unlinkFromRuntime(FreeOp *fop) // The writes to the executable buffer below may clobber backedge jumps, so // make sure that those backedges are unlinked from the runtime and not // reclobbered with garbage if an interrupt is requested. - JitRuntime *jrt = fop->runtime()->jitRuntime(); - JitRuntime::AutoMutateBackedges amb(jrt); - for (size_t i = 0; i < backedgeEntries_; i++) - jrt->removePatchableBackedge(&backedgeList()[i]); + JSRuntime *rt = fop->runtime(); + for (size_t i = 0; i < backedgeEntries_; i++) { + PatchableBackedge *backedge = &backedgeList()[i]; + rt->jitRuntime()->removePatchableBackedge(backedge); + } // Clear the list of backedges, so that this method is idempotent. It is // called during destruction, and may be additionally called when the diff --git a/js/src/jit/Ion.h b/js/src/jit/Ion.h index 95093821b59a..30d4daf06fd5 100644 --- a/js/src/jit/Ion.h +++ b/js/src/jit/Ion.h @@ -201,6 +201,8 @@ size_t SizeOfIonData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf); void DestroyIonScripts(FreeOp *fop, JSScript *script); void TraceIonScripts(JSTracer* trc, JSScript *script); +void RequestInterruptForIonCode(JSRuntime *rt, JSRuntime::InterruptMode mode); + bool RematerializeAllFrames(JSContext *cx, JSCompartment *comp); bool UpdateForDebugMode(JSContext *maybecx, JSCompartment *comp, AutoDebugModeInvalidation &invalidate); diff --git a/js/src/jit/IonLinker.h b/js/src/jit/IonLinker.h index fa63b7ce046f..de97815f8f48 100644 --- a/js/src/jit/IonLinker.h +++ b/js/src/jit/IonLinker.h @@ -82,6 +82,10 @@ class Linker } JitCode *newCodeForIonScript(JSContext *cx) { + // The caller must lock the runtime against interrupt requests, as the + // thread requesting an interrupt may use the executable allocator below. + MOZ_ASSERT(cx->runtime()->currentThreadOwnsInterruptLock()); + ExecutableAllocator *alloc = cx->runtime()->jitRuntime()->getIonAlloc(cx); if (!alloc) return nullptr; diff --git a/js/src/jit/JitCompartment.h b/js/src/jit/JitCompartment.h index a76999230068..718373896884 100644 --- a/js/src/jit/JitCompartment.h +++ b/js/src/jit/JitCompartment.h @@ -217,11 +217,12 @@ class JitRuntime // (after returning from JIT code). uint8_t *osrTempData_; - // List of all backedges in all Ion code. The backedge edge list is accessed - // asynchronously when the main thread is paused and mutatingBackedgeList_ - // is false. Thus, the list must only be mutated while mutatingBackedgeList_ - // is true. - volatile bool mutatingBackedgeList_; + // Whether all Ion code in the runtime is protected, and will fault if it + // is accessed. + bool ionCodeProtected_; + + // If signal handlers are installed, this contains all loop backedges for + // IonScripts in the runtime. InlineList backedgeList_; // In certain cases, we want to optimize certain opcodes to typed instructions, @@ -273,39 +274,29 @@ class JitRuntime ExecutableAllocator *execAlloc() const { return execAlloc_; } + ExecutableAllocator *getIonAlloc(JSContext *cx) { + MOZ_ASSERT(cx->runtime()->currentThreadOwnsInterruptLock()); return ionAlloc_ ? ionAlloc_ : createIonAlloc(cx); } + ExecutableAllocator *ionAlloc(JSRuntime *rt) { + MOZ_ASSERT(rt->currentThreadOwnsInterruptLock()); return ionAlloc_; } + bool hasIonAlloc() const { return !!ionAlloc_; } - class AutoMutateBackedges - { - JitRuntime *jrt_; - public: - AutoMutateBackedges(JitRuntime *jrt) : jrt_(jrt) { - MOZ_ASSERT(!jrt->mutatingBackedgeList_); - jrt->mutatingBackedgeList_ = true; - } - ~AutoMutateBackedges() { - MOZ_ASSERT(jrt_->mutatingBackedgeList_); - jrt_->mutatingBackedgeList_ = false; - } - }; - - bool mutatingBackedgeList() const { - return mutatingBackedgeList_; + bool ionCodeProtected() { + return ionCodeProtected_; } + void addPatchableBackedge(PatchableBackedge *backedge) { - MOZ_ASSERT(mutatingBackedgeList_); backedgeList_.pushFront(backedge); } void removePatchableBackedge(PatchableBackedge *backedge) { - MOZ_ASSERT(mutatingBackedgeList_); backedgeList_.remove(backedge); } @@ -314,8 +305,12 @@ class JitRuntime BackedgeInterruptCheck }; + void ensureIonCodeProtected(JSRuntime *rt); + void ensureIonCodeAccessible(JSRuntime *rt); void patchIonBackedges(JSRuntime *rt, BackedgeTarget target); + bool handleAccessViolation(JSRuntime *rt, void *faultingAddress); + JitCode *getVMWrapper(const VMFunction &f) const; JitCode *debugTrapHandler(JSContext *cx); JitCode *getBaselineDebugModeOSRHandler(JSContext *cx); diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 0a0d2d4d2541..501562c5b663 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -522,11 +522,15 @@ InterruptCheck(JSContext *cx) { gc::MaybeVerifyBarriers(cx); - { - JitRuntime *jrt = cx->runtime()->jitRuntime(); - JitRuntime::AutoMutateBackedges amb(jrt); - jrt->patchIonBackedges(cx->runtime(), JitRuntime::BackedgeLoopHeader); - } + // Fix loop backedges so that they do not invoke the interrupt again. + // No lock is held here and it's possible we could segv in the middle here + // and end up with a state where some fraction of the backedges point to + // the interrupt handler and some don't. This is ok since the interrupt + // is definitely about to be handled; if there are still backedges + // afterwards which point to the interrupt handler, the next time they are + // taken the backedges will just be reset again. + cx->runtime()->jitRuntime()->patchIonBackedges(cx->runtime(), + JitRuntime::BackedgeLoopHeader); return CheckForInterrupt(cx); } diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 2db98984532a..a913b3d7958a 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -5072,7 +5072,7 @@ JS_GetInterruptCallback(JSRuntime *rt) JS_PUBLIC_API(void) JS_RequestInterruptCallback(JSRuntime *rt) { - rt->requestInterrupt(JSRuntime::RequestInterruptUrgent); + rt->requestInterrupt(JSRuntime::RequestInterruptAnyThread); } JS_PUBLIC_API(bool) diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 9f9dd119dbcd..4c81f3febbd0 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -293,6 +293,7 @@ struct ThreadSafeContext : ContextFriendFields, void *stackLimitAddress(StackKind kind) { return &runtime_->mainThread.nativeStackLimit[kind]; } void *stackLimitAddressForJitCode(StackKind kind); size_t gcSystemPageSize() { return gc::SystemPageSize(); } + bool signalHandlersInstalled() const { return runtime_->signalHandlersInstalled(); } bool canUseSignalHandlers() const { return runtime_->canUseSignalHandlers(); } bool jitSupportsFloatingPoint() const { return runtime_->jitSupportsFloatingPoint; } bool jitSupportsSimd() const { return runtime_->jitSupportsSimd; } diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index fd54b3b5f8bc..826e42167da2 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -33,7 +33,6 @@ using namespace js; using namespace js::gc; -using namespace js::jit; using mozilla::DebugOnly; @@ -126,17 +125,17 @@ JSRuntime::createJitRuntime(JSContext *cx) // accessed by other threads with an exclusive context. AutoLockForExclusiveAccess atomsLock(cx); + // The runtime will only be created on its owning thread, but reads of a + // runtime's jitRuntime() can occur when another thread is requesting an + // interrupt. + AutoLockForInterrupt lock(this); + MOZ_ASSERT(!jitRuntime_); - jit::JitRuntime *jrt = cx->new_(); - if (!jrt) - return nullptr; + jitRuntime_ = cx->new_(); - // Protect jitRuntime_ from being observed (by InterruptRunningJitCode) - // while it is being initialized. Unfortunately, initialization depends on - // jitRuntime_ being non-null, so we can't just wait to assign jitRuntime_. - JitRuntime::AutoMutateBackedges amb(jrt); - jitRuntime_ = jrt; + if (!jitRuntime_) + return nullptr; if (!jitRuntime_->initialize(cx)) { js_delete(jitRuntime_); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 2a79db8e1e3e..49d40c039003 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -645,7 +645,12 @@ FinalizeArenas(FreeOp *fop, case FINALIZE_SYMBOL: return FinalizeTypedArenas(fop, src, dest, thingKind, budget, keepArenas); case FINALIZE_JITCODE: + { + // JitCode finalization may release references on an executable + // allocator that is accessed when requesting interrupts. + JSRuntime::AutoLockForInterrupt lock(fop->runtime()); return FinalizeTypedArenas(fop, src, dest, thingKind, budget, keepArenas); + } default: MOZ_CRASH("Invalid alloc kind"); } @@ -1051,7 +1056,7 @@ class js::gc::AutoMaybeStartBackgroundAllocation } ~AutoMaybeStartBackgroundAllocation() { - if (runtime) + if (runtime && !runtime->currentThreadOwnsInterruptLock()) runtime->gc.startBackgroundAllocTaskIfIdle(); } }; @@ -2988,7 +2993,7 @@ GCRuntime::requestMajorGC(JS::gcreason::Reason reason) majorGCRequested = true; majorGCTriggerReason = reason; - rt->requestInterrupt(JSRuntime::RequestInterruptUrgent); + rt->requestInterrupt(JSRuntime::RequestInterruptMainThread); } void @@ -3000,7 +3005,7 @@ GCRuntime::requestMinorGC(JS::gcreason::Reason reason) minorGCRequested = true; minorGCTriggerReason = reason; - rt->requestInterrupt(JSRuntime::RequestInterruptUrgent); + rt->requestInterrupt(JSRuntime::RequestInterruptMainThread); } bool @@ -3019,6 +3024,10 @@ GCRuntime::triggerGC(JS::gcreason::Reason reason) if (!CurrentThreadCanAccessRuntime(rt)) return false; + /* Don't trigger GCs when allocating under the interrupt callback lock. */ + if (rt->currentThreadOwnsInterruptLock()) + return false; + /* GC is already running. */ if (rt->isHeapCollecting()) return false; @@ -3078,6 +3087,10 @@ GCRuntime::triggerZoneGC(Zone *zone, JS::gcreason::Reason reason) if (zone->usedByExclusiveThread) return false; + /* Don't trigger GCs when allocating under the interrupt callback lock. */ + if (rt->currentThreadOwnsInterruptLock()) + return false; + /* GC is already running. */ if (rt->isHeapCollecting()) return false; @@ -5305,8 +5318,10 @@ GCRuntime::endSweepPhase(bool lastGC) if (jit::ExecutableAllocator *execAlloc = rt->maybeExecAlloc()) execAlloc->purge(); - if (rt->jitRuntime() && rt->jitRuntime()->hasIonAlloc()) + if (rt->jitRuntime() && rt->jitRuntime()->hasIonAlloc()) { + JSRuntime::AutoLockForInterrupt lock(rt); rt->jitRuntime()->ionAlloc(rt)->purge(); + } /* * This removes compartments from rt->compartment, so we do it last to make diff --git a/js/src/vm/ForkJoin.cpp b/js/src/vm/ForkJoin.cpp index 529e510f1510..7e1471311716 100644 --- a/js/src/vm/ForkJoin.cpp +++ b/js/src/vm/ForkJoin.cpp @@ -1667,7 +1667,9 @@ ForkJoinShared::setAbortFlagAndRequestInterrupt(bool fatal) abort_ = true; fatal_ = fatal_ || fatal; - cx_->runtime()->requestInterrupt(JSRuntime::RequestInterruptCanWait); + // Note: The ForkJoin trigger here avoids the expensive memory protection needed to + // interrupt Ion code compiled for sequential execution. + cx_->runtime()->requestInterrupt(JSRuntime::RequestInterruptAnyThreadForkJoin); } void diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index a4a27d2b4ac4..37cfea2863a3 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -1065,7 +1065,7 @@ HelperThread::handleIonWorkload() // at the next interrupt callback. Don't interrupt Ion code for this, as // this incorporation can be delayed indefinitely without affecting // performance as long as the main thread is actually executing Ion code. - rt->requestInterrupt(JSRuntime::RequestInterruptCanWait); + rt->requestInterrupt(JSRuntime::RequestInterruptAnyThreadDontStopIon); // Notify the main thread in case it is waiting for the compilation to finish. HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER); diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 66acf33b3a0e..44b5516380e5 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -27,7 +27,6 @@ #include "jsobj.h" #include "jsscript.h" #include "jswatchpoint.h" -#include "jswin.h" #include "jswrapper.h" #include "asmjs/AsmJSSignalHandlers.h" @@ -141,6 +140,8 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime) interruptPar_(false), handlingSignal(false), interruptCallback(nullptr), + interruptLock(nullptr), + interruptLockOwner(nullptr), exclusiveAccessLock(nullptr), exclusiveAccessOwner(nullptr), mainThreadHasExclusiveAccess(false), @@ -151,7 +152,6 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime) defaultVersion_(JSVERSION_DEFAULT), futexAPI_(nullptr), ownerThread_(nullptr), - ownerThreadNative_(0), tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), execAlloc_(nullptr), jitRuntime_(nullptr), @@ -256,19 +256,9 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes) { ownerThread_ = PR_GetCurrentThread(); - // Get a platform-native handle for the owner thread, used by - // js::InterruptRunningJitCode to halt the runtime's main thread. -#ifdef XP_WIN - size_t openFlags = THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME; - HANDLE self = OpenThread(openFlags, false, GetCurrentThreadId()); - if (!self) - MOZ_CRASH("Unable to open thread handle"); - static_assert(sizeof(HANDLE) <= sizeof(ownerThreadNative_), "need bigger field"); - ownerThreadNative_ = (size_t)self; -#else - static_assert(sizeof(pthread_t) <= sizeof(ownerThreadNative_), "need bigger field"); - ownerThreadNative_ = (size_t)pthread_self(); -#endif + interruptLock = PR_NewLock(); + if (!interruptLock) + return false; exclusiveAccessLock = PR_NewLock(); if (!exclusiveAccessLock) @@ -335,7 +325,7 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes) jitSupportsFloatingPoint = js::jit::JitSupportsFloatingPoint(); jitSupportsSimd = js::jit::JitSupportsSimd(); - signalHandlersInstalled_ = EnsureSignalHandlersInstalled(this); + signalHandlersInstalled_ = EnsureAsmJSSignalHandlersInstalled(this); canUseSignalHandlers_ = signalHandlersInstalled_ && !SignalBasedTriggersDisabled(); if (!spsProfiler.init()) @@ -401,6 +391,10 @@ JSRuntime::~JSRuntime() MOZ_ASSERT(!numExclusiveThreads); mainThreadHasExclusiveAccess = true; + MOZ_ASSERT(!interruptLockOwner); + if (interruptLock) + PR_DestroyLock(interruptLock); + /* * Even though all objects in the compartment are dead, we may have keep * some filenames around because of gcKeepAtoms. @@ -450,11 +444,6 @@ JSRuntime::~JSRuntime() MOZ_ASSERT(oldCount > 0); js::TlsPerThreadData.set(nullptr); - -#ifdef XP_WIN - if (ownerThreadNative_) - CloseHandle((HANDLE)ownerThreadNative_); -#endif } void @@ -511,9 +500,13 @@ JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Runtim if (execAlloc_) execAlloc_->addSizeOfCode(&rtSizes->code); - - if (jitRuntime() && jitRuntime()->ionAlloc(this)) - jitRuntime()->ionAlloc(this)->addSizeOfCode(&rtSizes->code); + { + AutoLockForInterrupt lock(this); + if (jitRuntime()) { + if (jit::ExecutableAllocator *ionAlloc = jitRuntime()->ionAlloc(this)) + ionAlloc->addSizeOfCode(&rtSizes->code); + } + } rtSizes->gc.marker += gc.marker.sizeOfExcludingThis(mallocSizeOf); #ifdef JSGC_GENERATIONAL @@ -618,8 +611,11 @@ JSRuntime::requestInterrupt(InterruptMode mode) interruptPar_ = true; mainThread.jitStackLimit_ = UINTPTR_MAX; - if (mode == JSRuntime::RequestInterruptUrgent) - InterruptRunningJitCode(this); + if (canUseSignalHandlers()) { + AutoLockForInterrupt lock(this); + RequestInterruptForAsmJSCode(this, mode); + jit::RequestInterruptForIonCode(this, mode); + } } bool @@ -840,6 +836,8 @@ JSRuntime::assertCanLock(RuntimeLock which) MOZ_ASSERT(exclusiveAccessOwner != PR_GetCurrentThread()); case HelperThreadStateLock: MOZ_ASSERT(!HelperThreadState().isLocked()); + case InterruptLock: + MOZ_ASSERT(!currentThreadOwnsInterruptLock()); case GCLock: gc.assertCanLock(); break; diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 204fa3bc6c1c..3735e3140fec 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -452,6 +452,7 @@ AtomStateOffsetToName(const JSAtomState &atomState, size_t offset) enum RuntimeLock { ExclusiveAccessLock, HelperThreadStateLock, + InterruptLock, GCLock }; @@ -540,6 +541,14 @@ class PerThreadData : public PerThreadDataFriendFields TraceLogger *traceLogger; #endif + /* + * asm.js maintains a stack of AsmJSModule activations (see AsmJS.h). This + * stack is used by JSRuntime::requestInterrupt to stop long-running asm.js + * without requiring dynamic polling operations in the generated + * code. Since requestInterrupt may run on a separate thread than the + * JSRuntime's owner thread all reads/writes must be synchronized (by + * rt->interruptLock). + */ private: friend class js::Activation; friend class js::ActivationIterator; @@ -557,11 +566,11 @@ class PerThreadData : public PerThreadDataFriendFields /* * Points to the most recent profiling activation running on the - * thread. + * thread. Protected by rt->interruptLock. */ js::Activation * volatile profilingActivation_; - /* See AsmJSActivation comment. */ + /* See AsmJSActivation comment. Protected by rt->interruptLock. */ js::AsmJSActivation * volatile asmJSActivationStack_; /* Pointer to the current AutoFlushICache. */ @@ -705,8 +714,10 @@ struct JSRuntime : public JS::shadow::Runtime, public: enum InterruptMode { - RequestInterruptUrgent, - RequestInterruptCanWait + RequestInterruptMainThread, + RequestInterruptAnyThread, + RequestInterruptAnyThreadDontStopIon, + RequestInterruptAnyThreadForkJoin }; // Any thread can call requestInterrupt() to request that the main JS thread @@ -759,6 +770,37 @@ struct JSRuntime : public JS::shadow::Runtime, void assertCanLock(js::RuntimeLock which) {} #endif + private: + /* + * Lock taken when triggering an interrupt from another thread. + * Protects all data that is touched in this process. + */ + PRLock *interruptLock; + PRThread *interruptLockOwner; + + public: + class AutoLockForInterrupt { + JSRuntime *rt; + public: + explicit AutoLockForInterrupt(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : rt(rt) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + rt->assertCanLock(js::InterruptLock); + PR_Lock(rt->interruptLock); + rt->interruptLockOwner = PR_GetCurrentThread(); + } + ~AutoLockForInterrupt() { + MOZ_ASSERT(rt->currentThreadOwnsInterruptLock()); + rt->interruptLockOwner = nullptr; + PR_Unlock(rt->interruptLock); + } + + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + }; + + bool currentThreadOwnsInterruptLock() { + return interruptLockOwner == PR_GetCurrentThread(); + } + private: /* * Lock taken when using per-runtime or per-zone data that could otherwise @@ -810,14 +852,9 @@ struct JSRuntime : public JS::shadow::Runtime, private: /* See comment for JS_AbortIfWrongThread in jsapi.h. */ void *ownerThread_; - size_t ownerThreadNative_; friend bool js::CurrentThreadCanAccessRuntime(JSRuntime *rt); public: - size_t ownerThreadNative() const { - return ownerThreadNative_; - } - /* Temporary arena pool used while compiling and decompiling. */ static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4 * 1024; js::LifoAlloc tempLifoAlloc; @@ -1052,15 +1089,16 @@ struct JSRuntime : public JS::shadow::Runtime, #endif private: - // Whether EnsureSignalHandlersInstalled succeeded in installing all the - // relevant handlers for this platform. + // Whether asm.js signal handlers have been installed and can be used for + // performing interrupt checks in loops. bool signalHandlersInstalled_; - // Whether we should use them or they have been disabled for making // debugging easier. If signal handlers aren't installed, it is set to false. bool canUseSignalHandlers_; - public: + bool signalHandlersInstalled() const { + return signalHandlersInstalled_; + } bool canUseSignalHandlers() const { return canUseSignalHandlers_; } diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 02d119e606cd..49a992a662bc 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -1556,7 +1556,11 @@ AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module) module.activation() = this; prevAsmJS_ = cx->mainThread().asmJSActivationStack_; - cx->mainThread().asmJSActivationStack_ = this; + + { + JSRuntime::AutoLockForInterrupt lock(cx->runtime()); + cx->mainThread().asmJSActivationStack_ = this; + } // Now that the AsmJSActivation is fully initialized, make it visible to // asynchronous profiling. @@ -1579,6 +1583,7 @@ AsmJSActivation::~AsmJSActivation() JSContext *cx = cx_->asJSContext(); MOZ_ASSERT(cx->mainThread().asmJSActivationStack_ == this); + JSRuntime::AutoLockForInterrupt lock(cx->runtime()); cx->mainThread().asmJSActivationStack_ = prevAsmJS_; } @@ -1602,6 +1607,7 @@ void Activation::registerProfiling() { MOZ_ASSERT(isProfiling()); + JSRuntime::AutoLockForInterrupt lock(cx_->asJSContext()->runtime()); cx_->perThreadData->profilingActivation_ = this; } @@ -1609,6 +1615,7 @@ void Activation::unregisterProfiling() { MOZ_ASSERT(isProfiling()); + JSRuntime::AutoLockForInterrupt lock(cx_->asJSContext()->runtime()); MOZ_ASSERT(cx_->perThreadData->profilingActivation_ == this); cx_->perThreadData->profilingActivation_ = prevProfiling_; } From feff5cece6b5a9afad59ef655cde83272f980215 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Tue, 11 Nov 2014 14:43:04 -0500 Subject: [PATCH 37/47] Bug 1071217 - Disable test_imagecapture.html on Android due to going permafail. CLOSED TREE --- dom/media/test/mochitest.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/dom/media/test/mochitest.ini b/dom/media/test/mochitest.ini index 8b5011d91385..cfbd7b890296 100644 --- a/dom/media/test/mochitest.ini +++ b/dom/media/test/mochitest.ini @@ -374,6 +374,7 @@ skip-if = toolkit == 'android' || (os == 'win' && !debug) || (os == 'mac' && !de skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439 [test_fastSeek-forwards.html] [test_imagecapture.html] +skip-if = toolkit == 'android' # bug 1071217 - crashes on 2.3 [test_info_leak.html] [test_invalid_reject.html] [test_invalid_reject_play.html] From 1533f5ace36044b84785d09f3a1fccd698d7e213 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Tue, 11 Nov 2014 14:53:11 -0500 Subject: [PATCH 38/47] Backed out changeset 583284c299fb (bug 1091916) for causing intermittent "too much recursion" jit-test failures on Win32 and OSX 10.6. CLOSED TREE --- js/src/asmjs/AsmJSModule.cpp | 6 +- .../irregexp/NativeRegExpMacroAssembler.cpp | 4 +- js/src/jit/BaselineCompiler.cpp | 4 +- js/src/jit/CodeGenerator.cpp | 8 +- js/src/jit/CompileWrappers.cpp | 10 +- js/src/jit/CompileWrappers.h | 4 +- js/src/jit/Ion.cpp | 4 +- js/src/jit/IonMacroAssembler.cpp | 2 +- js/src/jit/ParallelFunctions.cpp | 2 +- js/src/jit/VMFunctions.cpp | 29 +++- js/src/jit/shared/Assembler-shared.h | 2 +- js/src/jsapi.cpp | 54 ++++--- js/src/jsapi.h | 3 - js/src/jscntxt.cpp | 85 +++++++++++ js/src/jscntxt.h | 32 +++- js/src/jsgcinlines.h | 2 +- js/src/jsnativestack.h | 1 - js/src/vm/ForkJoin.cpp | 17 ++- js/src/vm/ForkJoin.h | 2 + js/src/vm/RegExpObject.cpp | 10 +- js/src/vm/Runtime.cpp | 143 +++++------------- js/src/vm/Runtime.h | 105 +++++-------- 22 files changed, 290 insertions(+), 239 deletions(-) diff --git a/js/src/asmjs/AsmJSModule.cpp b/js/src/asmjs/AsmJSModule.cpp index ae86f8fb05c6..bdceba091af9 100644 --- a/js/src/asmjs/AsmJSModule.cpp +++ b/js/src/asmjs/AsmJSModule.cpp @@ -500,7 +500,7 @@ AsmJSHandleExecutionInterrupt() { AsmJSActivation *act = PerThreadData::innermostAsmJSActivation(); act->module().setInterrupted(true); - bool ret = CheckForInterrupt(act->cx()); + bool ret = HandleExecutionInterrupt(act->cx()); act->module().setInterrupted(false); return ret; } @@ -673,8 +673,8 @@ AddressOf(AsmJSImmKind kind, ExclusiveContext *cx) switch (kind) { case AsmJSImm_Runtime: return cx->runtimeAddressForJit(); - case AsmJSImm_RuntimeInterruptUint32: - return cx->runtimeAddressOfInterruptUint32(); + case AsmJSImm_RuntimeInterrupt: + return cx->runtimeAddressOfInterrupt(); case AsmJSImm_StackLimit: return cx->stackLimitAddressForJitCode(StackForUntrustedScript); case AsmJSImm_ReportOverRecursed: diff --git a/js/src/irregexp/NativeRegExpMacroAssembler.cpp b/js/src/irregexp/NativeRegExpMacroAssembler.cpp index ea6a71ab3336..8cce4ee744b2 100644 --- a/js/src/irregexp/NativeRegExpMacroAssembler.cpp +++ b/js/src/irregexp/NativeRegExpMacroAssembler.cpp @@ -152,7 +152,7 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext *cx, bool match_only) // Check if we have space on the stack. Label stack_ok; - void *stack_limit = runtime->mainThread.addressOfJitStackLimit(); + void *stack_limit = &runtime->mainThread.jitStackLimit; masm.branchPtr(Assembler::Below, AbsoluteAddress(stack_limit), StackPointer, &stack_ok); // Exit with an exception. There is not enough space on the stack @@ -502,7 +502,7 @@ NativeRegExpMacroAssembler::Backtrack() // Check for an interrupt. Label noInterrupt; masm.branch32(Assembler::Equal, - AbsoluteAddress(runtime->addressOfInterruptUint32()), Imm32(0), + AbsoluteAddress(&runtime->interrupt), Imm32(0), &noInterrupt); masm.movePtr(ImmWord(RegExpRunStatus_Error), temp0); masm.jump(&exit_label_); diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index a833129a0e4e..5f3cbc8cd0f8 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -500,7 +500,7 @@ bool BaselineCompiler::emitStackCheck(bool earlyCheck) { Label skipCall; - void *limitAddr = cx->runtime()->mainThread.addressOfJitStackLimit(); + uintptr_t *limitAddr = &cx->runtime()->mainThread.jitStackLimit; uint32_t slotsSize = script->nslots() * sizeof(Value); uint32_t tolerance = earlyCheck ? slotsSize : 0; @@ -650,7 +650,7 @@ BaselineCompiler::emitInterruptCheck() frame.syncStack(0); Label done; - void *interrupt = cx->runtimeAddressOfInterruptUint32(); + void *interrupt = (void *)&cx->runtime()->interrupt; masm.branch32(Assembler::Equal, AbsoluteAddress(interrupt), Imm32(0), &done); prepareVMCall(); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index be05db38ac57..b9b45e213d00 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -3772,7 +3772,7 @@ CodeGenerator::visitCheckOverRecursedPar(LCheckOverRecursedPar *lir) Register tempReg = ToRegister(lir->getTempReg()); masm.loadPtr(Address(cxReg, offsetof(ForkJoinContext, perThreadData)), tempReg); - masm.loadPtr(Address(tempReg, PerThreadData::offsetOfJitStackLimit()), tempReg); + masm.loadPtr(Address(tempReg, offsetof(PerThreadData, jitStackLimit)), tempReg); // Conditional forward (unlikely) branch to failure. CheckOverRecursedFailure *ool = new(alloc()) CheckOverRecursedFailure(lir); @@ -9950,7 +9950,7 @@ CodeGenerator::visitInterruptCheck(LInterruptCheck *lir) if (!ool) return false; - AbsoluteAddress interruptAddr(GetIonContext()->runtime->addressOfInterruptUint32()); + AbsoluteAddress interruptAddr(GetIonContext()->runtime->addressOfInterrupt()); masm.branch32(Assembler::NotEqual, interruptAddr, Imm32(0), ool->entry()); masm.bind(ool->rejoin()); return true; @@ -9960,8 +9960,8 @@ bool CodeGenerator::visitAsmJSInterruptCheck(LAsmJSInterruptCheck *lir) { Register scratch = ToRegister(lir->scratch()); - masm.movePtr(AsmJSImmPtr(AsmJSImm_RuntimeInterruptUint32), scratch); - masm.load32(Address(scratch, 0), scratch); + masm.movePtr(AsmJSImmPtr(AsmJSImm_RuntimeInterrupt), scratch); + masm.load8ZeroExtend(Address(scratch, 0), scratch); Label rejoin; masm.branch32(Assembler::Equal, scratch, Imm32(0), &rejoin); { diff --git a/js/src/jit/CompileWrappers.cpp b/js/src/jit/CompileWrappers.cpp index 210eaf97c563..0030b92b26d8 100644 --- a/js/src/jit/CompileWrappers.cpp +++ b/js/src/jit/CompileWrappers.cpp @@ -43,7 +43,7 @@ CompileRuntime::addressOfJitTop() const void * CompileRuntime::addressOfJitStackLimit() { - return runtime()->mainThread.addressOfJitStackLimit(); + return &runtime()->mainThread.jitStackLimit; } const void * @@ -73,15 +73,15 @@ CompileRuntime::addressOfGCZeal() #endif const void * -CompileRuntime::addressOfInterruptUint32() +CompileRuntime::addressOfInterrupt() { - return runtime()->addressOfInterruptUint32(); + return &runtime()->interrupt; } const void * -CompileRuntime::addressOfInterruptParUint32() +CompileRuntime::addressOfInterruptPar() { - return runtime()->addressOfInterruptParUint32(); + return &runtime()->interruptPar; } const void * diff --git a/js/src/jit/CompileWrappers.h b/js/src/jit/CompileWrappers.h index 879bca9e8f45..fe896315d0ed 100644 --- a/js/src/jit/CompileWrappers.h +++ b/js/src/jit/CompileWrappers.h @@ -50,8 +50,8 @@ class CompileRuntime const void *addressOfGCZeal(); #endif - const void *addressOfInterruptUint32(); - const void *addressOfInterruptParUint32(); + const void *addressOfInterrupt(); + const void *addressOfInterruptPar(); const void *addressOfThreadPool(); diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 0ea6001111d8..f6075bfa8246 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -428,7 +428,7 @@ JitRuntime::ensureIonCodeAccessible(JSRuntime *rt) ionCodeProtected_ = false; } - if (rt->hasPendingInterrupt()) { + if (rt->interrupt) { // The interrupt handler needs to be invoked by this thread, but we may // be inside a signal handler and have no idea what is above us on the // stack (probably we are executing Ion code at an arbitrary point, but @@ -1162,7 +1162,7 @@ IonScript::copyPatchableBackedges(JSContext *cx, JitCode *code, // whether an interrupt is currently desired, matching the targets // established by ensureIonCodeAccessible() above. We don't handle the // interrupt immediately as the interrupt lock is held here. - if (cx->runtime()->hasPendingInterrupt()) + if (cx->runtime()->interrupt) PatchBackedge(backedge, interruptCheck, JitRuntime::BackedgeInterruptCheck); else PatchBackedge(backedge, loopHeader, JitRuntime::BackedgeLoopHeader); diff --git a/js/src/jit/IonMacroAssembler.cpp b/js/src/jit/IonMacroAssembler.cpp index 086f28071807..11b8701b38fe 100644 --- a/js/src/jit/IonMacroAssembler.cpp +++ b/js/src/jit/IonMacroAssembler.cpp @@ -1238,7 +1238,7 @@ MacroAssembler::loadStringChar(Register str, Register index, Register output) void MacroAssembler::checkInterruptFlagPar(Register tempReg, Label *fail) { - movePtr(ImmPtr(GetIonContext()->runtime->addressOfInterruptParUint32()), tempReg); + movePtr(ImmPtr(GetIonContext()->runtime->addressOfInterruptPar()), tempReg); branch32(Assembler::NonZero, Address(tempReg, 0), Imm32(0), fail); } diff --git a/js/src/jit/ParallelFunctions.cpp b/js/src/jit/ParallelFunctions.cpp index 58df34db82cc..2080bb959ad4 100644 --- a/js/src/jit/ParallelFunctions.cpp +++ b/js/src/jit/ParallelFunctions.cpp @@ -147,7 +147,7 @@ jit::CheckOverRecursedPar(ForkJoinContext *cx) } #endif - if (!JS_CHECK_STACK_SIZE(cx->perThreadData->jitStackLimit(), &stackDummy_)) { + if (!JS_CHECK_STACK_SIZE(cx->perThreadData->jitStackLimit, &stackDummy_)) { cx->bailoutRecord->joinCause(ParallelBailoutOverRecursed); return false; } diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 501562c5b663..bc798f6f1dda 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -113,17 +113,28 @@ NewGCObject(JSContext *cx, gc::AllocKind allocKind, gc::InitialHeap initialHeap) bool CheckOverRecursed(JSContext *cx) { - // We just failed the jitStackLimit check. There are two possible reasons: - // - jitStackLimit was the real stack limit and we're over-recursed - // - jitStackLimit was set to UINTPTR_MAX by JSRuntime::requestInterrupt - // and we need to call JSRuntime::handleInterrupt. + // IonMonkey's stackLimit is equal to nativeStackLimit by default. When we + // request an interrupt, we set the jitStackLimit to nullptr, which causes + // the stack limit check to fail. + // + // There are two states we're concerned about here: + // (1) The interrupt bit is set, and we need to fire the interrupt callback. + // (2) The stack limit has been exceeded, and we need to throw an error. + // + // Note that we can reach here if jitStackLimit is MAXADDR, but interrupt + // has not yet been set to 1. That's okay; it will be set to 1 very shortly, + // and in the interim we might just fire a few useless calls to + // CheckOverRecursed. #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR) JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, 0, return false); #else JS_CHECK_RECURSION(cx, return false); #endif - gc::MaybeVerifyBarriers(cx); - return cx->runtime()->handleInterrupt(cx); + + if (cx->runtime()->interrupt) + return InterruptCheck(cx); + + return true; } // This function can get called in two contexts. In the usual context, it's @@ -167,8 +178,10 @@ CheckOverRecursedWithExtra(JSContext *cx, BaselineFrame *frame, JS_CHECK_RECURSION_WITH_SP(cx, checkSp, return false); #endif - gc::MaybeVerifyBarriers(cx); - return cx->runtime()->handleInterrupt(cx); + if (cx->runtime()->interrupt) + return InterruptCheck(cx); + + return true; } bool diff --git a/js/src/jit/shared/Assembler-shared.h b/js/src/jit/shared/Assembler-shared.h index 9b54186df22e..2144df9b0be3 100644 --- a/js/src/jit/shared/Assembler-shared.h +++ b/js/src/jit/shared/Assembler-shared.h @@ -783,7 +783,7 @@ enum AsmJSImmKind AsmJSImm_PowD = AsmJSExit::Builtin_PowD, AsmJSImm_ATan2D = AsmJSExit::Builtin_ATan2D, AsmJSImm_Runtime, - AsmJSImm_RuntimeInterruptUint32, + AsmJSImm_RuntimeInterrupt, AsmJSImm_StackLimit, AsmJSImm_ReportOverRecursed, AsmJSImm_OnDetached, diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index a913b3d7958a..0bec32dca66e 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2031,48 +2031,68 @@ JS_GetExternalStringFinalizer(JSString *str) } static void -SetNativeStackQuotaAndLimit(JSRuntime *rt, StackKind kind, size_t stackSize) +SetNativeStackQuota(JSRuntime *rt, StackKind kind, size_t stackSize) { rt->nativeStackQuota[kind] = stackSize; + if (rt->nativeStackBase) + RecomputeStackLimit(rt, kind); +} +void +js::RecomputeStackLimit(JSRuntime *rt, StackKind kind) +{ + size_t stackSize = rt->nativeStackQuota[kind]; #if JS_STACK_GROWTH_DIRECTION > 0 if (stackSize == 0) { rt->mainThread.nativeStackLimit[kind] = UINTPTR_MAX; } else { MOZ_ASSERT(rt->nativeStackBase <= size_t(-1) - stackSize); - rt->mainThread.nativeStackLimit[kind] = rt->nativeStackBase + stackSize - 1; + rt->mainThread.nativeStackLimit[kind] = + rt->nativeStackBase + stackSize - 1; } #else if (stackSize == 0) { rt->mainThread.nativeStackLimit[kind] = 0; } else { MOZ_ASSERT(rt->nativeStackBase >= stackSize); - rt->mainThread.nativeStackLimit[kind] = rt->nativeStackBase - (stackSize - 1); + rt->mainThread.nativeStackLimit[kind] = + rt->nativeStackBase - (stackSize - 1); } #endif + + // If there's no pending interrupt request set on the runtime's main thread's + // jitStackLimit, then update it so that it reflects the new nativeStacklimit. + // + // Note that, for now, we use the untrusted limit for ion. This is fine, + // because it's the most conservative limit, and if we hit it, we'll bail + // out of ion into the interpeter, which will do a proper recursion check. + if (kind == StackForUntrustedScript) { + JSRuntime::AutoLockForInterrupt lock(rt); + if (rt->mainThread.jitStackLimit != uintptr_t(-1)) { + rt->mainThread.jitStackLimit = rt->mainThread.nativeStackLimit[kind]; +#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR) + rt->mainThread.jitStackLimit = jit::Simulator::StackLimit(); +#endif + } + } } JS_PUBLIC_API(void) -JS_SetNativeStackQuota(JSRuntime *rt, size_t systemCodeStackSize, size_t trustedScriptStackSize, +JS_SetNativeStackQuota(JSRuntime *rt, size_t systemCodeStackSize, + size_t trustedScriptStackSize, size_t untrustedScriptStackSize) { - MOZ_ASSERT(rt->requestDepth == 0); - + MOZ_ASSERT_IF(trustedScriptStackSize, + trustedScriptStackSize < systemCodeStackSize); if (!trustedScriptStackSize) trustedScriptStackSize = systemCodeStackSize; - else - MOZ_ASSERT(trustedScriptStackSize < systemCodeStackSize); - + MOZ_ASSERT_IF(untrustedScriptStackSize, + untrustedScriptStackSize < trustedScriptStackSize); if (!untrustedScriptStackSize) untrustedScriptStackSize = trustedScriptStackSize; - else - MOZ_ASSERT(untrustedScriptStackSize < trustedScriptStackSize); - - SetNativeStackQuotaAndLimit(rt, StackForSystemCode, systemCodeStackSize); - SetNativeStackQuotaAndLimit(rt, StackForTrustedScript, trustedScriptStackSize); - SetNativeStackQuotaAndLimit(rt, StackForUntrustedScript, untrustedScriptStackSize); - - rt->mainThread.initJitStackLimit(); + SetNativeStackQuota(rt, StackForSystemCode, systemCodeStackSize); + SetNativeStackQuota(rt, StackForTrustedScript, trustedScriptStackSize); + SetNativeStackQuota(rt, StackForUntrustedScript, untrustedScriptStackSize); } /************************************************************************/ diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 3946eec97cdc..0b434a3ac58a 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2272,9 +2272,6 @@ JS_GetExternalStringFinalizer(JSString *str); * The stack quotas for each kind of code should be monotonically descending, * and may be specified with this function. If 0 is passed for a given kind * of code, it defaults to the value of the next-highest-priority kind. - * - * This function may only be called immediately after the runtime is initialized - * and before any code is executed and/or interrupts requested. */ extern JS_PUBLIC_API(void) JS_SetNativeStackQuota(JSRuntime *cx, size_t systemCodeStackSize, diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 412ae616d270..cb861567edfe 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -41,6 +41,7 @@ #include "gc/Marking.h" #include "jit/Ion.h" #include "js/CharacterEncoding.h" +#include "vm/Debugger.h" #include "vm/HelperThreads.h" #include "vm/Shape.h" @@ -970,6 +971,90 @@ js_GetErrorMessage(void *userRef, const unsigned errorNumber) return nullptr; } +bool +js::InvokeInterruptCallback(JSContext *cx) +{ + MOZ_ASSERT(cx->runtime()->requestDepth >= 1); + + JSRuntime *rt = cx->runtime(); + MOZ_ASSERT(rt->interrupt); + + // Reset the callback counter first, then run GC and yield. If another + // thread is racing us here we will accumulate another callback request + // which will be serviced at the next opportunity. + rt->interrupt = false; + + // IonMonkey sets its stack limit to UINTPTR_MAX to trigger interrupt + // callbacks. + rt->resetJitStackLimit(); + + cx->gcIfNeeded(); + + rt->interruptPar = false; + + // A worker thread may have requested an interrupt after finishing an Ion + // compilation. + jit::AttachFinishedCompilations(cx); + + // Important: Additional callbacks can occur inside the callback handler + // if it re-enters the JS engine. The embedding must ensure that the + // callback is disconnected before attempting such re-entry. + JSInterruptCallback cb = cx->runtime()->interruptCallback; + if (!cb) + return true; + + if (cb(cx)) { + // Debugger treats invoking the interrupt callback as a "step", so + // invoke the onStep handler. + if (cx->compartment()->debugMode()) { + ScriptFrameIter iter(cx); + if (iter.script()->stepModeEnabled()) { + RootedValue rval(cx); + switch (Debugger::onSingleStep(cx, &rval)) { + case JSTRAP_ERROR: + return false; + case JSTRAP_CONTINUE: + return true; + case JSTRAP_RETURN: + // See note in Debugger::propagateForcedReturn. + Debugger::propagateForcedReturn(cx, iter.abstractFramePtr(), rval); + return false; + case JSTRAP_THROW: + cx->setPendingException(rval); + return false; + default:; + } + } + } + + return true; + } + + // No need to set aside any pending exception here: ComputeStackString + // already does that. + JSString *stack = ComputeStackString(cx); + JSFlatString *flat = stack ? stack->ensureFlat(cx) : nullptr; + + const char16_t *chars; + AutoStableStringChars stableChars(cx); + if (flat && stableChars.initTwoByte(cx, flat)) + chars = stableChars.twoByteRange().start().get(); + else + chars = MOZ_UTF16("(stack not available)"); + JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_WARNING, js_GetErrorMessage, nullptr, + JSMSG_TERMINATED, chars); + + return false; +} + +bool +js::HandleExecutionInterrupt(JSContext *cx) +{ + if (cx->runtime()->interrupt) + return InvokeInterruptCallback(cx); + return true; +} + ThreadSafeContext::ThreadSafeContext(JSRuntime *rt, PerThreadData *pt, ContextKind kind) : ContextFriendFields(rt), contextKind_(kind), diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 4c81f3febbd0..3fa252c061a7 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -289,7 +289,7 @@ struct ThreadSafeContext : ContextFriendFields, PropertyName *emptyString() { return runtime_->emptyString; } FreeOp *defaultFreeOp() { return runtime_->defaultFreeOp(); } void *runtimeAddressForJit() { return runtime_; } - void *runtimeAddressOfInterruptUint32() { return runtime_->addressOfInterruptUint32(); } + void *runtimeAddressOfInterrupt() { return &runtime_->interrupt; } void *stackLimitAddress(StackKind kind) { return &runtime_->mainThread.nativeStackLimit[kind]; } void *stackLimitAddressForJitCode(StackKind kind); size_t gcSystemPageSize() { return gc::SystemPageSize(); } @@ -782,15 +782,33 @@ extern const JSErrorFormatString js_ErrorFormatString[JSErr_Limit]; namespace js { +/* + * Invoke the interrupt callback and return false if the current execution + * is to be terminated. + */ +bool +InvokeInterruptCallback(JSContext *cx); + +bool +HandleExecutionInterrupt(JSContext *cx); + +/* + * Process any pending interrupt requests. Long-running inner loops in C++ must + * call this periodically to make sure they are interruptible --- that is, to + * make sure they do not prevent the slow script dialog from appearing. + * + * This can run a full GC or call the interrupt callback, which could do + * anything. In the browser, it displays the slow script dialog. + * + * If this returns true, the caller can continue; if false, the caller must + * break out of its loop. This happens if, for example, the user clicks "Stop + * script" on the slow script dialog; treat it as an uncatchable error. + */ MOZ_ALWAYS_INLINE bool CheckForInterrupt(JSContext *cx) { - // Add an inline fast-path since we have to check for interrupts in some hot - // C++ loops of library builtins. - JSRuntime *rt = cx->runtime(); - if (rt->hasPendingInterrupt()) - return rt->handleInterrupt(cx); - return true; + MOZ_ASSERT(cx->runtime()->requestDepth >= 1); + return !cx->runtime()->interrupt || InvokeInterruptCallback(cx); } /************************************************************************/ diff --git a/js/src/jsgcinlines.h b/js/src/jsgcinlines.h index bf4ec955c7fd..1921c6b8b776 100644 --- a/js/src/jsgcinlines.h +++ b/js/src/jsgcinlines.h @@ -526,7 +526,7 @@ CheckAllocatorState(ThreadSafeContext *cx, AllocKind kind) rt->gc.runDebugGC(); #endif - if (rt->hasPendingInterrupt()) { + if (rt->interrupt) { // Invoking the interrupt callback can fail and we can't usefully // handle that here. Just check in case we need to collect instead. ncx->gcIfNeeded(); diff --git a/js/src/jsnativestack.h b/js/src/jsnativestack.h index bcfe0ad88d27..86abcd08ac5c 100644 --- a/js/src/jsnativestack.h +++ b/js/src/jsnativestack.h @@ -18,7 +18,6 @@ inline uintptr_t GetNativeStackBase() { uintptr_t stackBase = reinterpret_cast(GetNativeStackBaseImpl()); - MOZ_ASSERT(stackBase != 0); MOZ_ASSERT(stackBase % sizeof(void *) == 0); return stackBase; } diff --git a/js/src/vm/ForkJoin.cpp b/js/src/vm/ForkJoin.cpp index 7e1471311716..dd828fd771a4 100644 --- a/js/src/vm/ForkJoin.cpp +++ b/js/src/vm/ForkJoin.cpp @@ -1440,7 +1440,7 @@ ForkJoinShared::execute() // Sometimes a GC request occurs *just before* we enter into the // parallel section. Rather than enter into the parallel section // and then abort, we just check here and abort early. - if (cx_->runtime()->hasPendingInterruptPar()) + if (cx_->runtime()->interruptPar) return TP_RETRY_SEQUENTIALLY; AutoLockMonitor lock(*this); @@ -1518,7 +1518,7 @@ ForkJoinShared::executeFromWorker(ThreadPoolWorker *worker, uintptr_t stackLimit // Don't use setIonStackLimit() because that acquires the ionStackLimitLock, and the // lock has not been initialized in these cases. - thisThread.initJitStackLimitPar(stackLimit); + thisThread.jitStackLimit = stackLimit; executePortion(&thisThread, worker); TlsPerThreadData.set(nullptr); @@ -1551,7 +1551,7 @@ ForkJoinShared::executeFromMainThread(ThreadPoolWorker *worker) // // Thus, use GetNativeStackLimit instead of just propagating the // main thread's. - thisThread.initJitStackLimitPar(GetNativeStackLimit(cx_)); + thisThread.jitStackLimit = GetNativeStackLimit(cx_); executePortion(&thisThread, worker); TlsPerThreadData.set(oldData); @@ -1647,7 +1647,7 @@ ForkJoinShared::executePortion(PerThreadData *perThread, ThreadPoolWorker *worke void ForkJoinShared::setAbortFlagDueToInterrupt(ForkJoinContext &cx) { - MOZ_ASSERT(cx_->runtime()->hasPendingInterruptPar()); + MOZ_ASSERT(cx_->runtime()->interruptPar); // The GC Needed flag should not be set during parallel // execution. Instead, one of the requestGC() or // requestZoneGC() methods should be invoked. @@ -1826,7 +1826,7 @@ ForkJoinContext::hasAcquiredJSContext() const bool ForkJoinContext::check() { - if (runtime()->hasPendingInterruptPar()) { + if (runtime()->interruptPar) { shared_->setAbortFlagDueToInterrupt(*this); return false; } @@ -2273,6 +2273,13 @@ js::ParallelTestsShouldPass(JSContext *cx) cx->runtime()->gcZeal() == 0; } +void +js::RequestInterruptForForkJoin(JSRuntime *rt, JSRuntime::InterruptMode mode) +{ + if (mode != JSRuntime::RequestInterruptAnyThreadDontStopIon) + rt->interruptPar = true; +} + bool js::intrinsic_SetForkJoinTargetRegion(JSContext *cx, unsigned argc, Value *vp) { diff --git a/js/src/vm/ForkJoin.h b/js/src/vm/ForkJoin.h index 8554d4f87f7d..55af6f09f7a1 100644 --- a/js/src/vm/ForkJoin.h +++ b/js/src/vm/ForkJoin.h @@ -546,6 +546,8 @@ bool InExclusiveParallelSection(); bool ParallelTestsShouldPass(JSContext *cx); +void RequestInterruptForForkJoin(JSRuntime *rt, JSRuntime::InterruptMode mode); + bool intrinsic_SetForkJoinTargetRegion(JSContext *cx, unsigned argc, Value *vp); extern const JSJitInfo intrinsic_SetForkJoinTargetRegionInfo; diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index 6429469b750e..6e2ac67120dc 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -621,8 +621,14 @@ RegExpShared::execute(JSContext *cx, HandleLinearString input, size_t start, // in the bytecode interpreter, which can execute while tolerating // future interrupts. Otherwise, if we keep getting interrupted we // will never finish executing the regexp. - if (cx->runtime()->hasPendingInterrupt()) { - if (!cx->runtime()->handleInterrupt(cx)) + bool interrupted; + { + JSRuntime::AutoLockForInterrupt lock(cx->runtime()); + interrupted = cx->runtime()->interrupt; + } + + if (interrupted) { + if (!InvokeInterruptCallback(cx)) return RegExpRunStatus_Error; break; } diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 44b5516380e5..105f3eccace9 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -36,7 +36,6 @@ #include "jit/PcScriptCache.h" #include "js/MemoryMetrics.h" #include "js/SliceBudget.h" -#include "vm/Debugger.h" #include "jscntxtinlines.h" #include "jsgcinlines.h" @@ -74,7 +73,7 @@ PerThreadData::PerThreadData(JSRuntime *runtime) runtime_(runtime), jitTop(nullptr), jitJSContext(nullptr), - jitStackLimit_(0xbad), + jitStackLimit(0), #ifdef JS_TRACE_LOGGING traceLogger(nullptr), #endif @@ -136,8 +135,8 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime) ), mainThread(this), parentRuntime(parentRuntime), - interrupt_(false), - interruptPar_(false), + interrupt(false), + interruptPar(false), handlingSignal(false), interruptCallback(nullptr), interruptLock(nullptr), @@ -156,7 +155,7 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime) execAlloc_(nullptr), jitRuntime_(nullptr), selfHostingGlobal_(nullptr), - nativeStackBase(GetNativeStackBase()), + nativeStackBase(0), cxCallback(nullptr), destroyCompartmentCallback(nullptr), destroyZoneCallback(nullptr), @@ -322,6 +321,8 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes) return false; #endif + nativeStackBase = GetNativeStackBase(); + jitSupportsFloatingPoint = js::jit::JitSupportsFloatingPoint(); jitSupportsSimd = js::jit::JitSupportsSimd(); @@ -463,6 +464,17 @@ NewObjectCache::clearNurseryObjects(JSRuntime *rt) #endif } +void +JSRuntime::resetJitStackLimit() +{ + AutoLockForInterrupt lock(this); + mainThread.setJitStackLimit(mainThread.nativeStackLimit[js::StackForUntrustedScript]); + +#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR) + mainThread.setJitStackLimit(js::jit::Simulator::StackLimit()); +#endif +} + void JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes *rtSizes) { @@ -517,120 +529,33 @@ JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Runtim #endif } -static bool -InvokeInterruptCallback(JSContext *cx) -{ - MOZ_ASSERT(cx->runtime()->requestDepth >= 1); - - cx->gcIfNeeded(); - - // A worker thread may have requested an interrupt after finishing an Ion - // compilation. - jit::AttachFinishedCompilations(cx); - - // Important: Additional callbacks can occur inside the callback handler - // if it re-enters the JS engine. The embedding must ensure that the - // callback is disconnected before attempting such re-entry. - JSInterruptCallback cb = cx->runtime()->interruptCallback; - if (!cb) - return true; - - if (cb(cx)) { - // Debugger treats invoking the interrupt callback as a "step", so - // invoke the onStep handler. - if (cx->compartment()->debugMode()) { - ScriptFrameIter iter(cx); - if (iter.script()->stepModeEnabled()) { - RootedValue rval(cx); - switch (Debugger::onSingleStep(cx, &rval)) { - case JSTRAP_ERROR: - return false; - case JSTRAP_CONTINUE: - return true; - case JSTRAP_RETURN: - // See note in Debugger::propagateForcedReturn. - Debugger::propagateForcedReturn(cx, iter.abstractFramePtr(), rval); - return false; - case JSTRAP_THROW: - cx->setPendingException(rval); - return false; - default:; - } - } - } - - return true; - } - - // No need to set aside any pending exception here: ComputeStackString - // already does that. - JSString *stack = ComputeStackString(cx); - JSFlatString *flat = stack ? stack->ensureFlat(cx) : nullptr; - - const char16_t *chars; - AutoStableStringChars stableChars(cx); - if (flat && stableChars.initTwoByte(cx, flat)) - chars = stableChars.twoByteRange().start().get(); - else - chars = MOZ_UTF16("(stack not available)"); - JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_WARNING, js_GetErrorMessage, nullptr, - JSMSG_TERMINATED, chars); - - return false; -} - -void -PerThreadData::resetJitStackLimit() -{ - // Note that, for now, we use the untrusted limit for ion. This is fine, - // because it's the most conservative limit, and if we hit it, we'll bail - // out of ion into the interpeter, which will do a proper recursion check. -#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR) - jitStackLimit_ = jit::Simulator::StackLimit(); -#else - jitStackLimit_ = nativeStackLimit[StackForUntrustedScript]; -#endif -} - -void -PerThreadData::initJitStackLimit() -{ - resetJitStackLimit(); -} - -void -PerThreadData::initJitStackLimitPar(uintptr_t limit) -{ - jitStackLimit_ = limit; -} - void JSRuntime::requestInterrupt(InterruptMode mode) { - interrupt_ = true; - interruptPar_ = true; - mainThread.jitStackLimit_ = UINTPTR_MAX; + AutoLockForInterrupt lock(this); + /* + * Invalidate ionTop to trigger its over-recursion check. Note this must be + * set before interrupt, to avoid racing with js::InvokeInterruptCallback, + * into a weird state where interrupt is stuck at 0 but jitStackLimit is + * MAXADDR. + */ + mainThread.setJitStackLimit(-1); + + interrupt = true; + + RequestInterruptForForkJoin(this, mode); + + /* + * asm.js and normal Ion code optionally use memory protection and signal + * handlers to halt running code. + */ if (canUseSignalHandlers()) { - AutoLockForInterrupt lock(this); RequestInterruptForAsmJSCode(this, mode); jit::RequestInterruptForIonCode(this, mode); } } -bool -JSRuntime::handleInterrupt(JSContext *cx) -{ - MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime())); - if (interrupt_ || mainThread.jitStackLimit_ == UINTPTR_MAX) { - interrupt_ = false; - interruptPar_ = false; - mainThread.resetJitStackLimit(); - return InvokeInterruptCallback(cx); - } - return true; -} - jit::ExecutableAllocator * JSRuntime::createExecutableAllocator(JSContext *cx) { diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 3735e3140fec..7c883a686db7 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -519,20 +519,13 @@ class PerThreadData : public PerThreadDataFriendFields */ JSContext *jitJSContext; - /* See comment for JSRuntime::interrupt_. */ - private: - mozilla::Atomic jitStackLimit_; - void resetJitStackLimit(); - friend struct ::JSRuntime; - public: - void initJitStackLimit(); - void initJitStackLimitPar(uintptr_t limit); + /* + * The stack limit checked by JIT code. This stack limit may be temporarily + * set to null to force JIT code to exit (e.g., for the operation callback). + */ + uintptr_t jitStackLimit; - uintptr_t jitStackLimit() const { return jitStackLimit_; } - - // For read-only JIT use: - void *addressOfJitStackLimit() { return &jitStackLimit_; } - static size_t offsetOfJitStackLimit() { return offsetof(PerThreadData, jitStackLimit_); } + inline void setJitStackLimit(uintptr_t limit); // Information about the heap allocated backtrack stack used by RegExp JIT code. irregexp::RegExpStack regexpStack; @@ -685,6 +678,8 @@ class PerThreadData : public PerThreadDataFriendFields class AutoLockForExclusiveAccess; +void RecomputeStackLimit(JSRuntime *rt, StackKind kind); + } // namespace js struct JSRuntime : public JS::shadow::Runtime, @@ -708,56 +703,18 @@ struct JSRuntime : public JS::shadow::Runtime, */ JSRuntime *parentRuntime; - private: - mozilla::Atomic interrupt_; - mozilla::Atomic interruptPar_; - public: + /* + * If true, we've been asked to call the interrupt callback as soon as + * possible. + */ + mozilla::Atomic interrupt; - enum InterruptMode { - RequestInterruptMainThread, - RequestInterruptAnyThread, - RequestInterruptAnyThreadDontStopIon, - RequestInterruptAnyThreadForkJoin - }; - - // Any thread can call requestInterrupt() to request that the main JS thread - // stop running and call the interrupt callback (allowing the interrupt - // callback to halt execution). To stop the main JS thread, requestInterrupt - // sets two fields: interrupt_ (set to true) and jitStackLimit_ (set to - // UINTPTR_MAX). The JS engine must continually poll one of these fields - // and call handleInterrupt if either field has the interrupt value. (The - // point of setting jitStackLimit_ to UINTPTR_MAX is that JIT code already - // needs to guard on jitStackLimit_ in every function prologue to avoid - // stack overflow, so we avoid a second branch on interrupt_ by setting - // jitStackLimit_ to a value that is guaranteed to fail the guard.) - // - // Note that the writes to interrupt_ and jitStackLimit_ use a Relaxed - // Atomic so, while the writes are guaranteed to eventually be visible to - // the main thread, it can happen in any order. handleInterrupt calls the - // interrupt callback if either is set, so it really doesn't matter as long - // as the JS engine is continually polling at least one field. In corner - // cases, this relaxed ordering could lead to an interrupt handler being - // called twice in succession after a single requestInterrupt call, but - // that's fine. - void requestInterrupt(InterruptMode mode); - bool handleInterrupt(JSContext *cx); - - MOZ_ALWAYS_INLINE bool hasPendingInterrupt() const { - return interrupt_; - } - MOZ_ALWAYS_INLINE bool hasPendingInterruptPar() const { - return interruptPar_; - } - - // For read-only JIT use: - void *addressOfInterruptUint32() { - static_assert(sizeof(interrupt_) == sizeof(uint32_t), "Assumed by JIT callers"); - return &interrupt_; - } - void *addressOfInterruptParUint32() { - static_assert(sizeof(interruptPar_) == sizeof(uint32_t), "Assumed by JIT callers"); - return &interruptPar_; - } + /* + * If non-zero, ForkJoin should service an interrupt. This is a separate + * flag from |interrupt| because we cannot use the mprotect trick with PJS + * code and ignore the TriggerCallbackAnyThreadDontStopIon trigger. + */ + mozilla::Atomic interruptPar; /* Set when handling a signal for a thread associated with this runtime. */ bool handlingSignal; @@ -943,7 +900,7 @@ struct JSRuntime : public JS::shadow::Runtime, void setDefaultVersion(JSVersion v) { defaultVersion_ = v; } /* Base address of the native stack for the current thread. */ - const uintptr_t nativeStackBase; + uintptr_t nativeStackBase; /* The native stack size limit that runtime should not exceed. */ size_t nativeStackQuota[js::StackKindCount]; @@ -1309,6 +1266,10 @@ struct JSRuntime : public JS::shadow::Runtime, bool jitSupportsFloatingPoint; bool jitSupportsSimd; + // Used to reset stack limit after a signaled interrupt (i.e. jitStackLimit_ = -1) + // has been noticed by Ion/Baseline. + void resetJitStackLimit(); + // Cache for jit::GetPcScript(). js::jit::PcScriptCache *ionPcScriptCache; @@ -1369,6 +1330,17 @@ struct JSRuntime : public JS::shadow::Runtime, /* onOutOfMemory but can call the largeAllocationFailureCallback. */ JS_FRIEND_API(void *) onOutOfMemoryCanGC(void *p, size_t bytes); + // Ways in which the interrupt callback on the runtime can be triggered, + // varying based on which thread is triggering the callback. + enum InterruptMode { + RequestInterruptMainThread, + RequestInterruptAnyThread, + RequestInterruptAnyThreadDontStopIon, + RequestInterruptAnyThreadForkJoin + }; + + void requestInterrupt(InterruptMode mode); + void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes *runtime); private: @@ -1592,6 +1564,13 @@ class MOZ_STACK_CLASS AutoKeepAtoms } }; +inline void +PerThreadData::setJitStackLimit(uintptr_t limit) +{ + MOZ_ASSERT(runtime_->currentThreadOwnsInterruptLock()); + jitStackLimit = limit; +} + inline JSRuntime * PerThreadData::runtimeFromMainThread() { From 3f8b80262f56f8072747f0b89d1eea99531131dd Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Tue, 11 Nov 2014 15:15:04 -0500 Subject: [PATCH 39/47] Bug 1079837 - Disable resource-timing/test_resource_timing.html for frequent failures. CLOSED TREE --- .../meta/resource-timing/test_resource_timing.html.ini | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 testing/web-platform/meta/resource-timing/test_resource_timing.html.ini diff --git a/testing/web-platform/meta/resource-timing/test_resource_timing.html.ini b/testing/web-platform/meta/resource-timing/test_resource_timing.html.ini new file mode 100644 index 000000000000..b08fa726928c --- /dev/null +++ b/testing/web-platform/meta/resource-timing/test_resource_timing.html.ini @@ -0,0 +1,3 @@ +[test_resource_timing.html] + type: testharness + disabled: 1079837 From 6dac4045828cd404120957052e754df4d096cf45 Mon Sep 17 00:00:00 2001 From: James Willcox Date: Tue, 11 Nov 2014 14:46:06 -0600 Subject: [PATCH 40/47] Bug 1086693 - Part 1: Add SDKProcessor r=ckitching --- build/annotationProcessors/CodeGenerator.java | 22 ++ build/annotationProcessors/SDKProcessor.java | 214 ++++++++++++++++++ build/annotationProcessors/moz.build | 1 + 3 files changed, 237 insertions(+) create mode 100644 build/annotationProcessors/SDKProcessor.java diff --git a/build/annotationProcessors/CodeGenerator.java b/build/annotationProcessors/CodeGenerator.java index cb28e6fc4729..31d345022fe3 100644 --- a/build/annotationProcessors/CodeGenerator.java +++ b/build/annotationProcessors/CodeGenerator.java @@ -12,6 +12,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.HashSet; @@ -234,6 +235,27 @@ public class CodeGenerator { } } + public void generateMembers(Member[] members) { + for (Member m : members) { + if (!Modifier.isPublic(m.getModifiers())) { + continue; + } + + String name = m.getName(); + name = name.substring(0, 1).toUpperCase() + name.substring(1); + + AnnotationInfo info = new AnnotationInfo(name, true, true, true); + AnnotatableEntity entity = new AnnotatableEntity(m, info); + if (m instanceof Constructor) { + generateConstructor(entity); + } else if (m instanceof Method) { + generateMethod(entity); + } else if (m instanceof Field) { + generateField(entity); + } + } + } + /** * Writes the appropriate header and startup code to ensure the existence of a reference to the * class specified. If this is already done, does nothing. diff --git a/build/annotationProcessors/SDKProcessor.java b/build/annotationProcessors/SDKProcessor.java new file mode 100644 index 000000000000..26cce8d5a360 --- /dev/null +++ b/build/annotationProcessors/SDKProcessor.java @@ -0,0 +1,214 @@ +/* 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/. */ + +package org.mozilla.gecko.annotationProcessors; + +import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity; +import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions; +import org.mozilla.gecko.annotationProcessors.classloader.IterableJarLoadingURLClassLoader; +import org.mozilla.gecko.annotationProcessors.utils.GeneratableElementIterator; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Iterator; +import java.util.Scanner; +import java.util.Vector; +import java.net.URL; +import java.net.URLClassLoader; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +public class SDKProcessor { + public static final String GENERATED_COMMENT = + "// GENERATED CODE\n" + + "// Generated by the Java program at /build/annotationProcessors at compile time from\n" + + "// annotations on Java methods. To update, change the annotations on the corresponding Java\n" + + "// methods and rerun the build. Manually updating this file will cause your build to fail.\n\n"; + + public static void main(String[] args) { + // We expect a list of jars on the commandline. If missing, whinge about it. + if (args.length < 4) { + System.err.println("Usage: java SDKProcessor sdkjar classlistfile outdir fileprefix"); + System.exit(1); + } + + System.out.println("Processing platform bindings..."); + + String sdkJar = args[0]; + Vector classes = getClassList(args[1]); + String outdir = args[2]; + String generatedFilePrefix = args[3]; + + // Start the clock! + long s = System.currentTimeMillis(); + + // Get an iterator over the classes in the jar files given... + // Iterator jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args); + + StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT); + headerFile.append("#ifndef " + generatedFilePrefix + "_h__\n" + + "#define " + generatedFilePrefix + "_h__\n" + + "#include \"nsXPCOMStrings.h\"\n" + + "#include \"AndroidJavaWrappers.h\"\n" + + "\n" + + "namespace mozilla {\n" + + "namespace widget {\n" + + "namespace android {\n" + + "namespace sdk {\n" + + "void Init" + generatedFilePrefix + "Stubs(JNIEnv *jEnv);\n\n"); + + StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT); + implementationFile.append("#include \"" + generatedFilePrefix + ".h\"\n" + + "#include \"AndroidBridgeUtilities.h\"\n" + + "#include \"nsXPCOMStrings.h\"\n" + + "#include \"AndroidBridge.h\"\n" + + "\n" + + "namespace mozilla {\n" + + "namespace widget {\n" + + "namespace android {\n" + + "namespace sdk {\n"); + + // Used to track the calls to the various class-specific initialisation functions. + StringBuilder stubInitializer = new StringBuilder(); + stubInitializer.append("void Init" + generatedFilePrefix + "Stubs(JNIEnv *jEnv) {\n"); + + ClassLoader loader = null; + try { + loader = URLClassLoader.newInstance(new URL[] { new URL("file://" + sdkJar) }, + SDKProcessor.class.getClassLoader()); + } catch (Exception e) { + System.out.println(e); + } + + for (Iterator i = classes.iterator(); i.hasNext(); ) { + String className = i.next(); + System.out.println("looking up: " + className); + + try { + Class c = Class.forName(className, true, loader); + + generateClass(Class.forName(className, true, loader), + stubInitializer, + implementationFile, + headerFile); + } catch (Exception e) { + System.out.println("Failed to generate class " + className + ": " + e); + } + } + + implementationFile.append('\n'); + stubInitializer.append("}"); + implementationFile.append(stubInitializer); + + implementationFile.append("\n} /* sdk */\n" + + "} /* android */\n" + + "} /* widget */\n" + + "} /* mozilla */\n"); + + headerFile.append("\n} /* sdk */\n" + + "} /* android */\n" + + "} /* widget */\n" + + "} /* mozilla */\n" + + "#endif\n"); + + writeOutputFiles(outdir, generatedFilePrefix, headerFile, implementationFile); + long e = System.currentTimeMillis(); + System.out.println("SDK processing complete in " + (e - s) + "ms"); + } + + private static Member[] sortMembers(Member[] members) { + Arrays.sort(members, new Comparator() { + @Override + public int compare(Member a, Member b) { + return a.getName().compareTo(b.getName()); + } + }); + + return members; + } + + private static void generateClass(Class clazz, + StringBuilder stubInitializer, + StringBuilder implementationFile, + StringBuilder headerFile) { + String generatedName = clazz.getSimpleName(); + + CodeGenerator generator = new CodeGenerator(clazz, generatedName); + stubInitializer.append(" ").append(generatedName).append("::InitStubs(jEnv);\n"); + + generator.generateMembers(sortMembers(clazz.getDeclaredConstructors())); + generator.generateMembers(sortMembers(clazz.getDeclaredMethods())); + generator.generateMembers(sortMembers(clazz.getDeclaredFields())); + + headerFile.append(generator.getHeaderFileContents()); + implementationFile.append(generator.getWrapperFileContents()); + } + + private static Vector getClassList(String path) { + Scanner scanner = null; + try { + scanner = new Scanner(new FileInputStream(path)); + + Vector lines = new Vector(); + while (scanner.hasNextLine()) { + lines.add(scanner.nextLine()); + } + return lines; + } catch (Exception e) { + System.out.println(e.toString()); + return null; + } finally { + if (scanner != null) { + scanner.close(); + } + } + } + + private static void writeOutputFiles(String aOutputDir, String aPrefix, StringBuilder aHeaderFile, + StringBuilder aImplementationFile) { + FileOutputStream implStream = null; + try { + implStream = new FileOutputStream(new File(aOutputDir, aPrefix + ".cpp")); + implStream.write(aImplementationFile.toString().getBytes()); + } catch (IOException e) { + System.err.println("Unable to write " + aOutputDir + ". Perhaps a permissions issue?"); + e.printStackTrace(System.err); + } finally { + if (implStream != null) { + try { + implStream.close(); + } catch (IOException e) { + System.err.println("Unable to close implStream due to "+e); + e.printStackTrace(System.err); + } + } + } + + FileOutputStream headerStream = null; + try { + headerStream = new FileOutputStream(new File(aOutputDir, aPrefix + ".h")); + headerStream.write(aHeaderFile.toString().getBytes()); + } catch (IOException e) { + System.err.println("Unable to write " + aOutputDir + ". Perhaps a permissions issue?"); + e.printStackTrace(System.err); + } finally { + if (headerStream != null) { + try { + headerStream.close(); + } catch (IOException e) { + System.err.println("Unable to close headerStream due to "+e); + e.printStackTrace(System.err); + } + } + } + } +} \ No newline at end of file diff --git a/build/annotationProcessors/moz.build b/build/annotationProcessors/moz.build index 1fbf9938518e..c8e0fb8bdcfe 100644 --- a/build/annotationProcessors/moz.build +++ b/build/annotationProcessors/moz.build @@ -13,6 +13,7 @@ jar.sources += [ 'classloader/IterableJarLoadingURLClassLoader.java', 'classloader/JarClassIterator.java', 'CodeGenerator.java', + 'SDKProcessor.java', 'utils/AlphabeticAnnotatableEntityComparator.java', 'utils/GeneratableElementIterator.java', 'utils/Utils.java', From ecf0908ac2cc458b54dd8aa6202b7ede9becb311 Mon Sep 17 00:00:00 2001 From: Nick Alexander Date: Tue, 11 Nov 2014 14:46:07 -0600 Subject: [PATCH 41/47] Bug 1086693 - Part 2: Generate and build Android SDK JNI wrappers. r=gps --- build/annotationProcessors/Makefile.in | 2 +- config/recurse.mk | 1 + widget/android/bindings/Makefile.in | 26 +++++++++++++++++++ .../android/bindings/mediacodec-classes.txt | 3 +++ widget/android/bindings/moz.build | 24 +++++++++++++++++ .../bindings/surfacetexture-classes.txt | 2 ++ widget/android/moz.build | 4 +++ 7 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 widget/android/bindings/Makefile.in create mode 100644 widget/android/bindings/mediacodec-classes.txt create mode 100644 widget/android/bindings/moz.build create mode 100644 widget/android/bindings/surfacetexture-classes.txt diff --git a/build/annotationProcessors/Makefile.in b/build/annotationProcessors/Makefile.in index c7661c36fd5f..052669864be9 100644 --- a/build/annotationProcessors/Makefile.in +++ b/build/annotationProcessors/Makefile.in @@ -9,4 +9,4 @@ JAVA_CLASSPATH := $(ANDROID_SDK)/android.jar # Include Android specific java flags, instead of what's in rules.mk. include $(topsrcdir)/config/android-common.mk -libs:: annotationProcessors.jar +export:: annotationProcessors.jar diff --git a/config/recurse.mk b/config/recurse.mk index e22dde964d84..5ef0b8c26fb8 100644 --- a/config/recurse.mk +++ b/config/recurse.mk @@ -141,6 +141,7 @@ ifeq (.,$(DEPTH)) # Interdependencies for parallel export. js/xpconnect/src/export: dom/bindings/export xpcom/xpidl/export accessible/xpcom/export: xpcom/xpidl/export +widget/android/bindings/export: build/annotationProcessors/export ifdef ENABLE_CLANG_PLUGIN $(filter-out build/clang-plugin/%,$(compile_targets)): build/clang-plugin/target build/clang-plugin/tests/target build/clang-plugin/tests/target: build/clang-plugin/target diff --git a/widget/android/bindings/Makefile.in b/widget/android/bindings/Makefile.in new file mode 100644 index 000000000000..d9ee1896ea01 --- /dev/null +++ b/widget/android/bindings/Makefile.in @@ -0,0 +1,26 @@ +# 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/. + +ANNOTATION_PROCESSOR_JAR_FILES := $(DEPTH)/build/annotationProcessors/annotationProcessors.jar + +MediaCodec.cpp: $(ANDROID_SDK)/android.jar mediacodec-classes.txt + $(JAVA) -classpath $(ANNOTATION_PROCESSOR_JAR_FILES) org.mozilla.gecko.annotationProcessors.SDKProcessor $(ANDROID_SDK)/android.jar $(srcdir)/mediacodec-classes.txt $(CURDIR) MediaCodec + +MediaCodec.h: MediaCodec.cpp ; + +SurfaceTexture.cpp: $(ANDROID_SDK)/android.jar surfacetexture-classes.txt + $(JAVA) -classpath $(ANNOTATION_PROCESSOR_JAR_FILES) org.mozilla.gecko.annotationProcessors.SDKProcessor $(ANDROID_SDK)/android.jar $(srcdir)/surfacetexture-classes.txt $(CURDIR) SurfaceTexture + +SurfaceTexture.h: SurfaceTexture.cpp ; + +# We'd like these to be defined in a future GENERATED_EXPORTS list. +bindings_exports := \ + MediaCodec.h \ + SurfaceTexture.h \ + $(NULL) + +INSTALL_TARGETS += bindings_exports +bindings_exports_FILES := $(bindings_exports) +bindings_exports_DEST = $(DIST)/include +bindings_exports_TARGET := export diff --git a/widget/android/bindings/mediacodec-classes.txt b/widget/android/bindings/mediacodec-classes.txt new file mode 100644 index 000000000000..d8fb3420d3d5 --- /dev/null +++ b/widget/android/bindings/mediacodec-classes.txt @@ -0,0 +1,3 @@ +android.media.MediaCodec +android.media.MediaCodec$BufferInfo +android.media.MediaFormat diff --git a/widget/android/bindings/moz.build b/widget/android/bindings/moz.build new file mode 100644 index 000000000000..c446a76bac36 --- /dev/null +++ b/widget/android/bindings/moz.build @@ -0,0 +1,24 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +GENERATED_SOURCES += [ + 'MediaCodec.cpp', + 'SurfaceTexture.cpp', +] + +# We'd like to add these to a future GENERATED_EXPORTS list, but for now we mark +# them as generated here and manually install them in Makefile.in. +GENERATED_INCLUDES += [ + 'MediaCodec.h', + 'SurfaceTexture.h', +] + +FAIL_ON_WARNINGS = True +FINAL_LIBRARY = 'xul' + +LOCAL_INCLUDES += [ + '/widget/android', +] diff --git a/widget/android/bindings/surfacetexture-classes.txt b/widget/android/bindings/surfacetexture-classes.txt new file mode 100644 index 000000000000..5c7ca8968860 --- /dev/null +++ b/widget/android/bindings/surfacetexture-classes.txt @@ -0,0 +1,2 @@ +android.graphics.SurfaceTexture +android.view.Surface diff --git a/widget/android/moz.build b/widget/android/moz.build index 78873655b283..70651dc215aa 100644 --- a/widget/android/moz.build +++ b/widget/android/moz.build @@ -4,6 +4,10 @@ # 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/. +DIRS += [ + 'bindings', +] + XPIDL_SOURCES += [ 'nsIAndroidBridge.idl', ] From d8a8a83fae45468d0b4eb9862c2e2d291e71d7e4 Mon Sep 17 00:00:00 2001 From: James Willcox Date: Tue, 11 Nov 2014 14:46:07 -0600 Subject: [PATCH 42/47] Bug 1086693 - Part 3: Don't generate members that are above a given API version r=ckitching --- build/annotationProcessors/CodeGenerator.java | 2 + build/annotationProcessors/Makefile.in | 2 +- build/annotationProcessors/SDKProcessor.java | 55 ++++++++++++++++--- build/annotationProcessors/utils/Utils.java | 8 ++- widget/android/bindings/Makefile.in | 6 +- 5 files changed, 60 insertions(+), 13 deletions(-) diff --git a/build/annotationProcessors/CodeGenerator.java b/build/annotationProcessors/CodeGenerator.java index 31d345022fe3..15843c5c7507 100644 --- a/build/annotationProcessors/CodeGenerator.java +++ b/build/annotationProcessors/CodeGenerator.java @@ -252,6 +252,8 @@ public class CodeGenerator { generateMethod(entity); } else if (m instanceof Field) { generateField(entity); + } else { + throw new IllegalArgumentException("expected member to be Constructor, Method, or Field"); } } } diff --git a/build/annotationProcessors/Makefile.in b/build/annotationProcessors/Makefile.in index 052669864be9..b21a52bbd1ff 100644 --- a/build/annotationProcessors/Makefile.in +++ b/build/annotationProcessors/Makefile.in @@ -4,7 +4,7 @@ include $(topsrcdir)/config/rules.mk -JAVA_CLASSPATH := $(ANDROID_SDK)/android.jar +JAVA_CLASSPATH := $(ANDROID_SDK)/android.jar:$(ANDROID_SDK)/../../tools/lib/lint.jar:$(ANDROID_SDK)/../../tools/lib/lint-checks.jar # Include Android specific java flags, instead of what's in rules.mk. include $(topsrcdir)/config/android-common.mk diff --git a/build/annotationProcessors/SDKProcessor.java b/build/annotationProcessors/SDKProcessor.java index 26cce8d5a360..48d7dc8e7ff0 100644 --- a/build/annotationProcessors/SDKProcessor.java +++ b/build/annotationProcessors/SDKProcessor.java @@ -4,18 +4,24 @@ package org.mozilla.gecko.annotationProcessors; +import com.android.tools.lint.checks.ApiLookup; +import com.android.tools.lint.LintCliClient; + import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity; import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions; import org.mozilla.gecko.annotationProcessors.classloader.IterableJarLoadingURLClassLoader; import org.mozilla.gecko.annotationProcessors.utils.GeneratableElementIterator; +import org.mozilla.gecko.annotationProcessors.utils.Utils; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Arrays; +import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; +import java.util.Properties; import java.util.Scanner; import java.util.Vector; import java.net.URL; @@ -34,10 +40,13 @@ public class SDKProcessor { "// annotations on Java methods. To update, change the annotations on the corresponding Java\n" + "// methods and rerun the build. Manually updating this file will cause your build to fail.\n\n"; + private static ApiLookup sApiLookup; + private static int sMaxSdkVersion; + public static void main(String[] args) { // We expect a list of jars on the commandline. If missing, whinge about it. - if (args.length < 4) { - System.err.println("Usage: java SDKProcessor sdkjar classlistfile outdir fileprefix"); + if (args.length < 5) { + System.err.println("Usage: java SDKProcessor sdkjar classlistfile outdir fileprefix max-sdk-version"); System.exit(1); } @@ -47,6 +56,14 @@ public class SDKProcessor { Vector classes = getClassList(args[1]); String outdir = args[2]; String generatedFilePrefix = args[3]; + sMaxSdkVersion = Integer.parseInt(args[4]); + + Properties props = System.getProperties(); + props.setProperty("com.android.tools.lint.bindir", + new File(new File(sdkJar).getParentFile(), "../../tools").toString()); + + LintCliClient lintClient = new LintCliClient(); + sApiLookup = ApiLookup.get(lintClient); // Start the clock! long s = System.currentTimeMillis(); @@ -125,7 +142,7 @@ public class SDKProcessor { System.out.println("SDK processing complete in " + (e - s) + "ms"); } - private static Member[] sortMembers(Member[] members) { + private static Member[] sortAndFilterMembers(Member[] members) { Arrays.sort(members, new Comparator() { @Override public int compare(Member a, Member b) { @@ -133,7 +150,31 @@ public class SDKProcessor { } }); - return members; + ArrayList list = new ArrayList<>(); + for (Member m : members) { + int version = 0; + + if (m instanceof Method || m instanceof Constructor) { + version = sApiLookup.getCallVersion(Utils.getTypeSignatureStringForClass(m.getDeclaringClass()), + m.getName(), + Utils.getTypeSignatureStringForMember(m)); + } else if (m instanceof Field) { + version = sApiLookup.getFieldVersion(Utils.getTypeSignatureStringForClass(m.getDeclaringClass()), + m.getName()); + } else { + throw new IllegalArgumentException("expected member to be Method, Constructor, or Field"); + } + + if (version > sMaxSdkVersion) { + System.out.println("Skipping " + m.getDeclaringClass().getName() + "." + m.getName() + + ", version " + version + " > " + sMaxSdkVersion); + continue; + } + + list.add(m); + } + + return list.toArray(new Member[list.size()]); } private static void generateClass(Class clazz, @@ -145,9 +186,9 @@ public class SDKProcessor { CodeGenerator generator = new CodeGenerator(clazz, generatedName); stubInitializer.append(" ").append(generatedName).append("::InitStubs(jEnv);\n"); - generator.generateMembers(sortMembers(clazz.getDeclaredConstructors())); - generator.generateMembers(sortMembers(clazz.getDeclaredMethods())); - generator.generateMembers(sortMembers(clazz.getDeclaredFields())); + generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredConstructors())); + generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredMethods())); + generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredFields())); headerFile.append(generator.getHeaderFileContents()); implementationFile.append(generator.getWrapperFileContents()); diff --git a/build/annotationProcessors/utils/Utils.java b/build/annotationProcessors/utils/Utils.java index f13ae66e1461..fbb13ff27cbd 100644 --- a/build/annotationProcessors/utils/Utils.java +++ b/build/annotationProcessors/utils/Utils.java @@ -318,6 +318,10 @@ public class Utils { } } + public static String getTypeSignatureStringForClass(Class clazz) { + return clazz.getCanonicalName().replace('.', '/'); + } + public static String getTypeSignatureString(Constructor aConstructor) { Class[] arguments = aConstructor.getParameterTypes(); StringBuilder sb = new StringBuilder(); @@ -341,7 +345,7 @@ public class Utils { * @param c The type of the element to write the subsignature of. */ private static void writeTypeSignature(StringBuilder sb, Class c) { - String name = c.getCanonicalName().replaceAll("\\.", "/"); + String name = Utils.getTypeSignatureStringForClass(c); // Determine if this is an array type and, if so, peel away the array operators.. int len = name.length(); @@ -589,7 +593,7 @@ public class Utils { sb.append(getClassReferenceName(aClass)); sb.append(" = getClassGlobalRef(\""); - String name = aClass.getCanonicalName().replaceAll("\\.", "/"); + String name = Utils.getTypeSignatureStringForClass(aClass); Class containerClass = aClass.getDeclaringClass(); if (containerClass != null) { // Is an inner class. Add the $ symbol. diff --git a/widget/android/bindings/Makefile.in b/widget/android/bindings/Makefile.in index d9ee1896ea01..8a069f18f1cc 100644 --- a/widget/android/bindings/Makefile.in +++ b/widget/android/bindings/Makefile.in @@ -2,15 +2,15 @@ # 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/. -ANNOTATION_PROCESSOR_JAR_FILES := $(DEPTH)/build/annotationProcessors/annotationProcessors.jar +ANNOTATION_PROCESSOR_JAR_FILES := $(DEPTH)/build/annotationProcessors/annotationProcessors.jar:$(ANDROID_SDK)/android.jar:$(ANDROID_SDK)/../../tools/lib/lint.jar:$(ANDROID_SDK)/../../tools/lib/lint-checks.jar MediaCodec.cpp: $(ANDROID_SDK)/android.jar mediacodec-classes.txt - $(JAVA) -classpath $(ANNOTATION_PROCESSOR_JAR_FILES) org.mozilla.gecko.annotationProcessors.SDKProcessor $(ANDROID_SDK)/android.jar $(srcdir)/mediacodec-classes.txt $(CURDIR) MediaCodec + $(JAVA) -classpath $(ANNOTATION_PROCESSOR_JAR_FILES) org.mozilla.gecko.annotationProcessors.SDKProcessor $(ANDROID_SDK)/android.jar $(srcdir)/mediacodec-classes.txt $(CURDIR) MediaCodec 16 MediaCodec.h: MediaCodec.cpp ; SurfaceTexture.cpp: $(ANDROID_SDK)/android.jar surfacetexture-classes.txt - $(JAVA) -classpath $(ANNOTATION_PROCESSOR_JAR_FILES) org.mozilla.gecko.annotationProcessors.SDKProcessor $(ANDROID_SDK)/android.jar $(srcdir)/surfacetexture-classes.txt $(CURDIR) SurfaceTexture + $(JAVA) -classpath $(ANNOTATION_PROCESSOR_JAR_FILES) org.mozilla.gecko.annotationProcessors.SDKProcessor $(ANDROID_SDK)/android.jar $(srcdir)/surfacetexture-classes.txt $(CURDIR) SurfaceTexture 16 SurfaceTexture.h: SurfaceTexture.cpp ; From c94a9e76f7cea52308bbe76a50f4a8cec729e601 Mon Sep 17 00:00:00 2001 From: James Willcox Date: Tue, 11 Nov 2014 14:46:07 -0600 Subject: [PATCH 43/47] Bug 1086693 - Part 4: Add a lazy initialization mode to CodeGenerator, and use it for SDK bindings r=ckitching --- .../AnnotationProcessor.java | 6 +- build/annotationProcessors/CodeGenerator.java | 83 ++-- build/annotationProcessors/SDKProcessor.java | 4 +- build/annotationProcessors/utils/Utils.java | 2 +- widget/android/GeneratedJNIWrappers.cpp | 438 ++++++++---------- widget/android/GeneratedJNIWrappers.h | 38 +- 6 files changed, 282 insertions(+), 289 deletions(-) diff --git a/build/annotationProcessors/AnnotationProcessor.java b/build/annotationProcessors/AnnotationProcessor.java index bcd70a58ee8f..66c3918d2744 100644 --- a/build/annotationProcessors/AnnotationProcessor.java +++ b/build/annotationProcessors/AnnotationProcessor.java @@ -52,7 +52,7 @@ public class AnnotationProcessor { "namespace mozilla {\n" + "namespace widget {\n" + "namespace android {\n" + - "void InitStubs(JNIEnv *jEnv);\n\n"); + "void InitStubs(JNIEnv *env);\n\n"); StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT); implementationFile.append("#include \"GeneratedJNIWrappers.h\"\n" + @@ -66,7 +66,7 @@ public class AnnotationProcessor { // Used to track the calls to the various class-specific initialisation functions. StringBuilder stubInitialiser = new StringBuilder(); - stubInitialiser.append("void InitStubs(JNIEnv *jEnv) {\n"); + stubInitialiser.append("void InitStubs(JNIEnv *env) {\n"); while (jarClassIterator.hasNext()) { ClassWithOptions aClassTuple = jarClassIterator.next(); @@ -81,7 +81,7 @@ public class AnnotationProcessor { } generatorInstance = new CodeGenerator(aClassTuple.wrappedClass, aClassTuple.generatedName); - stubInitialiser.append(" ").append(aClassTuple.generatedName).append("::InitStubs(jEnv);\n"); + stubInitialiser.append(" ").append(aClassTuple.generatedName).append("::InitStubs(env);\n"); // Iterate all annotated members in this class.. while (methodIterator.hasNext()) { diff --git a/build/annotationProcessors/CodeGenerator.java b/build/annotationProcessors/CodeGenerator.java index 15843c5c7507..b172f33e8f30 100644 --- a/build/annotationProcessors/CodeGenerator.java +++ b/build/annotationProcessors/CodeGenerator.java @@ -41,21 +41,27 @@ public class CodeGenerator { private final HashSet mTakenMemberNames = new HashSet(); private int mNameMunger; + private final boolean mLazyInit; + public CodeGenerator(Class aClass, String aGeneratedName) { + this(aClass, aGeneratedName, false); + } + + public CodeGenerator(Class aClass, String aGeneratedName, boolean aLazyInit) { mClassToWrap = aClass; mCClassName = aGeneratedName; + mLazyInit = aLazyInit; // Write the file header things. Includes and so forth. // GeneratedJNIWrappers.cpp is generated as the concatenation of wrapperStartupCode with // wrapperMethodBodies. Similarly, GeneratedJNIWrappers.h is the concatenation of headerPublic // with headerProtected. - wrapperStartupCode.append("void ").append(mCClassName).append("::InitStubs(JNIEnv *jEnv) {\n" + - " initInit();\n"); + wrapperStartupCode.append("void ").append(mCClassName).append("::InitStubs(JNIEnv *env) {\n"); // Now we write the various GetStaticMethodID calls here... headerPublic.append("class ").append(mCClassName).append(" : public AutoGlobalWrappedJavaObject {\n" + "public:\n" + - " static void InitStubs(JNIEnv *jEnv);\n"); + " static void InitStubs(JNIEnv *env);\n"); headerProtected.append("protected:"); generateWrapperMethod(); @@ -80,7 +86,10 @@ public class CodeGenerator { private void generateMemberCommon(Member theMethod, String aCMethodName, Class aClass) { ensureClassHeaderAndStartup(aClass); writeMemberIdField(theMethod, aCMethodName); - writeStartupCode(theMethod); + + if (!mLazyInit) { + writeMemberInit(theMethod, wrapperStartupCode); + } } /** @@ -115,16 +124,21 @@ public class CodeGenerator { aMethodTuple.mAnnotationInfo.narrowChars); } - private void generateGetterOrSetterBody(Class aFieldType, String aFieldName, boolean aIsFieldStatic, boolean isSetter, boolean aNarrowChars) { + private void generateGetterOrSetterBody(Field aField, String aFieldName, boolean aIsFieldStatic, boolean isSetter, boolean aNarrowChars) { StringBuilder argumentContent = null; + Class fieldType = aField.getType(); if (isSetter) { - Class[] setterArguments = new Class[]{aFieldType}; + Class[] setterArguments = new Class[]{fieldType}; // Marshall the argument.. argumentContent = getArgumentMarshalling(setterArguments); } - boolean isObjectReturningMethod = Utils.isObjectType(aFieldType); + if (mLazyInit) { + writeMemberInit(aField, wrapperMethodBodies); + } + + boolean isObjectReturningMethod = Utils.isObjectType(fieldType); wrapperMethodBodies.append(" "); if (isSetter) { wrapperMethodBodies.append("env->Set"); @@ -132,7 +146,7 @@ public class CodeGenerator { wrapperMethodBodies.append("return "); if (isObjectReturningMethod) { - wrapperMethodBodies.append("static_cast<").append(Utils.getCReturnType(aFieldType, aNarrowChars)).append(">("); + wrapperMethodBodies.append("static_cast<").append(Utils.getCReturnType(fieldType, aNarrowChars)).append(">("); } wrapperMethodBodies.append("env->Get"); @@ -141,7 +155,7 @@ public class CodeGenerator { if (aIsFieldStatic) { wrapperMethodBodies.append("Static"); } - wrapperMethodBodies.append(Utils.getFieldType(aFieldType)) + wrapperMethodBodies.append(Utils.getFieldType(fieldType)) .append("Field("); // Static will require the class and the field id. Nonstatic, the object and the field id. @@ -189,7 +203,7 @@ public class CodeGenerator { writeFunctionStartupBoilerPlate(getterSignature, true); - generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, false, aFieldTuple.mAnnotationInfo.narrowChars); + generateGetterOrSetterBody(theField, CFieldName, isFieldStatic, false, aFieldTuple.mAnnotationInfo.narrowChars); // If field not final, also generate a setter function. if (!isFieldFinal) { @@ -204,7 +218,7 @@ public class CodeGenerator { writeFunctionStartupBoilerPlate(setterSignature, true); - generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, true, aFieldTuple.mAnnotationInfo.narrowChars); + generateGetterOrSetterBody(theField, CFieldName, isFieldStatic, true, aFieldTuple.mAnnotationInfo.narrowChars); } } @@ -282,8 +296,7 @@ public class CodeGenerator { .append(";\n"); // Add startup code to populate it.. - wrapperStartupCode.append('\n') - .append(Utils.getStartupLineForClass(aClass)); + wrapperStartupCode.append(Utils.getStartupLineForClass(aClass)); seenClasses.add(className); } @@ -403,6 +416,10 @@ public class CodeGenerator { writeFramePushBoilerplate(theCtor, false, aNoThrow); + if (mLazyInit) { + writeMemberInit(theCtor, wrapperMethodBodies); + } + // Marshall arguments for this constructor, if any... boolean hasArguments = argumentTypes.length != 0; @@ -451,6 +468,10 @@ public class CodeGenerator { writeFramePushBoilerplate(aMethod, isObjectReturningMethod, aNoThrow); + if (mLazyInit) { + writeMemberInit(aMethod, wrapperMethodBodies); + } + // Marshall arguments, if we have any. boolean hasArguments = argumentTypes.length != 0; @@ -525,33 +546,41 @@ public class CodeGenerator { } /** - * Generates the code to get the id of the given member on startup. + * Generates the code to get the id of the given member on startup or in the member body if lazy init + * is requested. * * @param aMember The Java member being wrapped. */ - private void writeStartupCode(Member aMember) { - wrapperStartupCode.append(" ") - .append(mMembersToIds.get(aMember)) - .append(" = get"); + private void writeMemberInit(Member aMember, StringBuilder aOutput) { + if (mLazyInit) { + aOutput.append(" if (!" + mMembersToIds.get(aMember) + ") {\n "); + } + + aOutput.append(" " + mMembersToIds.get(aMember)).append(" = AndroidBridge::Get"); if (Utils.isMemberStatic(aMember)) { - wrapperStartupCode.append("Static"); + aOutput.append("Static"); } boolean isField = aMember instanceof Field; if (isField) { - wrapperStartupCode.append("Field(\""); + aOutput.append("FieldID(env, " + Utils.getClassReferenceName(aMember.getDeclaringClass()) + ", \""); } else { - wrapperStartupCode.append("Method(\""); - } - if (aMember instanceof Constructor) { - wrapperStartupCode.append(""); - } else { - wrapperStartupCode.append(aMember.getName()); + aOutput.append("MethodID(env, " + Utils.getClassReferenceName(aMember.getDeclaringClass()) + ", \""); } - wrapperStartupCode.append("\", \"") + if (aMember instanceof Constructor) { + aOutput.append(""); + } else { + aOutput.append(aMember.getName()); + } + + aOutput.append("\", \"") .append(Utils.getTypeSignatureStringForMember(aMember)) .append("\");\n"); + + if (mLazyInit) { + aOutput.append(" }\n\n"); + } } private void writeZeroingFor(Member aMember, final String aMemberName) { diff --git a/build/annotationProcessors/SDKProcessor.java b/build/annotationProcessors/SDKProcessor.java index 48d7dc8e7ff0..2eab460468a8 100644 --- a/build/annotationProcessors/SDKProcessor.java +++ b/build/annotationProcessors/SDKProcessor.java @@ -108,7 +108,7 @@ public class SDKProcessor { for (Iterator i = classes.iterator(); i.hasNext(); ) { String className = i.next(); - System.out.println("looking up: " + className); + System.out.println("Looking up: " + className); try { Class c = Class.forName(className, true, loader); @@ -183,7 +183,7 @@ public class SDKProcessor { StringBuilder headerFile) { String generatedName = clazz.getSimpleName(); - CodeGenerator generator = new CodeGenerator(clazz, generatedName); + CodeGenerator generator = new CodeGenerator(clazz, generatedName, true); stubInitializer.append(" ").append(generatedName).append("::InitStubs(jEnv);\n"); generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredConstructors())); diff --git a/build/annotationProcessors/utils/Utils.java b/build/annotationProcessors/utils/Utils.java index fbb13ff27cbd..89f70dc8b5fb 100644 --- a/build/annotationProcessors/utils/Utils.java +++ b/build/annotationProcessors/utils/Utils.java @@ -591,7 +591,7 @@ public class Utils { StringBuilder sb = new StringBuilder(); sb.append(" "); sb.append(getClassReferenceName(aClass)); - sb.append(" = getClassGlobalRef(\""); + sb.append(" = AndroidBridge::GetClassGlobalRef(env, \""); String name = Utils.getTypeSignatureStringForClass(aClass); Class containerClass = aClass.getDeclaringClass(); diff --git a/widget/android/GeneratedJNIWrappers.cpp b/widget/android/GeneratedJNIWrappers.cpp index 304849b91b72..e8aed3f5a092 100644 --- a/widget/android/GeneratedJNIWrappers.cpp +++ b/widget/android/GeneratedJNIWrappers.cpp @@ -13,11 +13,9 @@ namespace widget { namespace android { jclass DownloadsIntegration::mDownloadsIntegrationClass = 0; jmethodID DownloadsIntegration::jScanMedia = 0; -void DownloadsIntegration::InitStubs(JNIEnv *jEnv) { - initInit(); - - mDownloadsIntegrationClass = getClassGlobalRef("org/mozilla/gecko/DownloadsIntegration"); - jScanMedia = getStaticMethod("scanMedia", "(Ljava/lang/String;Ljava/lang/String;)V"); +void DownloadsIntegration::InitStubs(JNIEnv *env) { + mDownloadsIntegrationClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/DownloadsIntegration"); + jScanMedia = AndroidBridge::GetStaticMethodID(env, mDownloadsIntegrationClass, "scanMedia", "(Ljava/lang/String;Ljava/lang/String;)V"); } DownloadsIntegration* DownloadsIntegration::Wrap(jobject obj) { @@ -124,92 +122,90 @@ jmethodID GeckoAppShell::jUnlockScreenOrientation = 0; jmethodID GeckoAppShell::jUnregisterSurfaceTextureFrameListener = 0; jmethodID GeckoAppShell::jVibrate1 = 0; jmethodID GeckoAppShell::jVibrateA = 0; -void GeckoAppShell::InitStubs(JNIEnv *jEnv) { - initInit(); - - mGeckoAppShellClass = getClassGlobalRef("org/mozilla/gecko/GeckoAppShell"); - jAcknowledgeEvent = getStaticMethod("acknowledgeEvent", "()V"); - jAddPluginViewWrapper = getStaticMethod("addPluginView", "(Landroid/view/View;FFFFZ)V"); - jAlertsProgressListener_OnProgress = getStaticMethod("alertsProgressListener_OnProgress", "(Ljava/lang/String;JJLjava/lang/String;)V"); - jCancelVibrate = getStaticMethod("cancelVibrate", "()V"); - jCheckURIVisited = getStaticMethod("checkUriVisited", "(Ljava/lang/String;)V"); - jClearMessageList = getStaticMethod("clearMessageList", "(I)V"); - jCloseCamera = getStaticMethod("closeCamera", "()V"); - jCloseNotification = getStaticMethod("closeNotification", "(Ljava/lang/String;)V"); - jConnectionGetMimeType = getStaticMethod("connectionGetMimeType", "(Ljava/net/URLConnection;)Ljava/lang/String;"); - jCreateInputStream = getStaticMethod("createInputStream", "(Ljava/net/URLConnection;)Ljava/io/InputStream;"); - jCreateMessageListWrapper = getStaticMethod("createMessageList", "(JJ[Ljava/lang/String;ILjava/lang/String;ZZJZI)V"); - jCreateShortcut = getStaticMethod("createShortcut", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); - jDeleteMessageWrapper = getStaticMethod("deleteMessage", "(II)V"); - jDisableBatteryNotifications = getStaticMethod("disableBatteryNotifications", "()V"); - jDisableNetworkNotifications = getStaticMethod("disableNetworkNotifications", "()V"); - jDisableScreenOrientationNotifications = getStaticMethod("disableScreenOrientationNotifications", "()V"); - jDisableSensor = getStaticMethod("disableSensor", "(I)V"); - jEnableBatteryNotifications = getStaticMethod("enableBatteryNotifications", "()V"); - jEnableLocation = getStaticMethod("enableLocation", "(Z)V"); - jEnableLocationHighAccuracy = getStaticMethod("enableLocationHighAccuracy", "(Z)V"); - jEnableNetworkNotifications = getStaticMethod("enableNetworkNotifications", "()V"); - jEnableScreenOrientationNotifications = getStaticMethod("enableScreenOrientationNotifications", "()V"); - jEnableSensor = getStaticMethod("enableSensor", "(I)V"); - jGamepadAdded = getStaticMethod("gamepadAdded", "(II)V"); - jGetConnection = getStaticMethod("getConnection", "(Ljava/lang/String;)Ljava/net/URLConnection;"); - jGetContext = getStaticMethod("getContext", "()Landroid/content/Context;"); - jGetCurrentBatteryInformationWrapper = getStaticMethod("getCurrentBatteryInformation", "()[D"); - jGetCurrentNetworkInformationWrapper = getStaticMethod("getCurrentNetworkInformation", "()[D"); - jGetDensity = getStaticMethod("getDensity", "()F"); - jGetDpiWrapper = getStaticMethod("getDpi", "()I"); - jGetExtensionFromMimeTypeWrapper = getStaticMethod("getExtensionFromMimeType", "(Ljava/lang/String;)Ljava/lang/String;"); - jGetExternalPublicDirectory = getStaticMethod("getExternalPublicDirectory", "(Ljava/lang/String;)Ljava/lang/String;"); - jGetHandlersForMimeTypeWrapper = getStaticMethod("getHandlersForMimeType", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"); - jGetHandlersForURLWrapper = getStaticMethod("getHandlersForURL", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"); - jGetIconForExtensionWrapper = getStaticMethod("getIconForExtension", "(Ljava/lang/String;I)[B"); - jGetMessageWrapper = getStaticMethod("getMessage", "(II)V"); - jGetMimeTypeFromExtensionsWrapper = getStaticMethod("getMimeTypeFromExtensions", "(Ljava/lang/String;)Ljava/lang/String;"); - jGetNextMessageInListWrapper = getStaticMethod("getNextMessageInList", "(II)V"); - jGetProxyForURIWrapper = getStaticMethod("getProxyForURI", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;"); - jGetScreenDepthWrapper = getStaticMethod("getScreenDepth", "()I"); - jGetScreenOrientationWrapper = getStaticMethod("getScreenOrientation", "()S"); - jGetShowPasswordSetting = getStaticMethod("getShowPasswordSetting", "()Z"); - jGetSystemColoursWrapper = getStaticMethod("getSystemColors", "()[I"); - jHandleGeckoMessageWrapper = getStaticMethod("handleGeckoMessage", "(Lorg/mozilla/gecko/util/NativeJSContainer;)V"); - jHandleUncaughtException = getStaticMethod("handleUncaughtException", "(Ljava/lang/Thread;Ljava/lang/Throwable;)V"); - jHideProgressDialog = getStaticMethod("hideProgressDialog", "()V"); - jInitCameraWrapper = getStaticMethod("initCamera", "(Ljava/lang/String;III)[I"); - jIsNetworkLinkKnown = getStaticMethod("isNetworkLinkKnown", "()Z"); - jIsNetworkLinkUp = getStaticMethod("isNetworkLinkUp", "()Z"); - jIsTablet = getStaticMethod("isTablet", "()Z"); - jKillAnyZombies = getStaticMethod("killAnyZombies", "()V"); - jLoadPluginClass = getStaticMethod("loadPluginClass", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;"); - jLockScreenOrientation = getStaticMethod("lockScreenOrientation", "(I)V"); - jMarkURIVisited = getStaticMethod("markUriVisited", "(Ljava/lang/String;)V"); - jMoveTaskToBack = getStaticMethod("moveTaskToBack", "()V"); - jNetworkLinkType = getStaticMethod("networkLinkType", "()I"); - jNotifyDefaultPrevented = getStaticMethod("notifyDefaultPrevented", "(Z)V"); - jNotifyIME = getStaticMethod("notifyIME", "(I)V"); - jNotifyIMEChange = getStaticMethod("notifyIMEChange", "(Ljava/lang/String;III)V"); - jNotifyIMEContext = getStaticMethod("notifyIMEContext", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); - jNotifyWakeLockChanged = getStaticMethod("notifyWakeLockChanged", "(Ljava/lang/String;Ljava/lang/String;)V"); - jNotifyXreExit = getStaticMethod("onXreExit", "()V"); - jOpenUriExternal = getStaticMethod("openUriExternal", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z"); - jPerformHapticFeedback = getStaticMethod("performHapticFeedback", "(Z)V"); - jPumpMessageLoop = getStaticMethod("pumpMessageLoop", "()Z"); - jRegisterSurfaceTextureFrameListener = getStaticMethod("registerSurfaceTextureFrameListener", "(Ljava/lang/Object;I)V"); - jRemovePluginView = getStaticMethod("removePluginView", "(Landroid/view/View;Z)V"); - jRequestUiThreadCallback = getStaticMethod("requestUiThreadCallback", "(J)V"); - jScheduleRestart = getStaticMethod("scheduleRestart", "()V"); - jSendMessageWrapper = getStaticMethod("sendMessage", "(Ljava/lang/String;Ljava/lang/String;I)V"); - jSetFullScreen = getStaticMethod("setFullScreen", "(Z)V"); - jSetKeepScreenOn = getStaticMethod("setKeepScreenOn", "(Z)V"); - jSetURITitle = getStaticMethod("setUriTitle", "(Ljava/lang/String;Ljava/lang/String;)V"); - jShowAlertNotificationWrapper = getStaticMethod("showAlertNotification", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); - jShowInputMethodPicker = getStaticMethod("showInputMethodPicker", "()V"); - jStartMonitoringGamepad = getStaticMethod("startMonitoringGamepad", "()V"); - jStopMonitoringGamepad = getStaticMethod("stopMonitoringGamepad", "()V"); - jUnlockProfile = getStaticMethod("unlockProfile", "()Z"); - jUnlockScreenOrientation = getStaticMethod("unlockScreenOrientation", "()V"); - jUnregisterSurfaceTextureFrameListener = getStaticMethod("unregisterSurfaceTextureFrameListener", "(Ljava/lang/Object;)V"); - jVibrate1 = getStaticMethod("vibrate", "(J)V"); - jVibrateA = getStaticMethod("vibrate", "([JI)V"); +void GeckoAppShell::InitStubs(JNIEnv *env) { + mGeckoAppShellClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/GeckoAppShell"); + jAcknowledgeEvent = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "acknowledgeEvent", "()V"); + jAddPluginViewWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "addPluginView", "(Landroid/view/View;FFFFZ)V"); + jAlertsProgressListener_OnProgress = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "alertsProgressListener_OnProgress", "(Ljava/lang/String;JJLjava/lang/String;)V"); + jCancelVibrate = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "cancelVibrate", "()V"); + jCheckURIVisited = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "checkUriVisited", "(Ljava/lang/String;)V"); + jClearMessageList = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "clearMessageList", "(I)V"); + jCloseCamera = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "closeCamera", "()V"); + jCloseNotification = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "closeNotification", "(Ljava/lang/String;)V"); + jConnectionGetMimeType = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "connectionGetMimeType", "(Ljava/net/URLConnection;)Ljava/lang/String;"); + jCreateInputStream = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "createInputStream", "(Ljava/net/URLConnection;)Ljava/io/InputStream;"); + jCreateMessageListWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "createMessageList", "(JJ[Ljava/lang/String;ILjava/lang/String;ZZJZI)V"); + jCreateShortcut = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "createShortcut", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + jDeleteMessageWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "deleteMessage", "(II)V"); + jDisableBatteryNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "disableBatteryNotifications", "()V"); + jDisableNetworkNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "disableNetworkNotifications", "()V"); + jDisableScreenOrientationNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "disableScreenOrientationNotifications", "()V"); + jDisableSensor = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "disableSensor", "(I)V"); + jEnableBatteryNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableBatteryNotifications", "()V"); + jEnableLocation = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableLocation", "(Z)V"); + jEnableLocationHighAccuracy = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableLocationHighAccuracy", "(Z)V"); + jEnableNetworkNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableNetworkNotifications", "()V"); + jEnableScreenOrientationNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableScreenOrientationNotifications", "()V"); + jEnableSensor = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableSensor", "(I)V"); + jGamepadAdded = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "gamepadAdded", "(II)V"); + jGetConnection = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getConnection", "(Ljava/lang/String;)Ljava/net/URLConnection;"); + jGetContext = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getContext", "()Landroid/content/Context;"); + jGetCurrentBatteryInformationWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getCurrentBatteryInformation", "()[D"); + jGetCurrentNetworkInformationWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getCurrentNetworkInformation", "()[D"); + jGetDensity = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getDensity", "()F"); + jGetDpiWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getDpi", "()I"); + jGetExtensionFromMimeTypeWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getExtensionFromMimeType", "(Ljava/lang/String;)Ljava/lang/String;"); + jGetExternalPublicDirectory = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getExternalPublicDirectory", "(Ljava/lang/String;)Ljava/lang/String;"); + jGetHandlersForMimeTypeWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getHandlersForMimeType", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"); + jGetHandlersForURLWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getHandlersForURL", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"); + jGetIconForExtensionWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getIconForExtension", "(Ljava/lang/String;I)[B"); + jGetMessageWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getMessage", "(II)V"); + jGetMimeTypeFromExtensionsWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getMimeTypeFromExtensions", "(Ljava/lang/String;)Ljava/lang/String;"); + jGetNextMessageInListWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getNextMessageInList", "(II)V"); + jGetProxyForURIWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getProxyForURI", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;"); + jGetScreenDepthWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getScreenDepth", "()I"); + jGetScreenOrientationWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getScreenOrientation", "()S"); + jGetShowPasswordSetting = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getShowPasswordSetting", "()Z"); + jGetSystemColoursWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getSystemColors", "()[I"); + jHandleGeckoMessageWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "handleGeckoMessage", "(Lorg/mozilla/gecko/util/NativeJSContainer;)V"); + jHandleUncaughtException = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "handleUncaughtException", "(Ljava/lang/Thread;Ljava/lang/Throwable;)V"); + jHideProgressDialog = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "hideProgressDialog", "()V"); + jInitCameraWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "initCamera", "(Ljava/lang/String;III)[I"); + jIsNetworkLinkKnown = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "isNetworkLinkKnown", "()Z"); + jIsNetworkLinkUp = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "isNetworkLinkUp", "()Z"); + jIsTablet = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "isTablet", "()Z"); + jKillAnyZombies = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "killAnyZombies", "()V"); + jLoadPluginClass = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "loadPluginClass", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;"); + jLockScreenOrientation = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "lockScreenOrientation", "(I)V"); + jMarkURIVisited = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "markUriVisited", "(Ljava/lang/String;)V"); + jMoveTaskToBack = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "moveTaskToBack", "()V"); + jNetworkLinkType = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "networkLinkType", "()I"); + jNotifyDefaultPrevented = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyDefaultPrevented", "(Z)V"); + jNotifyIME = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyIME", "(I)V"); + jNotifyIMEChange = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyIMEChange", "(Ljava/lang/String;III)V"); + jNotifyIMEContext = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyIMEContext", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + jNotifyWakeLockChanged = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyWakeLockChanged", "(Ljava/lang/String;Ljava/lang/String;)V"); + jNotifyXreExit = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "onXreExit", "()V"); + jOpenUriExternal = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "openUriExternal", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z"); + jPerformHapticFeedback = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "performHapticFeedback", "(Z)V"); + jPumpMessageLoop = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "pumpMessageLoop", "()Z"); + jRegisterSurfaceTextureFrameListener = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "registerSurfaceTextureFrameListener", "(Ljava/lang/Object;I)V"); + jRemovePluginView = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "removePluginView", "(Landroid/view/View;Z)V"); + jRequestUiThreadCallback = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "requestUiThreadCallback", "(J)V"); + jScheduleRestart = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "scheduleRestart", "()V"); + jSendMessageWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "sendMessage", "(Ljava/lang/String;Ljava/lang/String;I)V"); + jSetFullScreen = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "setFullScreen", "(Z)V"); + jSetKeepScreenOn = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "setKeepScreenOn", "(Z)V"); + jSetURITitle = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "setUriTitle", "(Ljava/lang/String;Ljava/lang/String;)V"); + jShowAlertNotificationWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "showAlertNotification", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + jShowInputMethodPicker = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "showInputMethodPicker", "()V"); + jStartMonitoringGamepad = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "startMonitoringGamepad", "()V"); + jStopMonitoringGamepad = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "stopMonitoringGamepad", "()V"); + jUnlockProfile = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "unlockProfile", "()Z"); + jUnlockScreenOrientation = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "unlockScreenOrientation", "()V"); + jUnregisterSurfaceTextureFrameListener = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "unregisterSurfaceTextureFrameListener", "(Ljava/lang/Object;)V"); + jVibrate1 = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "vibrate", "(J)V"); + jVibrateA = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "vibrate", "([JI)V"); } GeckoAppShell* GeckoAppShell::Wrap(jobject obj) { @@ -1342,17 +1338,15 @@ jmethodID GeckoJavaSampler::jPauseJavaProfiling = 0; jmethodID GeckoJavaSampler::jStartJavaProfiling = 0; jmethodID GeckoJavaSampler::jStopJavaProfiling = 0; jmethodID GeckoJavaSampler::jUnpauseJavaProfiling = 0; -void GeckoJavaSampler::InitStubs(JNIEnv *jEnv) { - initInit(); - - mGeckoJavaSamplerClass = getClassGlobalRef("org/mozilla/gecko/GeckoJavaSampler"); - jGetFrameNameJavaProfilingWrapper = getStaticMethod("getFrameName", "(III)Ljava/lang/String;"); - jGetSampleTimeJavaProfiling = getStaticMethod("getSampleTime", "(II)D"); - jGetThreadNameJavaProfilingWrapper = getStaticMethod("getThreadName", "(I)Ljava/lang/String;"); - jPauseJavaProfiling = getStaticMethod("pause", "()V"); - jStartJavaProfiling = getStaticMethod("start", "(II)V"); - jStopJavaProfiling = getStaticMethod("stop", "()V"); - jUnpauseJavaProfiling = getStaticMethod("unpause", "()V"); +void GeckoJavaSampler::InitStubs(JNIEnv *env) { + mGeckoJavaSamplerClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/GeckoJavaSampler"); + jGetFrameNameJavaProfilingWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "getFrameName", "(III)Ljava/lang/String;"); + jGetSampleTimeJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "getSampleTime", "(II)D"); + jGetThreadNameJavaProfilingWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "getThreadName", "(I)Ljava/lang/String;"); + jPauseJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "pause", "()V"); + jStartJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "start", "(II)V"); + jStopJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "stop", "()V"); + jUnpauseJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "unpause", "()V"); } GeckoJavaSampler* GeckoJavaSampler::Wrap(jobject obj) { @@ -1457,13 +1451,11 @@ jclass RestrictedProfiles::mRestrictedProfilesClass = 0; jmethodID RestrictedProfiles::jGetUserRestrictions = 0; jmethodID RestrictedProfiles::jIsAllowed = 0; jmethodID RestrictedProfiles::jIsUserRestricted = 0; -void RestrictedProfiles::InitStubs(JNIEnv *jEnv) { - initInit(); - - mRestrictedProfilesClass = getClassGlobalRef("org/mozilla/gecko/RestrictedProfiles"); - jGetUserRestrictions = getStaticMethod("getUserRestrictions", "()Ljava/lang/String;"); - jIsAllowed = getStaticMethod("isAllowed", "(ILjava/lang/String;)Z"); - jIsUserRestricted = getStaticMethod("isUserRestricted", "()Z"); +void RestrictedProfiles::InitStubs(JNIEnv *env) { + mRestrictedProfilesClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/RestrictedProfiles"); + jGetUserRestrictions = AndroidBridge::GetStaticMethodID(env, mRestrictedProfilesClass, "getUserRestrictions", "()Ljava/lang/String;"); + jIsAllowed = AndroidBridge::GetStaticMethodID(env, mRestrictedProfilesClass, "isAllowed", "(ILjava/lang/String;)Z"); + jIsUserRestricted = AndroidBridge::GetStaticMethodID(env, mRestrictedProfilesClass, "isUserRestricted", "()Z"); } RestrictedProfiles* RestrictedProfiles::Wrap(jobject obj) { @@ -1519,15 +1511,13 @@ jfieldID SurfaceBits::jbuffer = 0; jfieldID SurfaceBits::jformat = 0; jfieldID SurfaceBits::jheight = 0; jfieldID SurfaceBits::jwidth = 0; -void SurfaceBits::InitStubs(JNIEnv *jEnv) { - initInit(); - - mSurfaceBitsClass = getClassGlobalRef("org/mozilla/gecko/SurfaceBits"); - jSurfaceBits = getMethod("", "()V"); - jbuffer = getField("buffer", "Ljava/nio/ByteBuffer;"); - jformat = getField("format", "I"); - jheight = getField("height", "I"); - jwidth = getField("width", "I"); +void SurfaceBits::InitStubs(JNIEnv *env) { + mSurfaceBitsClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/SurfaceBits"); + jSurfaceBits = AndroidBridge::GetMethodID(env, mSurfaceBitsClass, "", "()V"); + jbuffer = AndroidBridge::GetFieldID(env, mSurfaceBitsClass, "buffer", "Ljava/nio/ByteBuffer;"); + jformat = AndroidBridge::GetFieldID(env, mSurfaceBitsClass, "format", "I"); + jheight = AndroidBridge::GetFieldID(env, mSurfaceBitsClass, "height", "I"); + jwidth = AndroidBridge::GetFieldID(env, mSurfaceBitsClass, "width", "I"); } SurfaceBits* SurfaceBits::Wrap(jobject obj) { @@ -1589,11 +1579,9 @@ void SurfaceBits::setwidth(int32_t a0) { } jclass ThumbnailHelper::mThumbnailHelperClass = 0; jmethodID ThumbnailHelper::jSendThumbnail = 0; -void ThumbnailHelper::InitStubs(JNIEnv *jEnv) { - initInit(); - - mThumbnailHelperClass = getClassGlobalRef("org/mozilla/gecko/ThumbnailHelper"); - jSendThumbnail = getStaticMethod("notifyThumbnail", "(Ljava/nio/ByteBuffer;IZZ)V"); +void ThumbnailHelper::InitStubs(JNIEnv *env) { + mThumbnailHelperClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/ThumbnailHelper"); + jSendThumbnail = AndroidBridge::GetStaticMethodID(env, mThumbnailHelperClass, "notifyThumbnail", "(Ljava/nio/ByteBuffer;IZZ)V"); } ThumbnailHelper* ThumbnailHelper::Wrap(jobject obj) { @@ -1624,13 +1612,11 @@ jclass DisplayPortMetrics::mDisplayPortMetricsClass = 0; jmethodID DisplayPortMetrics::jDisplayPortMetrics = 0; jfieldID DisplayPortMetrics::jMPosition = 0; jfieldID DisplayPortMetrics::jResolution = 0; -void DisplayPortMetrics::InitStubs(JNIEnv *jEnv) { - initInit(); - - mDisplayPortMetricsClass = getClassGlobalRef("org/mozilla/gecko/gfx/DisplayPortMetrics"); - jDisplayPortMetrics = getMethod("", "(FFFFF)V"); - jMPosition = getField("mPosition", "Landroid/graphics/RectF;"); - jResolution = getField("resolution", "F"); +void DisplayPortMetrics::InitStubs(JNIEnv *env) { + mDisplayPortMetricsClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/DisplayPortMetrics"); + jDisplayPortMetrics = AndroidBridge::GetMethodID(env, mDisplayPortMetricsClass, "", "(FFFFF)V"); + jMPosition = AndroidBridge::GetFieldID(env, mDisplayPortMetricsClass, "mPosition", "Landroid/graphics/RectF;"); + jResolution = AndroidBridge::GetFieldID(env, mDisplayPortMetricsClass, "resolution", "F"); } DisplayPortMetrics* DisplayPortMetrics::Wrap(jobject obj) { @@ -1669,11 +1655,9 @@ jfloat DisplayPortMetrics::getResolution() { } jclass GLController::mGLControllerClass = 0; jmethodID GLController::jCreateEGLSurfaceForCompositorWrapper = 0; -void GLController::InitStubs(JNIEnv *jEnv) { - initInit(); - - mGLControllerClass = getClassGlobalRef("org/mozilla/gecko/gfx/GLController"); - jCreateEGLSurfaceForCompositorWrapper = getMethod("createEGLSurfaceForCompositor", "()Ljavax/microedition/khronos/egl/EGLSurface;"); +void GLController::InitStubs(JNIEnv *env) { + mGLControllerClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/GLController"); + jCreateEGLSurfaceForCompositorWrapper = AndroidBridge::GetMethodID(env, mGLControllerClass, "createEGLSurfaceForCompositor", "()Ljavax/microedition/khronos/egl/EGLSurface;"); } GLController* GLController::Wrap(jobject obj) { @@ -1707,21 +1691,19 @@ jmethodID GeckoLayerClient::jSetFirstPaintViewport = 0; jmethodID GeckoLayerClient::jSetPageRect = 0; jmethodID GeckoLayerClient::jSyncFrameMetrics = 0; jmethodID GeckoLayerClient::jSyncViewportInfo = 0; -void GeckoLayerClient::InitStubs(JNIEnv *jEnv) { - initInit(); - - mGeckoLayerClientClass = getClassGlobalRef("org/mozilla/gecko/gfx/GeckoLayerClient"); - jActivateProgram = getMethod("activateProgram", "()V"); - jContentDocumentChanged = getMethod("contentDocumentChanged", "()V"); - jCreateFrame = getMethod("createFrame", "()Lorg/mozilla/gecko/gfx/LayerRenderer$Frame;"); - jDeactivateProgramAndRestoreState = getMethod("deactivateProgramAndRestoreState", "(ZIIII)V"); - jGetDisplayPort = getMethod("getDisplayPort", "(ZZILorg/mozilla/gecko/gfx/ImmutableViewportMetrics;)Lorg/mozilla/gecko/gfx/DisplayPortMetrics;"); - jIsContentDocumentDisplayed = getMethod("isContentDocumentDisplayed", "()Z"); - jProgressiveUpdateCallback = getMethod("progressiveUpdateCallback", "(ZFFFFFZ)Lorg/mozilla/gecko/gfx/ProgressiveUpdateData;"); - jSetFirstPaintViewport = getMethod("setFirstPaintViewport", "(FFFFFFF)V"); - jSetPageRect = getMethod("setPageRect", "(FFFF)V"); - jSyncFrameMetrics = getMethod("syncFrameMetrics", "(FFFFFFFZIIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;"); - jSyncViewportInfo = getMethod("syncViewportInfo", "(IIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;"); +void GeckoLayerClient::InitStubs(JNIEnv *env) { + mGeckoLayerClientClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/GeckoLayerClient"); + jActivateProgram = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "activateProgram", "()V"); + jContentDocumentChanged = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "contentDocumentChanged", "()V"); + jCreateFrame = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "createFrame", "()Lorg/mozilla/gecko/gfx/LayerRenderer$Frame;"); + jDeactivateProgramAndRestoreState = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "deactivateProgramAndRestoreState", "(ZIIII)V"); + jGetDisplayPort = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "getDisplayPort", "(ZZILorg/mozilla/gecko/gfx/ImmutableViewportMetrics;)Lorg/mozilla/gecko/gfx/DisplayPortMetrics;"); + jIsContentDocumentDisplayed = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "isContentDocumentDisplayed", "()Z"); + jProgressiveUpdateCallback = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "progressiveUpdateCallback", "(ZFFFFFZ)Lorg/mozilla/gecko/gfx/ProgressiveUpdateData;"); + jSetFirstPaintViewport = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "setFirstPaintViewport", "(FFFFFFF)V"); + jSetPageRect = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "setPageRect", "(FFFF)V"); + jSyncFrameMetrics = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "syncFrameMetrics", "(FFFFFFFZIIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;"); + jSyncViewportInfo = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "syncViewportInfo", "(IIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;"); } GeckoLayerClient* GeckoLayerClient::Wrap(jobject obj) { @@ -1931,11 +1913,9 @@ jobject GeckoLayerClient::SyncViewportInfo(int32_t a0, int32_t a1, int32_t a2, i } jclass ImmutableViewportMetrics::mImmutableViewportMetricsClass = 0; jmethodID ImmutableViewportMetrics::jImmutableViewportMetrics = 0; -void ImmutableViewportMetrics::InitStubs(JNIEnv *jEnv) { - initInit(); - - mImmutableViewportMetricsClass = getClassGlobalRef("org/mozilla/gecko/gfx/ImmutableViewportMetrics"); - jImmutableViewportMetrics = getMethod("", "(FFFFFFFFFFFFF)V"); +void ImmutableViewportMetrics::InitStubs(JNIEnv *env) { + mImmutableViewportMetricsClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/ImmutableViewportMetrics"); + jImmutableViewportMetrics = AndroidBridge::GetMethodID(env, mImmutableViewportMetricsClass, "", "(FFFFFFFFFFFFF)V"); } ImmutableViewportMetrics* ImmutableViewportMetrics::Wrap(jobject obj) { @@ -1972,11 +1952,9 @@ ImmutableViewportMetrics::ImmutableViewportMetrics(jfloat a0, jfloat a1, jfloat } jclass LayerView::mLayerViewClass = 0; jmethodID LayerView::jRegisterCompositorWrapper = 0; -void LayerView::InitStubs(JNIEnv *jEnv) { - initInit(); - - mLayerViewClass = getClassGlobalRef("org/mozilla/gecko/gfx/LayerView"); - jRegisterCompositorWrapper = getStaticMethod("registerCxxCompositor", "()Lorg/mozilla/gecko/gfx/GLController;"); +void LayerView::InitStubs(JNIEnv *env) { + mLayerViewClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/LayerView"); + jRegisterCompositorWrapper = AndroidBridge::GetStaticMethodID(env, mLayerViewClass, "registerCxxCompositor", "()Lorg/mozilla/gecko/gfx/GLController;"); } LayerView* LayerView::Wrap(jobject obj) { @@ -2000,11 +1978,9 @@ jobject LayerView::RegisterCompositorWrapper() { } jclass NativePanZoomController::mNativePanZoomControllerClass = 0; jmethodID NativePanZoomController::jRequestContentRepaintWrapper = 0; -void NativePanZoomController::InitStubs(JNIEnv *jEnv) { - initInit(); - - mNativePanZoomControllerClass = getClassGlobalRef("org/mozilla/gecko/gfx/NativePanZoomController"); - jRequestContentRepaintWrapper = getMethod("requestContentRepaint", "(FFFFF)V"); +void NativePanZoomController::InitStubs(JNIEnv *env) { + mNativePanZoomControllerClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/NativePanZoomController"); + jRequestContentRepaintWrapper = AndroidBridge::GetMethodID(env, mNativePanZoomControllerClass, "requestContentRepaint", "(FFFFF)V"); } NativePanZoomController* NativePanZoomController::Wrap(jobject obj) { @@ -2039,16 +2015,14 @@ jfieldID ProgressiveUpdateData::jabort = 0; jfieldID ProgressiveUpdateData::jscale = 0; jfieldID ProgressiveUpdateData::jx = 0; jfieldID ProgressiveUpdateData::jy = 0; -void ProgressiveUpdateData::InitStubs(JNIEnv *jEnv) { - initInit(); - - mProgressiveUpdateDataClass = getClassGlobalRef("org/mozilla/gecko/gfx/ProgressiveUpdateData"); - jProgressiveUpdateData = getMethod("", "()V"); - jsetViewport = getMethod("setViewport", "(Lorg/mozilla/gecko/gfx/ImmutableViewportMetrics;)V"); - jabort = getField("abort", "Z"); - jscale = getField("scale", "F"); - jx = getField("x", "F"); - jy = getField("y", "F"); +void ProgressiveUpdateData::InitStubs(JNIEnv *env) { + mProgressiveUpdateDataClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/ProgressiveUpdateData"); + jProgressiveUpdateData = AndroidBridge::GetMethodID(env, mProgressiveUpdateDataClass, "", "()V"); + jsetViewport = AndroidBridge::GetMethodID(env, mProgressiveUpdateDataClass, "setViewport", "(Lorg/mozilla/gecko/gfx/ImmutableViewportMetrics;)V"); + jabort = AndroidBridge::GetFieldID(env, mProgressiveUpdateDataClass, "abort", "Z"); + jscale = AndroidBridge::GetFieldID(env, mProgressiveUpdateDataClass, "scale", "F"); + jx = AndroidBridge::GetFieldID(env, mProgressiveUpdateDataClass, "x", "F"); + jy = AndroidBridge::GetFieldID(env, mProgressiveUpdateDataClass, "y", "F"); } ProgressiveUpdateData* ProgressiveUpdateData::Wrap(jobject obj) { @@ -2131,20 +2105,18 @@ jfieldID ViewTransform::joffsetY = 0; jfieldID ViewTransform::jscale = 0; jfieldID ViewTransform::jx = 0; jfieldID ViewTransform::jy = 0; -void ViewTransform::InitStubs(JNIEnv *jEnv) { - initInit(); - - mViewTransformClass = getClassGlobalRef("org/mozilla/gecko/gfx/ViewTransform"); - jViewTransform = getMethod("", "(FFF)V"); - jfixedLayerMarginBottom = getField("fixedLayerMarginBottom", "F"); - jfixedLayerMarginLeft = getField("fixedLayerMarginLeft", "F"); - jfixedLayerMarginRight = getField("fixedLayerMarginRight", "F"); - jfixedLayerMarginTop = getField("fixedLayerMarginTop", "F"); - joffsetX = getField("offsetX", "F"); - joffsetY = getField("offsetY", "F"); - jscale = getField("scale", "F"); - jx = getField("x", "F"); - jy = getField("y", "F"); +void ViewTransform::InitStubs(JNIEnv *env) { + mViewTransformClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/ViewTransform"); + jViewTransform = AndroidBridge::GetMethodID(env, mViewTransformClass, "", "(FFF)V"); + jfixedLayerMarginBottom = AndroidBridge::GetFieldID(env, mViewTransformClass, "fixedLayerMarginBottom", "F"); + jfixedLayerMarginLeft = AndroidBridge::GetFieldID(env, mViewTransformClass, "fixedLayerMarginLeft", "F"); + jfixedLayerMarginRight = AndroidBridge::GetFieldID(env, mViewTransformClass, "fixedLayerMarginRight", "F"); + jfixedLayerMarginTop = AndroidBridge::GetFieldID(env, mViewTransformClass, "fixedLayerMarginTop", "F"); + joffsetX = AndroidBridge::GetFieldID(env, mViewTransformClass, "offsetX", "F"); + joffsetY = AndroidBridge::GetFieldID(env, mViewTransformClass, "offsetY", "F"); + jscale = AndroidBridge::GetFieldID(env, mViewTransformClass, "scale", "F"); + jx = AndroidBridge::GetFieldID(env, mViewTransformClass, "x", "F"); + jy = AndroidBridge::GetFieldID(env, mViewTransformClass, "y", "F"); } ViewTransform* ViewTransform::Wrap(jobject obj) { @@ -2261,11 +2233,9 @@ void ViewTransform::sety(jfloat a0) { } jclass NativeZip::mNativeZipClass = 0; jmethodID NativeZip::jCreateInputStream = 0; -void NativeZip::InitStubs(JNIEnv *jEnv) { - initInit(); - - mNativeZipClass = getClassGlobalRef("org/mozilla/gecko/mozglue/NativeZip"); - jCreateInputStream = getMethod("createInputStream", "(Ljava/nio/ByteBuffer;I)Ljava/io/InputStream;"); +void NativeZip::InitStubs(JNIEnv *env) { + mNativeZipClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/mozglue/NativeZip"); + jCreateInputStream = AndroidBridge::GetMethodID(env, mNativeZipClass, "createInputStream", "(Ljava/nio/ByteBuffer;I)Ljava/io/InputStream;"); } NativeZip* NativeZip::Wrap(jobject obj) { @@ -2293,15 +2263,13 @@ jmethodID MatrixBlobCursor::jMatrixBlobCursor0 = 0; jmethodID MatrixBlobCursor::jAddRow = 0; jmethodID MatrixBlobCursor::jAddRow1 = 0; jmethodID MatrixBlobCursor::jAddRow2 = 0; -void MatrixBlobCursor::InitStubs(JNIEnv *jEnv) { - initInit(); - - mMatrixBlobCursorClass = getClassGlobalRef("org/mozilla/gecko/sqlite/MatrixBlobCursor"); - jMatrixBlobCursor = getMethod("", "([Ljava/lang/String;)V"); - jMatrixBlobCursor0 = getMethod("", "([Ljava/lang/String;I)V"); - jAddRow = getMethod("addRow", "(Ljava/lang/Iterable;)V"); - jAddRow1 = getMethod("addRow", "(Ljava/util/ArrayList;I)V"); - jAddRow2 = getMethod("addRow", "([Ljava/lang/Object;)V"); +void MatrixBlobCursor::InitStubs(JNIEnv *env) { + mMatrixBlobCursorClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/sqlite/MatrixBlobCursor"); + jMatrixBlobCursor = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "", "([Ljava/lang/String;)V"); + jMatrixBlobCursor0 = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "", "([Ljava/lang/String;I)V"); + jAddRow = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "addRow", "(Ljava/lang/Iterable;)V"); + jAddRow1 = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "addRow", "(Ljava/util/ArrayList;I)V"); + jAddRow2 = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "addRow", "([Ljava/lang/Object;)V"); } MatrixBlobCursor* MatrixBlobCursor::Wrap(jobject obj) { @@ -2372,13 +2340,11 @@ jclass SQLiteBridgeException::mSQLiteBridgeExceptionClass = 0; jmethodID SQLiteBridgeException::jSQLiteBridgeException = 0; jmethodID SQLiteBridgeException::jSQLiteBridgeException0 = 0; jfieldID SQLiteBridgeException::jserialVersionUID = 0; -void SQLiteBridgeException::InitStubs(JNIEnv *jEnv) { - initInit(); - - mSQLiteBridgeExceptionClass = getClassGlobalRef("org/mozilla/gecko/sqlite/SQLiteBridgeException"); - jSQLiteBridgeException = getMethod("", "()V"); - jSQLiteBridgeException0 = getMethod("", "(Ljava/lang/String;)V"); - jserialVersionUID = getStaticField("serialVersionUID", "J"); +void SQLiteBridgeException::InitStubs(JNIEnv *env) { + mSQLiteBridgeExceptionClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/sqlite/SQLiteBridgeException"); + jSQLiteBridgeException = AndroidBridge::GetMethodID(env, mSQLiteBridgeExceptionClass, "", "()V"); + jSQLiteBridgeException0 = AndroidBridge::GetMethodID(env, mSQLiteBridgeExceptionClass, "", "(Ljava/lang/String;)V"); + jserialVersionUID = AndroidBridge::GetStaticFieldID(env, mSQLiteBridgeExceptionClass, "serialVersionUID", "J"); } SQLiteBridgeException* SQLiteBridgeException::Wrap(jobject obj) { @@ -2421,14 +2387,12 @@ jmethodID Clipboard::jClearText = 0; jmethodID Clipboard::jGetClipboardTextWrapper = 0; jmethodID Clipboard::jHasText = 0; jmethodID Clipboard::jSetClipboardText = 0; -void Clipboard::InitStubs(JNIEnv *jEnv) { - initInit(); - - mClipboardClass = getClassGlobalRef("org/mozilla/gecko/util/Clipboard"); - jClearText = getStaticMethod("clearText", "()V"); - jGetClipboardTextWrapper = getStaticMethod("getText", "()Ljava/lang/String;"); - jHasText = getStaticMethod("hasText", "()Z"); - jSetClipboardText = getStaticMethod("setText", "(Ljava/lang/CharSequence;)V"); +void Clipboard::InitStubs(JNIEnv *env) { + mClipboardClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/util/Clipboard"); + jClearText = AndroidBridge::GetStaticMethodID(env, mClipboardClass, "clearText", "()V"); + jGetClipboardTextWrapper = AndroidBridge::GetStaticMethodID(env, mClipboardClass, "getText", "()Ljava/lang/String;"); + jHasText = AndroidBridge::GetStaticMethodID(env, mClipboardClass, "hasText", "()Z"); + jSetClipboardText = AndroidBridge::GetStaticMethodID(env, mClipboardClass, "setText", "(Ljava/lang/CharSequence;)V"); } Clipboard* Clipboard::Wrap(jobject obj) { @@ -2490,25 +2454,25 @@ void Clipboard::SetClipboardText(const nsAString& a0) { env->PopLocalFrame(nullptr); } -void InitStubs(JNIEnv *jEnv) { - DownloadsIntegration::InitStubs(jEnv); - GeckoAppShell::InitStubs(jEnv); - GeckoJavaSampler::InitStubs(jEnv); - RestrictedProfiles::InitStubs(jEnv); - SurfaceBits::InitStubs(jEnv); - ThumbnailHelper::InitStubs(jEnv); - DisplayPortMetrics::InitStubs(jEnv); - GLController::InitStubs(jEnv); - GeckoLayerClient::InitStubs(jEnv); - ImmutableViewportMetrics::InitStubs(jEnv); - LayerView::InitStubs(jEnv); - NativePanZoomController::InitStubs(jEnv); - ProgressiveUpdateData::InitStubs(jEnv); - ViewTransform::InitStubs(jEnv); - NativeZip::InitStubs(jEnv); - MatrixBlobCursor::InitStubs(jEnv); - SQLiteBridgeException::InitStubs(jEnv); - Clipboard::InitStubs(jEnv); +void InitStubs(JNIEnv *env) { + DownloadsIntegration::InitStubs(env); + GeckoAppShell::InitStubs(env); + GeckoJavaSampler::InitStubs(env); + RestrictedProfiles::InitStubs(env); + SurfaceBits::InitStubs(env); + ThumbnailHelper::InitStubs(env); + DisplayPortMetrics::InitStubs(env); + GLController::InitStubs(env); + GeckoLayerClient::InitStubs(env); + ImmutableViewportMetrics::InitStubs(env); + LayerView::InitStubs(env); + NativePanZoomController::InitStubs(env); + ProgressiveUpdateData::InitStubs(env); + ViewTransform::InitStubs(env); + NativeZip::InitStubs(env); + MatrixBlobCursor::InitStubs(env); + SQLiteBridgeException::InitStubs(env); + Clipboard::InitStubs(env); } } /* android */ } /* widget */ diff --git a/widget/android/GeneratedJNIWrappers.h b/widget/android/GeneratedJNIWrappers.h index 2a143a4e4863..7aa326e8e895 100644 --- a/widget/android/GeneratedJNIWrappers.h +++ b/widget/android/GeneratedJNIWrappers.h @@ -12,11 +12,11 @@ namespace mozilla { namespace widget { namespace android { -void InitStubs(JNIEnv *jEnv); +void InitStubs(JNIEnv *env); class DownloadsIntegration : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *jEnv); + static void InitStubs(JNIEnv *env); static DownloadsIntegration* Wrap(jobject obj); DownloadsIntegration(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; static void ScanMedia(const nsAString& a0, const nsAString& a1); @@ -28,7 +28,7 @@ protected: class GeckoAppShell : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *jEnv); + static void InitStubs(JNIEnv *env); static GeckoAppShell* Wrap(jobject obj); GeckoAppShell(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; static void AcknowledgeEvent(); @@ -202,7 +202,7 @@ protected: class GeckoJavaSampler : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *jEnv); + static void InitStubs(JNIEnv *env); static GeckoJavaSampler* Wrap(jobject obj); GeckoJavaSampler(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; static jstring GetFrameNameJavaProfilingWrapper(int32_t a0, int32_t a1, int32_t a2); @@ -226,7 +226,7 @@ protected: class RestrictedProfiles : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *jEnv); + static void InitStubs(JNIEnv *env); static RestrictedProfiles* Wrap(jobject obj); RestrictedProfiles(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; static jstring GetUserRestrictions(); @@ -242,7 +242,7 @@ protected: class SurfaceBits : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *jEnv); + static void InitStubs(JNIEnv *env); static SurfaceBits* Wrap(jobject obj); SurfaceBits(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; SurfaceBits(); @@ -265,7 +265,7 @@ protected: class ThumbnailHelper : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *jEnv); + static void InitStubs(JNIEnv *env); static ThumbnailHelper* Wrap(jobject obj); ThumbnailHelper(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; static void SendThumbnail(jobject a0, int32_t a1, bool a2, bool a3); @@ -277,7 +277,7 @@ protected: class DisplayPortMetrics : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *jEnv); + static void InitStubs(JNIEnv *env); static DisplayPortMetrics* Wrap(jobject obj); DisplayPortMetrics(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; DisplayPortMetrics(jfloat a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4); @@ -293,7 +293,7 @@ protected: class GLController : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *jEnv); + static void InitStubs(JNIEnv *env); static GLController* Wrap(jobject obj); GLController(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; jobject CreateEGLSurfaceForCompositorWrapper(); @@ -305,7 +305,7 @@ protected: class GeckoLayerClient : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *jEnv); + static void InitStubs(JNIEnv *env); static GeckoLayerClient* Wrap(jobject obj); GeckoLayerClient(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; void ActivateProgram(); @@ -337,7 +337,7 @@ protected: class ImmutableViewportMetrics : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *jEnv); + static void InitStubs(JNIEnv *env); static ImmutableViewportMetrics* Wrap(jobject obj); ImmutableViewportMetrics(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; ImmutableViewportMetrics(jfloat a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4, jfloat a5, jfloat a6, jfloat a7, jfloat a8, jfloat a9, jfloat a10, jfloat a11, jfloat a12); @@ -349,7 +349,7 @@ protected: class LayerView : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *jEnv); + static void InitStubs(JNIEnv *env); static LayerView* Wrap(jobject obj); LayerView(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; static jobject RegisterCompositorWrapper(); @@ -361,7 +361,7 @@ protected: class NativePanZoomController : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *jEnv); + static void InitStubs(JNIEnv *env); static NativePanZoomController* Wrap(jobject obj); NativePanZoomController(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; void RequestContentRepaintWrapper(jfloat a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4); @@ -373,7 +373,7 @@ protected: class ProgressiveUpdateData : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *jEnv); + static void InitStubs(JNIEnv *env); static ProgressiveUpdateData* Wrap(jobject obj); ProgressiveUpdateData(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; ProgressiveUpdateData(); @@ -398,7 +398,7 @@ protected: class ViewTransform : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *jEnv); + static void InitStubs(JNIEnv *env); static ViewTransform* Wrap(jobject obj); ViewTransform(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; ViewTransform(jfloat a0, jfloat a1, jfloat a2); @@ -437,7 +437,7 @@ protected: class NativeZip : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *jEnv); + static void InitStubs(JNIEnv *env); static NativeZip* Wrap(jobject obj); NativeZip(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; jobject CreateInputStream(jobject a0, int32_t a1); @@ -449,7 +449,7 @@ protected: class MatrixBlobCursor : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *jEnv); + static void InitStubs(JNIEnv *env); static MatrixBlobCursor* Wrap(jobject obj); MatrixBlobCursor(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; MatrixBlobCursor(jobjectArray a0); @@ -469,7 +469,7 @@ protected: class SQLiteBridgeException : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *jEnv); + static void InitStubs(JNIEnv *env); static SQLiteBridgeException* Wrap(jobject obj); SQLiteBridgeException(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; SQLiteBridgeException(); @@ -484,7 +484,7 @@ protected: class Clipboard : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *jEnv); + static void InitStubs(JNIEnv *env); static Clipboard* Wrap(jobject obj); Clipboard(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; static void ClearText(); From a232b16042680dfaca482110c7a7e0ef67981508 Mon Sep 17 00:00:00 2001 From: James Willcox Date: Tue, 11 Nov 2014 14:46:08 -0600 Subject: [PATCH 44/47] Bug 1086693 - Part 5: Add a 'catchException' mode to JNI generator r=ckitching --- .../annotationProcessors/AnnotationInfo.java | 9 ++- build/annotationProcessors/CodeGenerator.java | 61 ++++++++++++++----- .../utils/GeneratableElementIterator.java | 10 ++- build/annotationProcessors/utils/Utils.java | 22 ++++++- .../WrapElementForJNI.java | 9 +++ 5 files changed, 90 insertions(+), 21 deletions(-) diff --git a/build/annotationProcessors/AnnotationInfo.java b/build/annotationProcessors/AnnotationInfo.java index 98fdb17d96fb..0f2da147d6a7 100644 --- a/build/annotationProcessors/AnnotationInfo.java +++ b/build/annotationProcessors/AnnotationInfo.java @@ -12,12 +12,19 @@ public class AnnotationInfo { public final boolean isMultithreaded; public final boolean noThrow; public final boolean narrowChars; + public final boolean catchException; public AnnotationInfo(String aWrapperName, boolean aIsMultithreaded, - boolean aNoThrow, boolean aNarrowChars) { + boolean aNoThrow, boolean aNarrowChars, boolean aCatchException) { wrapperName = aWrapperName; isMultithreaded = aIsMultithreaded; noThrow = aNoThrow; narrowChars = aNarrowChars; + catchException = aCatchException; + + if (!noThrow && catchException) { + // It doesn't make sense to have these together + throw new IllegalArgumentException("noThrow and catchException are not allowed together"); + } } } diff --git a/build/annotationProcessors/CodeGenerator.java b/build/annotationProcessors/CodeGenerator.java index b172f33e8f30..215b0009e8dc 100644 --- a/build/annotationProcessors/CodeGenerator.java +++ b/build/annotationProcessors/CodeGenerator.java @@ -111,8 +111,10 @@ public class CodeGenerator { Class returnType = theMethod.getReturnType(); // Get the C++ method signature for this method. - String implementationSignature = Utils.getCImplementationMethodSignature(parameterTypes, returnType, CMethodName, mCClassName, aMethodTuple.mAnnotationInfo.narrowChars); - String headerSignature = Utils.getCHeaderMethodSignature(parameterTypes, theMethod.getParameterAnnotations(), returnType, CMethodName, mCClassName, isFieldStatic, aMethodTuple.mAnnotationInfo.narrowChars); + String implementationSignature = Utils.getCImplementationMethodSignature(parameterTypes, returnType, CMethodName, + mCClassName, aMethodTuple.mAnnotationInfo.narrowChars, aMethodTuple.mAnnotationInfo.catchException); + String headerSignature = Utils.getCHeaderMethodSignature(parameterTypes, theMethod.getParameterAnnotations(), returnType, + CMethodName, mCClassName, isFieldStatic, aMethodTuple.mAnnotationInfo.narrowChars, aMethodTuple.mAnnotationInfo.catchException); // Add the header signature to the header file. writeSignatureToHeader(headerSignature); @@ -121,7 +123,8 @@ public class CodeGenerator { writeMethodBody(implementationSignature, theMethod, mClassToWrap, aMethodTuple.mAnnotationInfo.isMultithreaded, aMethodTuple.mAnnotationInfo.noThrow, - aMethodTuple.mAnnotationInfo.narrowChars); + aMethodTuple.mAnnotationInfo.narrowChars, + aMethodTuple.mAnnotationInfo.catchException); } private void generateGetterOrSetterBody(Field aField, String aFieldName, boolean aIsFieldStatic, boolean isSetter, boolean aNarrowChars) { @@ -196,8 +199,8 @@ public class CodeGenerator { boolean isFieldFinal = Utils.isMemberFinal(theField); String getterName = "get" + CFieldName; - String getterSignature = Utils.getCImplementationMethodSignature(EMPTY_CLASS_ARRAY, fieldType, getterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars); - String getterHeaderSignature = Utils.getCHeaderMethodSignature(EMPTY_CLASS_ARRAY, GETTER_ARGUMENT_ANNOTATIONS, fieldType, getterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars); + String getterSignature = Utils.getCImplementationMethodSignature(EMPTY_CLASS_ARRAY, fieldType, getterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars, false); + String getterHeaderSignature = Utils.getCHeaderMethodSignature(EMPTY_CLASS_ARRAY, GETTER_ARGUMENT_ANNOTATIONS, fieldType, getterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars, false); writeSignatureToHeader(getterHeaderSignature); @@ -211,8 +214,8 @@ public class CodeGenerator { Class[] setterArguments = new Class[]{fieldType}; - String setterSignature = Utils.getCImplementationMethodSignature(setterArguments, Void.class, setterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars); - String setterHeaderSignature = Utils.getCHeaderMethodSignature(setterArguments, SETTER_ARGUMENT_ANNOTATIONS, Void.class, setterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars); + String setterSignature = Utils.getCImplementationMethodSignature(setterArguments, Void.class, setterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars, false); + String setterHeaderSignature = Utils.getCHeaderMethodSignature(setterArguments, SETTER_ARGUMENT_ANNOTATIONS, Void.class, setterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars, false); writeSignatureToHeader(setterHeaderSignature); @@ -229,8 +232,10 @@ public class CodeGenerator { generateMemberCommon(theCtor, mCClassName, mClassToWrap); - String implementationSignature = Utils.getCImplementationMethodSignature(theCtor.getParameterTypes(), Void.class, CMethodName, mCClassName, aCtorTuple.mAnnotationInfo.narrowChars); - String headerSignature = Utils.getCHeaderMethodSignature(theCtor.getParameterTypes(), theCtor.getParameterAnnotations(), Void.class, CMethodName, mCClassName, false, aCtorTuple.mAnnotationInfo.narrowChars); + String implementationSignature = Utils.getCImplementationMethodSignature(theCtor.getParameterTypes(), Void.class, CMethodName, + mCClassName, aCtorTuple.mAnnotationInfo.narrowChars, aCtorTuple.mAnnotationInfo.catchException); + String headerSignature = Utils.getCHeaderMethodSignature(theCtor.getParameterTypes(), theCtor.getParameterAnnotations(), Void.class, CMethodName, + mCClassName, false, aCtorTuple.mAnnotationInfo.narrowChars, aCtorTuple.mAnnotationInfo.catchException); // Slice off the "void " from the start of the constructor declaration. headerSignature = headerSignature.substring(5); @@ -242,7 +247,8 @@ public class CodeGenerator { // Use the implementation signature to generate the method body... writeCtorBody(implementationSignature, theCtor, aCtorTuple.mAnnotationInfo.isMultithreaded, - aCtorTuple.mAnnotationInfo.noThrow); + aCtorTuple.mAnnotationInfo.noThrow, + aCtorTuple.mAnnotationInfo.catchException); if (theCtor.getParameterTypes().length == 0) { mHasEncounteredDefaultConstructor = true; @@ -258,7 +264,7 @@ public class CodeGenerator { String name = m.getName(); name = name.substring(0, 1).toUpperCase() + name.substring(1); - AnnotationInfo info = new AnnotationInfo(name, true, true, true); + AnnotationInfo info = new AnnotationInfo(name, true, true, true, true); AnnotatableEntity entity = new AnnotatableEntity(m, info); if (m instanceof Constructor) { generateConstructor(entity); @@ -408,8 +414,20 @@ public class CodeGenerator { return argumentContent; } + private void writeCatchException() { + wrapperMethodBodies.append( + " if (env->ExceptionCheck()) {\n" + + " env->ExceptionClear();\n" + + " if (aResult) {\n" + + " *aResult = NS_ERROR_FAILURE;\n" + + " }\n" + + " } else if (aResult) {\n" + + " *aResult = NS_OK;\n" + + " }\n\n"); + } + private void writeCtorBody(String implementationSignature, Constructor theCtor, - boolean aIsThreaded, boolean aNoThrow) { + boolean aIsThreaded, boolean aNoThrow, boolean aCatchException) { Class[] argumentTypes = theCtor.getParameterTypes(); writeFunctionStartupBoilerPlate(implementationSignature, aIsThreaded); @@ -443,9 +461,14 @@ public class CodeGenerator { wrapperMethodBodies.append(mMembersToIds.get(theCtor)) // Tack on the arguments, if any.. .append(argumentContent) - .append("), env);\n" + - " env->PopLocalFrame(nullptr);\n" + - "}\n"); + .append("), env);\n"); + + // Check for exception and set aResult + if (aCatchException) { + writeCatchException(); + } + + wrapperMethodBodies.append(" env->PopLocalFrame(nullptr);\n}\n"); } /** @@ -458,7 +481,8 @@ public class CodeGenerator { */ private void writeMethodBody(String methodSignature, Method aMethod, Class aClass, boolean aIsMultithreaded, - boolean aNoThrow, boolean aNarrowChars) { + boolean aNoThrow, boolean aNarrowChars, + boolean aCatchException) { Class[] argumentTypes = aMethod.getParameterTypes(); Class returnType = aMethod.getReturnType(); @@ -526,6 +550,11 @@ public class CodeGenerator { wrapperMethodBodies.append(" AndroidBridge::HandleUncaughtException(env);\n"); } + // Check for exception and set aResult + if (aCatchException) { + writeCatchException(); + } + // If we're returning an object, pop the callee's stack frame extracting our ref as the return // value. if (isObjectReturningMethod) { diff --git a/build/annotationProcessors/utils/GeneratableElementIterator.java b/build/annotationProcessors/utils/GeneratableElementIterator.java index 6e7b1349fbb1..32dd2b963e05 100644 --- a/build/annotationProcessors/utils/GeneratableElementIterator.java +++ b/build/annotationProcessors/utils/GeneratableElementIterator.java @@ -76,6 +76,7 @@ public class GeneratableElementIterator implements Iterator { boolean isMultithreadedStub = false; boolean noThrow = false; boolean narrowChars = false; + boolean catchException = false; try { // Determine the explicitly-given name of the stub to generate, if any. final Method stubNameMethod = annotationType.getDeclaredMethod("stubName"); @@ -97,6 +98,11 @@ public class GeneratableElementIterator implements Iterator { narrowCharsMethod.setAccessible(true); narrowChars = (Boolean) narrowCharsMethod.invoke(annotation); + // Determine if we should catch exceptions + final Method catchExceptionMethod = annotationType.getDeclaredMethod("catchException"); + catchExceptionMethod.setAccessible(true); + catchException = (Boolean) catchExceptionMethod.invoke(annotation); + } catch (NoSuchMethodException e) { System.err.println("Unable to find expected field on WrapElementForJNI annotation. Did the signature change?"); e.printStackTrace(System.err); @@ -118,7 +124,7 @@ public class GeneratableElementIterator implements Iterator { } AnnotationInfo annotationInfo = new AnnotationInfo( - stubName, isMultithreadedStub, noThrow, narrowChars); + stubName, isMultithreadedStub, noThrow, narrowChars, catchException); mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo); return; } @@ -128,7 +134,7 @@ public class GeneratableElementIterator implements Iterator { // thanks to the "Generate everything" annotation. if (mIterateEveryEntry) { AnnotationInfo annotationInfo = new AnnotationInfo( - candidateElement.getName(), false, false, false); + candidateElement.getName(), false, false, false, false); mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo); return; } diff --git a/build/annotationProcessors/utils/Utils.java b/build/annotationProcessors/utils/Utils.java index 89f70dc8b5fb..44876ebb4b99 100644 --- a/build/annotationProcessors/utils/Utils.java +++ b/build/annotationProcessors/utils/Utils.java @@ -388,7 +388,8 @@ public class Utils { * @param aCClassName Name of the C++ class into which the method is declared. * @return The C++ method implementation signature for the method described. */ - public static String getCImplementationMethodSignature(Class[] aArgumentTypes, Class aReturnType, String aCMethodName, String aCClassName, boolean aNarrowChars) { + public static String getCImplementationMethodSignature(Class[] aArgumentTypes, Class aReturnType, + String aCMethodName, String aCClassName, boolean aNarrowChars, boolean aCatchException) { StringBuilder retBuffer = new StringBuilder(); retBuffer.append(getCReturnType(aReturnType, aNarrowChars)); @@ -410,6 +411,14 @@ public class Utils { retBuffer.append(", "); } } + + if (aCatchException) { + if (aArgumentTypes.length > 0) { + retBuffer.append(", "); + } + retBuffer.append("nsresult* aResult"); + } + retBuffer.append(')'); return retBuffer.toString(); } @@ -427,7 +436,8 @@ public class Utils { * @param aIsStaticStub true if the generated C++ method should be static, false otherwise. * @return The generated C++ header method signature for the method described. */ - public static String getCHeaderMethodSignature(Class[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class aReturnType, String aCMethodName, String aCClassName, boolean aIsStaticStub, boolean aNarrowChars) { + public static String getCHeaderMethodSignature(Class[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class aReturnType, + String aCMethodName, String aCClassName, boolean aIsStaticStub, boolean aNarrowChars, boolean aCatchException) { StringBuilder retBuffer = new StringBuilder(); // Add the static keyword, if applicable. @@ -457,6 +467,14 @@ public class Utils { retBuffer.append(", "); } } + + if (aCatchException) { + if (aArgumentTypes.length > 0) { + retBuffer.append(", "); + } + retBuffer.append("nsresult* aResult = nullptr"); + } + retBuffer.append(')'); return retBuffer.toString(); } diff --git a/mobile/android/base/mozglue/generatorannotations/WrapElementForJNI.java b/mobile/android/base/mozglue/generatorannotations/WrapElementForJNI.java index 3036ecbf4954..a73d2d91b35f 100644 --- a/mobile/android/base/mozglue/generatorannotations/WrapElementForJNI.java +++ b/mobile/android/base/mozglue/generatorannotations/WrapElementForJNI.java @@ -44,5 +44,14 @@ public @interface WrapElementForJNI { */ boolean noThrow() default false; + /** + * If set, uses UTF-8 strings + */ boolean narrowChars() default false; + + /** + * If set, the generated stub will catch any exception thrown and + * set a passed-in nsresult to NS_ERROR_FAILURE + */ + boolean catchException() default false; } From 92de0e9c7ae185534c05054dbdc8a36f792d99db Mon Sep 17 00:00:00 2001 From: James Willcox Date: Tue, 11 Nov 2014 14:46:09 -0600 Subject: [PATCH 45/47] Bug 1086693 - Part 6: Use generated bindings for AndroidMediaCodec and AndroidSurfaceTexture r=blassey,gcp --- .../fmp4/android/AndroidDecoderModule.cpp | 121 +- dom/media/fmp4/android/AndroidDecoderModule.h | 19 +- dom/plugins/base/nsNPAPIPluginInstance.cpp | 16 +- dom/plugins/base/nsNPAPIPluginInstance.h | 8 +- gfx/gl/AndroidSurfaceTexture.cpp | 275 +-- gfx/gl/AndroidSurfaceTexture.h | 21 +- gfx/gl/GLBlitHelper.cpp | 2 +- gfx/layers/opengl/TextureHostOGL.cpp | 4 +- widget/android/AndroidBridge.cpp | 11 +- widget/android/AndroidJavaWrappers.cpp | 1 - widget/android/GeneratedSDKWrappers.cpp | 1877 ----------------- widget/android/GeneratedSDKWrappers.h | 335 --- widget/android/moz.build | 2 - 13 files changed, 181 insertions(+), 2511 deletions(-) delete mode 100644 widget/android/GeneratedSDKWrappers.cpp delete mode 100644 widget/android/GeneratedSDKWrappers.h diff --git a/dom/media/fmp4/android/AndroidDecoderModule.cpp b/dom/media/fmp4/android/AndroidDecoderModule.cpp index 6067f5fd5922..9f16fb20fb25 100644 --- a/dom/media/fmp4/android/AndroidDecoderModule.cpp +++ b/dom/media/fmp4/android/AndroidDecoderModule.cpp @@ -3,13 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "AndroidDecoderModule.h" -#include "PlatformDecoderModule.h" -#include "GeneratedJNIWrappers.h" -#include "GeneratedSDKWrappers.h" #include "AndroidBridge.h" -#include "MediaTaskQueue.h" -#include "SharedThreadPool.h" -#include "TexturePoolOGL.h" #include "GLImages.h" #include "MediaData.h" @@ -26,7 +20,7 @@ using namespace mozilla; using namespace mozilla::gl; -using namespace mozilla::widget::android; +using namespace mozilla::widget::android::sdk; namespace mozilla { @@ -36,10 +30,7 @@ static MediaCodec* CreateDecoder(JNIEnv* aEnv, const char* aMimeType) return nullptr; } - nsAutoString mimeType; - mimeType.AssignASCII(aMimeType); - - jobject decoder = MediaCodec::CreateDecoderByType(mimeType); + jobject decoder = MediaCodec::CreateDecoderByType(nsCString(aMimeType)); return new MediaCodec(decoder, aEnv); } @@ -103,7 +94,7 @@ public: protected: layers::ImageContainer* mImageContainer; const mp4_demuxer::VideoDecoderConfig& mConfig; - nsRefPtr mSurfaceTexture; + RefPtr mSurfaceTexture; }; class AudioDataDecoder : public MediaCodecDataDecoder { @@ -115,11 +106,11 @@ public: virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE { if (!strcmp(mMimeType, "audio/mp4a-latm")) { - uint32_t numChannels = mFormat->GetInteger(NS_LITERAL_STRING("channel-count")); - uint32_t sampleRate = mFormat->GetInteger(NS_LITERAL_STRING("sample-rate")); + uint32_t numChannels = mFormat->GetInteger(NS_LITERAL_CSTRING("channel-count")); + uint32_t sampleRate = mFormat->GetInteger(NS_LITERAL_CSTRING("sample-rate")); uint8_t frequencyIndex = mp4_demuxer::Adts::GetFrequencyIndex(sampleRate); - uint32_t aacProfile = mFormat->GetInteger(NS_LITERAL_STRING("aac-profile")); + uint32_t aacProfile = mFormat->GetInteger(NS_LITERAL_CSTRING("aac-profile")); bool rv = mp4_demuxer::Adts::ConvertSample(numChannels, frequencyIndex, aacProfile, @@ -135,8 +126,8 @@ public: nsresult Output(BufferInfo* aInfo, void* aBuffer, MediaFormat* aFormat, Microseconds aDuration) { // The output on Android is always 16-bit signed - uint32_t numChannels = aFormat->GetInteger(NS_LITERAL_STRING("channel-count")); - uint32_t sampleRate = aFormat->GetInteger(NS_LITERAL_STRING("sample-rate")); + uint32_t numChannels = aFormat->GetInteger(NS_LITERAL_CSTRING("channel-count")); + uint32_t sampleRate = aFormat->GetInteger(NS_LITERAL_CSTRING("sample-rate")); uint32_t numFrames = (aInfo->getSize() / numChannels) / 2; AudioDataValue* audio = new AudioDataValue[aInfo->getSize()]; @@ -169,10 +160,7 @@ AndroidDecoderModule::CreateH264Decoder( MediaTaskQueue* aVideoTaskQueue, MediaDataDecoderCallback* aCallback) { - nsAutoString mimeType; - mimeType.AssignASCII(aConfig.mime_type); - - jobject jFormat = MediaFormat::CreateVideoFormat(mimeType, + jobject jFormat = MediaFormat::CreateVideoFormat(nsCString(aConfig.mime_type), aConfig.display_width, aConfig.display_height); @@ -199,10 +187,7 @@ AndroidDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& { MOZ_ASSERT(aConfig.bits_per_sample == 16, "We only handle 16-bit audio!"); - nsAutoString mimeType; - mimeType.AssignASCII(aConfig.mime_type); - - jobject jFormat = MediaFormat::CreateAudioFormat(mimeType, + jobject jFormat = MediaFormat::CreateAudioFormat(nsCString(aConfig.mime_type), aConfig.samples_per_second, aConfig.channel_count); @@ -216,21 +201,21 @@ AndroidDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& JNIEnv* env = GetJNIForThread(); - if (!format->GetByteBuffer(NS_LITERAL_STRING("csd-0"))) { + if (!format->GetByteBuffer(NS_LITERAL_CSTRING("csd-0"))) { uint8_t* csd0 = new uint8_t[2]; csd0[0] = aConfig.audio_specific_config[0]; csd0[1] = aConfig.audio_specific_config[1]; jobject buffer = env->NewDirectByteBuffer(csd0, 2); - format->SetByteBuffer(NS_LITERAL_STRING("csd-0"), buffer); + format->SetByteBuffer(NS_LITERAL_CSTRING("csd-0"), buffer); env->DeleteLocalRef(buffer); } - if (mimeType.EqualsLiteral("audio/mp4a-latm")) { - format->SetInteger(NS_LITERAL_STRING("is-adts"), 1); - format->SetInteger(NS_LITERAL_STRING("aac-profile"), aConfig.aac_profile); + if (strcmp(aConfig.mime_type, "audio/mp4a-latm") == 0) { + format->SetInteger(NS_LITERAL_CSTRING("is-adts"), 1); + format->SetInteger(NS_LITERAL_CSTRING("aac-profile"), aConfig.aac_profile); } nsRefPtr decoder = @@ -294,15 +279,26 @@ nsresult MediaCodecDataDecoder::InitDecoder(jobject aSurface) return NS_ERROR_FAILURE; } - if (!mDecoder->Configure(mFormat->wrappedObject(), aSurface, nullptr, 0)) { - mCallback->Error(); - return NS_ERROR_FAILURE; + nsresult res; + mDecoder->Configure(mFormat->wrappedObject(), aSurface, nullptr, 0, &res); + if (NS_FAILED(res)) { + return res; } - mDecoder->Start(); + mDecoder->Start(&res); + if (NS_FAILED(res)) { + return res; + } - ResetInputBuffers(); - ResetOutputBuffers(); + res = ResetInputBuffers(); + if (NS_FAILED(res)) { + return res; + } + + res = ResetOutputBuffers(); + if (NS_FAILED(res)) { + return res; + } NS_NewNamedThread("MC Decoder", getter_AddRefs(mThread), NS_NewRunnableMethod(this, &MediaCodecDataDecoder::DecoderLoop)); @@ -321,6 +317,7 @@ void MediaCodecDataDecoder::DecoderLoop() mp4_demuxer::MP4Sample* sample = nullptr; nsAutoPtr outputFormat; + nsresult res; for (;;) { { @@ -354,7 +351,13 @@ void MediaCodecDataDecoder::DecoderLoop() if (sample) { // We have a sample, try to feed it to the decoder - int inputIndex = mDecoder->DequeueInputBuffer(DECODER_TIMEOUT); + int inputIndex = mDecoder->DequeueInputBuffer(DECODER_TIMEOUT, &res); + if (NS_FAILED(res)) { + printf_stderr("exiting decoder loop due to exception while dequeuing input\n"); + mCallback->Error(); + break; + } + if (inputIndex >= 0) { jobject buffer = env->GetObjectArrayElement(mInputBuffers, inputIndex); void* directBuffer = env->GetDirectBufferAddress(buffer); @@ -369,7 +372,13 @@ void MediaCodecDataDecoder::DecoderLoop() PodCopy((uint8_t*)directBuffer, sample->data, sample->size); - mDecoder->QueueInputBuffer(inputIndex, 0, sample->size, sample->composition_timestamp, 0); + mDecoder->QueueInputBuffer(inputIndex, 0, sample->size, sample->composition_timestamp, 0, &res); + if (NS_FAILED(res)) { + printf_stderr("exiting decoder loop due to exception while queuing input\n"); + mCallback->Error(); + break; + } + mDurations.push(sample->duration); delete sample; @@ -383,12 +392,23 @@ void MediaCodecDataDecoder::DecoderLoop() if (!outputDone) { BufferInfo bufferInfo; - int outputStatus = mDecoder->DequeueOutputBuffer(bufferInfo.wrappedObject(), DECODER_TIMEOUT); + int outputStatus = mDecoder->DequeueOutputBuffer(bufferInfo.wrappedObject(), DECODER_TIMEOUT, &res); + if (NS_FAILED(res)) { + printf_stderr("exiting decoder loop due to exception while dequeuing output\n"); + mCallback->Error(); + break; + } + if (outputStatus == MediaCodec::getINFO_TRY_AGAIN_LATER()) { // We might want to call mCallback->InputExhausted() here, but there seems to be // some possible bad interactions here with the threading } else if (outputStatus == MediaCodec::getINFO_OUTPUT_BUFFERS_CHANGED()) { - ResetOutputBuffers(); + res = ResetOutputBuffers(); + if (NS_FAILED(res)) { + printf_stderr("exiting decoder loop due to exception while restting output buffers\n"); + mCallback->Error(); + break; + } } else if (outputStatus == MediaCodec::getINFO_OUTPUT_FORMAT_CHANGED()) { outputFormat = new MediaFormat(mDecoder->GetOutputFormat(), GetJNIForThread()); } else if (outputStatus < 0) { @@ -454,7 +474,7 @@ nsresult MediaCodecDataDecoder::Input(mp4_demuxer::MP4Sample* aSample) { return NS_OK; } -void MediaCodecDataDecoder::ResetInputBuffers() +nsresult MediaCodecDataDecoder::ResetInputBuffers() { JNIEnv* env = GetJNIForThread(); @@ -462,10 +482,16 @@ void MediaCodecDataDecoder::ResetInputBuffers() env->DeleteGlobalRef(mInputBuffers); } - mInputBuffers = (jobjectArray) env->NewGlobalRef(mDecoder->GetInputBuffers()); + nsresult res; + mInputBuffers = (jobjectArray) env->NewGlobalRef(mDecoder->GetInputBuffers(&res)); + if (NS_FAILED(res)) { + return res; + } + + return NS_OK; } -void MediaCodecDataDecoder::ResetOutputBuffers() +nsresult MediaCodecDataDecoder::ResetOutputBuffers() { JNIEnv* env = GetJNIForThread(); @@ -473,7 +499,13 @@ void MediaCodecDataDecoder::ResetOutputBuffers() env->DeleteGlobalRef(mOutputBuffers); } - mOutputBuffers = (jobjectArray) env->NewGlobalRef(mDecoder->GetOutputBuffers()); + nsresult res; + mOutputBuffers = (jobjectArray) env->NewGlobalRef(mDecoder->GetOutputBuffers(&res)); + if (NS_FAILED(res)) { + return res; + } + + return NS_OK; } nsresult MediaCodecDataDecoder::Flush() { @@ -515,6 +547,7 @@ nsresult MediaCodecDataDecoder::Shutdown() { mDecoder->Stop(); mDecoder->Release(); + return NS_OK; } diff --git a/dom/media/fmp4/android/AndroidDecoderModule.h b/dom/media/fmp4/android/AndroidDecoderModule.h index 74beab3271a1..0ae43138e684 100644 --- a/dom/media/fmp4/android/AndroidDecoderModule.h +++ b/dom/media/fmp4/android/AndroidDecoderModule.h @@ -6,10 +6,9 @@ #define AndroidDecoderModule_h_ #include "PlatformDecoderModule.h" -#include "AndroidJavaWrappers.h" #include "AndroidSurfaceTexture.h" -#include "GeneratedSDKWrappers.h" +#include "MediaCodec.h" #include "mozilla/Monitor.h" #include @@ -20,11 +19,13 @@ typedef std::queue SampleQueue; namespace widget { namespace android { +namespace sdk { class MediaCodec; class MediaFormat; class ByteBuffer; } } +} class MediaCodecDataDecoder; @@ -56,7 +57,7 @@ public: MediaCodecDataDecoder(MediaData::Type aType, const char* aMimeType, - mozilla::widget::android::MediaFormat* aFormat, + mozilla::widget::android::sdk::MediaFormat* aFormat, MediaDataDecoderCallback* aCallback); virtual ~MediaCodecDataDecoder(); @@ -73,11 +74,11 @@ protected: MediaData::Type mType; nsAutoPtr mMimeType; - nsAutoPtr mFormat; + nsAutoPtr mFormat; MediaDataDecoderCallback* mCallback; - nsAutoPtr mDecoder; + nsAutoPtr mDecoder; jobjectArray mInputBuffers; jobjectArray mOutputBuffers; @@ -94,11 +95,11 @@ protected: virtual nsresult InitDecoder(jobject aSurface = nullptr); - virtual nsresult Output(mozilla::widget::android::BufferInfo* aInfo, void* aBuffer, mozilla::widget::android::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; } - virtual nsresult PostOutput(mozilla::widget::android::BufferInfo* aInfo, mozilla::widget::android::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; } + virtual nsresult Output(mozilla::widget::android::sdk::BufferInfo* aInfo, void* aBuffer, mozilla::widget::android::sdk::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; } + virtual nsresult PostOutput(mozilla::widget::android::sdk::BufferInfo* aInfo, mozilla::widget::android::sdk::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; } - void ResetInputBuffers(); - void ResetOutputBuffers(); + nsresult ResetInputBuffers(); + nsresult ResetOutputBuffers(); void DecoderLoop(); virtual void ClearQueue(); diff --git a/dom/plugins/base/nsNPAPIPluginInstance.cpp b/dom/plugins/base/nsNPAPIPluginInstance.cpp index c2a85e8bf76e..c42f47e09b11 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.cpp +++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp @@ -952,7 +952,7 @@ void nsNPAPIPluginInstance::ReleaseContentTexture(nsNPAPIPluginInstance::Texture mContentTexture->Release(aTextureInfo); } -AndroidSurfaceTexture* nsNPAPIPluginInstance::CreateSurfaceTexture() +TemporaryRef nsNPAPIPluginInstance::CreateSurfaceTexture() { if (!EnsureGLContext()) return nullptr; @@ -961,14 +961,15 @@ AndroidSurfaceTexture* nsNPAPIPluginInstance::CreateSurfaceTexture() if (!texture) return nullptr; - AndroidSurfaceTexture* surface = AndroidSurfaceTexture::Create(TexturePoolOGL::GetGLContext(), - texture); - if (!surface) + RefPtr surface = AndroidSurfaceTexture::Create(TexturePoolOGL::GetGLContext(), + texture); + if (!surface) { return nullptr; + } nsCOMPtr frameCallback = NS_NewRunnableMethod(this, &nsNPAPIPluginInstance::OnSurfaceTextureFrameAvailable); surface->SetFrameAvailableCallback(frameCallback); - return surface; + return surface.forget(); } void nsNPAPIPluginInstance::OnSurfaceTextureFrameAvailable() @@ -1009,9 +1010,10 @@ nsNPAPIPluginInstance::AsSurfaceTexture() void* nsNPAPIPluginInstance::AcquireVideoWindow() { - AndroidSurfaceTexture* surface = CreateSurfaceTexture(); - if (!surface) + RefPtr surface = CreateSurfaceTexture(); + if (!surface) { return nullptr; + } VideoInfo* info = new VideoInfo(surface); diff --git a/dom/plugins/base/nsNPAPIPluginInstance.h b/dom/plugins/base/nsNPAPIPluginInstance.h index c3a35488bd66..6454c627c3da 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.h +++ b/dom/plugins/base/nsNPAPIPluginInstance.h @@ -207,7 +207,7 @@ public: mSurfaceTexture = nullptr; } - nsRefPtr mSurfaceTexture; + mozilla::RefPtr mSurfaceTexture; gfxRect mDimensions; }; @@ -328,8 +328,8 @@ protected: bool mFullScreen; bool mInverted; - nsRefPtr mContentTexture; - nsRefPtr mContentSurface; + mozilla::RefPtr mContentTexture; + mozilla::RefPtr mContentSurface; #endif enum { @@ -378,7 +378,7 @@ private: #ifdef MOZ_WIDGET_ANDROID void EnsureSharedTexture(); - mozilla::gl::AndroidSurfaceTexture* CreateSurfaceTexture(); + mozilla::TemporaryRef CreateSurfaceTexture(); std::map mVideos; bool mOnScreen; diff --git a/gfx/gl/AndroidSurfaceTexture.cpp b/gfx/gl/AndroidSurfaceTexture.cpp index c5740c2b3d1a..06783922fc8e 100644 --- a/gfx/gl/AndroidSurfaceTexture.cpp +++ b/gfx/gl/AndroidSurfaceTexture.cpp @@ -15,10 +15,12 @@ #include "nsThreadUtils.h" #include "mozilla/gfx/Matrix.h" #include "GeneratedJNIWrappers.h" +#include "SurfaceTexture.h" #include "GLContext.h" using namespace mozilla; using namespace mozilla::widget::android; +using namespace mozilla::widget::android::sdk; namespace mozilla { namespace gl { @@ -39,192 +41,26 @@ IsSTSupported() return AndroidBridge::Bridge()->GetAPIVersion() >= 14; /* ICS */ } -static class JNIFunctions { -public: - - JNIFunctions() : mInitialized(false) - { - } - - bool EnsureInitialized() - { - if (mInitialized) { - return true; - } - - if (!IsSTSupported()) { - return false; - } - - JNIEnv* env = GetJNIForThread(); - - AutoLocalJNIFrame jniFrame(env); - - jSurfaceTextureClass = (jclass)env->NewGlobalRef(env->FindClass("android/graphics/SurfaceTexture")); - jSurfaceTexture_Ctor = env->GetMethodID(jSurfaceTextureClass, "", "(I)V"); - jSurfaceTexture_updateTexImage = env->GetMethodID(jSurfaceTextureClass, "updateTexImage", "()V"); - jSurfaceTexture_getTransformMatrix = env->GetMethodID(jSurfaceTextureClass, "getTransformMatrix", "([F)V"); - jSurfaceTexture_setDefaultBufferSize = env->GetMethodID(jSurfaceTextureClass, "setDefaultBufferSize", "(II)V"); - - if (IsDetachSupported()) { - jSurfaceTexture_attachToGLContext = env->GetMethodID(jSurfaceTextureClass, "attachToGLContext", "(I)V"); - jSurfaceTexture_detachFromGLContext = env->GetMethodID(jSurfaceTextureClass, "detachFromGLContext", "()V"); - } else { - jSurfaceTexture_attachToGLContext = jSurfaceTexture_detachFromGLContext = 0; - } - - jSurfaceClass = (jclass)env->NewGlobalRef(env->FindClass("android/view/Surface")); - jSurface_Ctor = env->GetMethodID(jSurfaceClass, "", "(Landroid/graphics/SurfaceTexture;)V"); - - mInitialized = true; - return true; - } - - jobject CreateSurfaceTexture(GLuint aTexture) - { - if (!EnsureInitialized()) - return nullptr; - - JNIEnv* env = GetJNIForThread(); - - AutoLocalJNIFrame jniFrame(env); - - return env->NewGlobalRef(env->NewObject(jSurfaceTextureClass, jSurfaceTexture_Ctor, (int) aTexture)); - } - - jobject CreateSurface(jobject aSurfaceTexture) - { - if (!EnsureInitialized()) - return nullptr; - - JNIEnv* env = GetJNIForThread(); - AutoLocalJNIFrame jniFrame(env); - return env->NewGlobalRef(env->NewObject(jSurfaceClass, jSurface_Ctor, aSurfaceTexture)); - } - - void ReleaseSurfaceTexture(jobject aSurfaceTexture) - { - JNIEnv* env = GetJNIForThread(); - - env->DeleteGlobalRef(aSurfaceTexture); - } - - void UpdateTexImage(jobject aSurfaceTexture) - { - JNIEnv* env = GetJNIForThread(); - - AutoLocalJNIFrame jniFrame(env); - env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_updateTexImage); - } - - bool GetTransformMatrix(jobject aSurfaceTexture, gfx::Matrix4x4& aMatrix) - { - JNIEnv* env = GetJNIForThread(); - - AutoLocalJNIFrame jniFrame(env); - - jfloatArray jarray = env->NewFloatArray(16); - env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_getTransformMatrix, jarray); - - jfloat* array = env->GetFloatArrayElements(jarray, nullptr); - - aMatrix._11 = array[0]; - aMatrix._12 = array[1]; - aMatrix._13 = array[2]; - aMatrix._14 = array[3]; - - aMatrix._21 = array[4]; - aMatrix._22 = array[5]; - aMatrix._23 = array[6]; - aMatrix._24 = array[7]; - - aMatrix._31 = array[8]; - aMatrix._32 = array[9]; - aMatrix._33 = array[10]; - aMatrix._34 = array[11]; - - aMatrix._41 = array[12]; - aMatrix._42 = array[13]; - aMatrix._43 = array[14]; - aMatrix._44 = array[15]; - - env->ReleaseFloatArrayElements(jarray, array, 0); - - return false; - } - - void SetDefaultBufferSize(jobject aSurfaceTexture, int32_t width, int32_t height) - { - JNIEnv* env = GetJNIForThread(); - - AutoLocalJNIFrame jniFrame(env); - env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_setDefaultBufferSize, width, height); - } - - void AttachToGLContext(jobject aSurfaceTexture, int32_t texName) - { - MOZ_ASSERT(jSurfaceTexture_attachToGLContext); - - JNIEnv* env = GetJNIForThread(); - - env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_attachToGLContext, texName); - if (env->ExceptionCheck()) { - env->ExceptionDescribe(); - env->ExceptionClear(); - } - } - - void DetachFromGLContext(jobject aSurfaceTexture) - { - MOZ_ASSERT(jSurfaceTexture_detachFromGLContext); - - JNIEnv* env = GetJNIForThread(); - - env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_detachFromGLContext); - if (env->ExceptionCheck()) { - env->ExceptionDescribe(); - env->ExceptionClear(); - } - } - -private: - bool mInitialized; - - jclass jSurfaceTextureClass; - jmethodID jSurfaceTexture_Ctor; - jmethodID jSurfaceTexture_updateTexImage; - jmethodID jSurfaceTexture_getTransformMatrix; - jmethodID jSurfaceTexture_setDefaultBufferSize; - - jmethodID jSurfaceTexture_attachToGLContext; - jmethodID jSurfaceTexture_detachFromGLContext; - - jclass jSurfaceClass; - jmethodID jSurface_Ctor; - -} sJNIFunctions; - -AndroidSurfaceTexture* +TemporaryRef AndroidSurfaceTexture::Create() { return Create(nullptr, 0); } -AndroidSurfaceTexture* +TemporaryRef AndroidSurfaceTexture::Create(GLContext* aContext, GLuint aTexture) { if (!IsSTSupported()) { return nullptr; } - AndroidSurfaceTexture* st = new AndroidSurfaceTexture(); + RefPtr st = new AndroidSurfaceTexture(); if (!st->Init(aContext, aTexture)) { printf_stderr("Failed to initialize AndroidSurfaceTexture"); - delete st; st = nullptr; } - return st; + return st.forget(); } AndroidSurfaceTexture* @@ -239,30 +75,25 @@ AndroidSurfaceTexture::Find(int id) return it->second; } -bool -AndroidSurfaceTexture::Check() -{ - return sJNIFunctions.EnsureInitialized(); -} -bool +nsresult AndroidSurfaceTexture::Attach(GLContext* aContext, PRIntervalTime aTimeout) { MonitorAutoLock lock(mMonitor); if (mAttachedContext == aContext) { NS_WARNING("Tried to attach same GLContext to AndroidSurfaceTexture"); - return true; + return NS_OK; } if (!IsDetachSupported()) { - return false; + return NS_ERROR_NOT_AVAILABLE; } while (mAttachedContext) { // Wait until it's detached (or we time out) if (NS_FAILED(lock.Wait(aTimeout))) { - return false; + return NS_ERROR_NOT_AVAILABLE; } } @@ -272,29 +103,29 @@ AndroidSurfaceTexture::Attach(GLContext* aContext, PRIntervalTime aTimeout) mAttachedContext->MakeCurrent(); aContext->fGenTextures(1, &mTexture); - sJNIFunctions.AttachToGLContext(mSurfaceTexture, mTexture); - return true; + nsresult res; + mSurfaceTexture->AttachToGLContext(mTexture, &res); + return res; } -bool +nsresult AndroidSurfaceTexture::Detach() { MonitorAutoLock lock(mMonitor); if (!IsDetachSupported() || !mAttachedContext || !mAttachedContext->IsOwningThreadCurrent()) { - return false; + return NS_ERROR_FAILURE; } mAttachedContext->MakeCurrent(); - // This call takes care of deleting the texture - sJNIFunctions.DetachFromGLContext(mSurfaceTexture); + mSurfaceTexture->DetachFromGLContext(); mTexture = 0; mAttachedContext = nullptr; lock.NotifyAll(); - return true; + return NS_OK; } bool @@ -305,28 +136,26 @@ AndroidSurfaceTexture::Init(GLContext* aContext, GLuint aTexture) return false; } - if (!sJNIFunctions.EnsureInitialized()) - return false; - - JNIEnv* env = GetJNIForThread(); - - mSurfaceTexture = sJNIFunctions.CreateSurfaceTexture(aTexture); - if (!mSurfaceTexture) { + nsresult res; + mSurfaceTexture = new SurfaceTexture(aTexture, &res); + if (NS_FAILED(res)) { return false; } if (!aTexture) { - sJNIFunctions.DetachFromGLContext(mSurfaceTexture); + mSurfaceTexture->DetachFromGLContext(); } mAttachedContext = aContext; - mSurface = sJNIFunctions.CreateSurface(mSurfaceTexture); - if (!mSurface) { + mSurface = new Surface(mSurfaceTexture->wrappedObject(), &res); + if (NS_FAILED(res)) { return false; } - mNativeWindow = AndroidNativeWindow::CreateFromSurface(env, mSurface); + mNativeWindow = AndroidNativeWindow::CreateFromSurface(GetJNIForThread(), + mSurface->wrappedObject()); + MOZ_ASSERT(mNativeWindow, "Failed to create native window from surface"); mID = ++sNextID; sInstances.insert(std::pair(mID, this)); @@ -349,40 +178,60 @@ AndroidSurfaceTexture::~AndroidSurfaceTexture() mFrameAvailableCallback = nullptr; - JNIEnv* env = GetJNIForThread(); - if (mSurfaceTexture) { - GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture); - - env->DeleteGlobalRef(mSurfaceTexture); + GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture->wrappedObject()); mSurfaceTexture = nullptr; } - - if (mSurface) { - env->DeleteGlobalRef(mSurface); - mSurface = nullptr; - } } void AndroidSurfaceTexture::UpdateTexImage() { - sJNIFunctions.UpdateTexImage(mSurfaceTexture); + mSurfaceTexture->UpdateTexImage(); } -bool +void AndroidSurfaceTexture::GetTransformMatrix(gfx::Matrix4x4& aMatrix) { - return sJNIFunctions.GetTransformMatrix(mSurfaceTexture, aMatrix); + JNIEnv* env = GetJNIForThread(); + + AutoLocalJNIFrame jniFrame(env); + + jfloatArray jarray = env->NewFloatArray(16); + mSurfaceTexture->GetTransformMatrix(jarray); + + jfloat* array = env->GetFloatArrayElements(jarray, nullptr); + + aMatrix._11 = array[0]; + aMatrix._12 = array[1]; + aMatrix._13 = array[2]; + aMatrix._14 = array[3]; + + aMatrix._21 = array[4]; + aMatrix._22 = array[5]; + aMatrix._23 = array[6]; + aMatrix._24 = array[7]; + + aMatrix._31 = array[8]; + aMatrix._32 = array[9]; + aMatrix._33 = array[10]; + aMatrix._34 = array[11]; + + aMatrix._41 = array[12]; + aMatrix._42 = array[13]; + aMatrix._43 = array[14]; + aMatrix._44 = array[15]; + + env->ReleaseFloatArrayElements(jarray, array, 0); } void AndroidSurfaceTexture::SetFrameAvailableCallback(nsIRunnable* aRunnable) { if (aRunnable) { - GeckoAppShell::RegisterSurfaceTextureFrameListener(mSurfaceTexture, mID); + GeckoAppShell::RegisterSurfaceTextureFrameListener(mSurfaceTexture->wrappedObject(), mID); } else { - GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture); + GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture->wrappedObject()); } mFrameAvailableCallback = aRunnable; @@ -391,7 +240,7 @@ AndroidSurfaceTexture::SetFrameAvailableCallback(nsIRunnable* aRunnable) void AndroidSurfaceTexture::SetDefaultSize(mozilla::gfx::IntSize size) { - sJNIFunctions.SetDefaultBufferSize(mSurfaceTexture, size.width, size.height); + mSurfaceTexture->SetDefaultBufferSize(size.width, size.height); } void diff --git a/gfx/gl/AndroidSurfaceTexture.h b/gfx/gl/AndroidSurfaceTexture.h index 76fe8227cce5..5f601bcc7424 100644 --- a/gfx/gl/AndroidSurfaceTexture.h +++ b/gfx/gl/AndroidSurfaceTexture.h @@ -15,6 +15,7 @@ #include "mozilla/gfx/2D.h" #include "mozilla/Monitor.h" +#include "SurfaceTexture.h" #include "AndroidNativeWindow.h" class gfxASurface; @@ -42,30 +43,26 @@ public: // The SurfaceTexture is created in an attached state. This method requires // Android Ice Cream Sandwich. - static AndroidSurfaceTexture* Create(GLContext* aGLContext, GLuint aTexture); + static TemporaryRef Create(GLContext* aGLContext, GLuint aTexture); // Here the SurfaceTexture will be created in a detached state. You must call // Attach() with the GLContext you wish to composite with. It must be done // on the thread where that GLContext is current. This method requires // Android Jelly Bean. - static AndroidSurfaceTexture* Create(); + static TemporaryRef Create(); static AndroidSurfaceTexture* Find(int id); - // Returns with reasonable certainty whether or not we'll - // be able to create and use a SurfaceTexture - static bool Check(); - // If we are on Jelly Bean, the SurfaceTexture can be detached and reattached // to allow consumption from different GLContexts. It is recommended to only // attach while you are consuming in order to allow this. // // Only one GLContext may be attached at any given time. If another is already // attached, we try to wait for it to become detached. - bool Attach(GLContext* aContext, PRIntervalTime aTiemout = PR_INTERVAL_NO_TIMEOUT); + nsresult Attach(GLContext* aContext, PRIntervalTime aTiemout = PR_INTERVAL_NO_TIMEOUT); // This is a noop on ICS, and will always fail - bool Detach(); + nsresult Detach(); GLContext* GetAttachedContext() { return mAttachedContext; } @@ -76,7 +73,7 @@ public: // This attaches the updated data to the TEXTURE_EXTERNAL target void UpdateTexImage(); - bool GetTransformMatrix(mozilla::gfx::Matrix4x4& aMatrix); + void GetTransformMatrix(mozilla::gfx::Matrix4x4& aMatrix); int ID() { return mID; } void SetDefaultSize(mozilla::gfx::IntSize size); @@ -90,7 +87,7 @@ public: void NotifyFrameAvailable(); GLuint Texture() { return mTexture; } - jobject JavaSurface() { return mSurface; } + jobject JavaSurface() { return mSurface->wrappedObject(); } private: AndroidSurfaceTexture(); ~AndroidSurfaceTexture(); @@ -98,8 +95,8 @@ private: bool Init(GLContext* aContext, GLuint aTexture); GLuint mTexture; - jobject mSurfaceTexture; - jobject mSurface; + nsAutoPtr mSurfaceTexture; + nsAutoPtr mSurface; Monitor mMonitor; GLContext* mAttachedContext; diff --git a/gfx/gl/GLBlitHelper.cpp b/gfx/gl/GLBlitHelper.cpp index 7e47f0b2d75e..fa44819869ad 100644 --- a/gfx/gl/GLBlitHelper.cpp +++ b/gfx/gl/GLBlitHelper.cpp @@ -728,7 +728,7 @@ GLBlitHelper::BlitSurfaceTextureImage(layers::SurfaceTextureImage* stImage) ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0); mGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT); - if (!surfaceTexture->Attach(mGL)) { + if (NS_FAILED(surfaceTexture->Attach(mGL))) { return false; } diff --git a/gfx/layers/opengl/TextureHostOGL.cpp b/gfx/layers/opengl/TextureHostOGL.cpp index 5540d5c8d804..6f45c849580f 100644 --- a/gfx/layers/opengl/TextureHostOGL.cpp +++ b/gfx/layers/opengl/TextureHostOGL.cpp @@ -534,9 +534,7 @@ SurfaceTextureHost::Lock() mSize); } - mSurfTex->Attach(gl()); - - return true; + return NS_SUCCEEDED(mSurfTex->Attach(gl())); } void diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp index d713b5db7f1f..6c46e3c36ae1 100644 --- a/widget/android/AndroidBridge.cpp +++ b/widget/android/AndroidBridge.cpp @@ -41,7 +41,9 @@ #include "nsContentUtils.h" #include "nsIScriptError.h" #include "nsIHttpChannel.h" -#include "GeneratedSDKWrappers.h" + +#include "MediaCodec.h" +#include "SurfaceTexture.h" using namespace mozilla; using namespace mozilla::widget::android; @@ -222,8 +224,11 @@ AndroidBridge::Init(JNIEnv *jEnv) InitAndroidJavaWrappers(jEnv); if (mAPIVersion >= 16 /* Jelly Bean */) { - // We only use this for MediaCodec right now - InitSDKStubs(jEnv); + sdk::InitMediaCodecStubs(jEnv); + } + + if (mAPIVersion >= 14 /* ICS */) { + sdk::InitSurfaceTextureStubs(jEnv); } // jEnv should NOT be cached here by anything -- the jEnv here diff --git a/widget/android/AndroidJavaWrappers.cpp b/widget/android/AndroidJavaWrappers.cpp index 3a3ad60b56f9..b22e9f07a4ca 100644 --- a/widget/android/AndroidJavaWrappers.cpp +++ b/widget/android/AndroidJavaWrappers.cpp @@ -11,7 +11,6 @@ #include "mozilla/BasicEvents.h" #include "mozilla/TimeStamp.h" #include "mozilla/TouchEvents.h" -#include "GeneratedSDKWrappers.h" using namespace mozilla; using namespace mozilla::dom; diff --git a/widget/android/GeneratedSDKWrappers.cpp b/widget/android/GeneratedSDKWrappers.cpp deleted file mode 100644 index 28c85a960874..000000000000 --- a/widget/android/GeneratedSDKWrappers.cpp +++ /dev/null @@ -1,1877 +0,0 @@ -// GENERATED CODE -// Generated by the Java program at /build/jarClassProcessors at compile time from -// a given set of jars and a set of requested methods. To update, change the annotations -// on the corresponding Java methods and rerun the build. Manually updating this file -// will cause your build to fail. - -#include "GeneratedSDKWrappers.h" -#include "AndroidBridgeUtilities.h" -#include "nsXPCOMStrings.h" -#include "AndroidBridge.h" -#include "nsDebug.h" - -namespace mozilla { -namespace widget { -namespace android { -jclass MediaCodec::mMediaCodecClass = 0; -jmethodID MediaCodec::jConfigure = 0; -jmethodID MediaCodec::jCreateByCodecName = 0; -jmethodID MediaCodec::jCreateDecoderByType = 0; -jmethodID MediaCodec::jCreateEncoderByType = 0; -jmethodID MediaCodec::jDequeueInputBuffer = 0; -jmethodID MediaCodec::jDequeueOutputBuffer = 0; -jmethodID MediaCodec::jFinalize = 0; -jmethodID MediaCodec::jFlush = 0; -jmethodID MediaCodec::jGetInputBuffers = 0; -jmethodID MediaCodec::jGetOutputBuffers = 0; -jmethodID MediaCodec::jGetOutputFormat = 0; -jmethodID MediaCodec::jQueueInputBuffer = 0; -jmethodID MediaCodec::jQueueSecureInputBuffer = 0; -jmethodID MediaCodec::jRelease = 0; -jmethodID MediaCodec::jReleaseOutputBuffer = 0; -jmethodID MediaCodec::jSetVideoScalingMode = 0; -jmethodID MediaCodec::jStart = 0; -jmethodID MediaCodec::jStop = 0; -jfieldID MediaCodec::jBUFFER_FLAG_CODEC_CONFIG = 0; -jfieldID MediaCodec::jBUFFER_FLAG_END_OF_STREAM = 0; -jfieldID MediaCodec::jBUFFER_FLAG_SYNC_FRAME = 0; -jfieldID MediaCodec::jCONFIGURE_FLAG_ENCODE = 0; -jfieldID MediaCodec::jCRYPTO_MODE_AES_CTR = 0; -jfieldID MediaCodec::jCRYPTO_MODE_UNENCRYPTED = 0; -jfieldID MediaCodec::jINFO_OUTPUT_BUFFERS_CHANGED = 0; -jfieldID MediaCodec::jINFO_OUTPUT_FORMAT_CHANGED = 0; -jfieldID MediaCodec::jINFO_TRY_AGAIN_LATER = 0; -jfieldID MediaCodec::jVIDEO_SCALING_MODE_SCALE_TO_FIT = 0; -jfieldID MediaCodec::jVIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 0; -void MediaCodec::InitStubs(JNIEnv *jEnv) { - initInit(); - - mMediaCodecClass = getClassGlobalRef("android/media/MediaCodec"); - jConfigure = getMethod("configure", "(Landroid/media/MediaFormat;Landroid/view/Surface;Landroid/media/MediaCrypto;I)V"); - jCreateByCodecName = getStaticMethod("createByCodecName", "(Ljava/lang/String;)Landroid/media/MediaCodec;"); - jCreateDecoderByType = getStaticMethod("createDecoderByType", "(Ljava/lang/String;)Landroid/media/MediaCodec;"); - jCreateEncoderByType = getStaticMethod("createEncoderByType", "(Ljava/lang/String;)Landroid/media/MediaCodec;"); - jDequeueInputBuffer = getMethod("dequeueInputBuffer", "(J)I"); - jDequeueOutputBuffer = getMethod("dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I"); - jFinalize = getMethod("finalize", "()V"); - jFlush = getMethod("flush", "()V"); - jGetInputBuffers = getMethod("getInputBuffers", "()[Ljava/nio/ByteBuffer;"); - jGetOutputBuffers = getMethod("getOutputBuffers", "()[Ljava/nio/ByteBuffer;"); - jGetOutputFormat = getMethod("getOutputFormat", "()Landroid/media/MediaFormat;"); - jQueueInputBuffer = getMethod("queueInputBuffer", "(IIIJI)V"); - jQueueSecureInputBuffer = getMethod("queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V"); - jRelease = getMethod("release", "()V"); - jReleaseOutputBuffer = getMethod("releaseOutputBuffer", "(IZ)V"); - jSetVideoScalingMode = getMethod("setVideoScalingMode", "(I)V"); - jStart = getMethod("start", "()V"); - jStop = getMethod("stop", "()V"); - jBUFFER_FLAG_CODEC_CONFIG = getStaticField("BUFFER_FLAG_CODEC_CONFIG", "I"); - jBUFFER_FLAG_END_OF_STREAM = getStaticField("BUFFER_FLAG_END_OF_STREAM", "I"); - jBUFFER_FLAG_SYNC_FRAME = getStaticField("BUFFER_FLAG_SYNC_FRAME", "I"); - jCONFIGURE_FLAG_ENCODE = getStaticField("CONFIGURE_FLAG_ENCODE", "I"); - jCRYPTO_MODE_AES_CTR = getStaticField("CRYPTO_MODE_AES_CTR", "I"); - jCRYPTO_MODE_UNENCRYPTED = getStaticField("CRYPTO_MODE_UNENCRYPTED", "I"); - jINFO_OUTPUT_BUFFERS_CHANGED = getStaticField("INFO_OUTPUT_BUFFERS_CHANGED", "I"); - jINFO_OUTPUT_FORMAT_CHANGED = getStaticField("INFO_OUTPUT_FORMAT_CHANGED", "I"); - jINFO_TRY_AGAIN_LATER = getStaticField("INFO_TRY_AGAIN_LATER", "I"); - jVIDEO_SCALING_MODE_SCALE_TO_FIT = getStaticField("VIDEO_SCALING_MODE_SCALE_TO_FIT", "I"); - jVIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = getStaticField("VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING", "I"); -} - -MediaCodec* MediaCodec::Wrap(jobject obj) { - JNIEnv *env = GetJNIForThread(); - MediaCodec* ret = new MediaCodec(obj, env); - env->DeleteLocalRef(obj); - return ret; -} - -bool MediaCodec::Configure(jobject a0, jobject a1, jobject a2, int32_t a3) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(3) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jvalue args[4]; - args[0].l = a0; - args[1].l = a1; - args[2].l = a2; - args[3].i = a3; - - env->CallVoidMethodA(wrapped_obj, jConfigure, args); - if (env->ExceptionCheck()) { - env->ExceptionClear(); - env->PopLocalFrame(nullptr); - return false; - } - env->PopLocalFrame(nullptr); - return true; -} - -jobject MediaCodec::CreateByCodecName(const nsAString& a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(2) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jstring j0 = AndroidBridge::NewJavaString(env, a0); - - jobject temp = env->CallStaticObjectMethod(mMediaCodecClass, jCreateByCodecName, j0); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject MediaCodec::CreateDecoderByType(const nsAString& a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(2) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jstring j0 = AndroidBridge::NewJavaString(env, a0); - - jobject temp = env->CallStaticObjectMethod(mMediaCodecClass, jCreateDecoderByType, j0); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject MediaCodec::CreateEncoderByType(const nsAString& a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(2) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jstring j0 = AndroidBridge::NewJavaString(env, a0); - - jobject temp = env->CallStaticObjectMethod(mMediaCodecClass, jCreateEncoderByType, j0); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -int32_t MediaCodec::DequeueInputBuffer(int64_t a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - int32_t temp = env->CallIntMethod(wrapped_obj, jDequeueInputBuffer, a0); - if (env->ExceptionCheck()) { - env->ExceptionClear(); - env->PopLocalFrame(nullptr); - return MEDIACODEC_EXCEPTION_INDEX; - } - env->PopLocalFrame(nullptr); - return temp; -} - -int32_t MediaCodec::DequeueOutputBuffer(jobject a0, int64_t a1) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - int32_t temp = env->CallIntMethod(wrapped_obj, jDequeueOutputBuffer, a0, a1); - if (env->ExceptionCheck()) { - env->ExceptionClear(); - env->PopLocalFrame(nullptr); - return MEDIACODEC_EXCEPTION_INDEX; - } - env->PopLocalFrame(nullptr); - return temp; -} - -void MediaCodec::Finalize() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - env->CallVoidMethod(wrapped_obj, jFinalize); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); -} - -void MediaCodec::Flush() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - env->CallVoidMethod(wrapped_obj, jFlush); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); -} - -jobjectArray MediaCodec::GetInputBuffers() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jGetInputBuffers); - AndroidBridge::HandleUncaughtException(env); - jobjectArray ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobjectArray MediaCodec::GetOutputBuffers() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jGetOutputBuffers); - AndroidBridge::HandleUncaughtException(env); - jobjectArray ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject MediaCodec::GetOutputFormat() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jGetOutputFormat); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -void MediaCodec::QueueInputBuffer(int32_t a0, int32_t a1, int32_t a2, int64_t a3, int32_t a4) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(5) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jvalue args[5]; - args[0].i = a0; - args[1].i = a1; - args[2].i = a2; - args[3].j = a3; - args[4].i = a4; - - env->CallVoidMethodA(wrapped_obj, jQueueInputBuffer, args); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); -} - -void MediaCodec::QueueSecureInputBuffer(int32_t a0, int32_t a1, jobject a2, int64_t a3, int32_t a4) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jvalue args[5]; - args[0].i = a0; - args[1].i = a1; - args[2].l = a2; - args[3].j = a3; - args[4].i = a4; - - env->CallVoidMethodA(wrapped_obj, jQueueSecureInputBuffer, args); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); -} - -void MediaCodec::Release() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - env->CallVoidMethod(wrapped_obj, jRelease); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); -} - -void MediaCodec::ReleaseOutputBuffer(int32_t a0, bool a1) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - env->CallVoidMethod(wrapped_obj, jReleaseOutputBuffer, a0, a1); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); -} - -void MediaCodec::SetVideoScalingMode(int32_t a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - env->CallVoidMethod(wrapped_obj, jSetVideoScalingMode, a0); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); -} - -bool MediaCodec::Start() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - env->CallVoidMethod(wrapped_obj, jStart); - if (env->ExceptionCheck()) { - env->ExceptionClear(); - env->PopLocalFrame(nullptr); - return false; - } - env->PopLocalFrame(nullptr); - return true; -} - -void MediaCodec::Stop() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - env->CallVoidMethod(wrapped_obj, jStop); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); -} - -int32_t MediaCodec::getBUFFER_FLAG_CODEC_CONFIG() { - JNIEnv *env = GetJNIForThread(); - return env->GetStaticIntField(mMediaCodecClass, jBUFFER_FLAG_CODEC_CONFIG); -} - -int32_t MediaCodec::getBUFFER_FLAG_END_OF_STREAM() { - JNIEnv *env = GetJNIForThread(); - return env->GetStaticIntField(mMediaCodecClass, jBUFFER_FLAG_END_OF_STREAM); -} - -int32_t MediaCodec::getBUFFER_FLAG_SYNC_FRAME() { - JNIEnv *env = GetJNIForThread(); - return env->GetStaticIntField(mMediaCodecClass, jBUFFER_FLAG_SYNC_FRAME); -} - -int32_t MediaCodec::getCONFIGURE_FLAG_ENCODE() { - JNIEnv *env = GetJNIForThread(); - return env->GetStaticIntField(mMediaCodecClass, jCONFIGURE_FLAG_ENCODE); -} - -int32_t MediaCodec::getCRYPTO_MODE_AES_CTR() { - JNIEnv *env = GetJNIForThread(); - return env->GetStaticIntField(mMediaCodecClass, jCRYPTO_MODE_AES_CTR); -} - -int32_t MediaCodec::getCRYPTO_MODE_UNENCRYPTED() { - JNIEnv *env = GetJNIForThread(); - return env->GetStaticIntField(mMediaCodecClass, jCRYPTO_MODE_UNENCRYPTED); -} - -int32_t MediaCodec::getINFO_OUTPUT_BUFFERS_CHANGED() { - JNIEnv *env = GetJNIForThread(); - return env->GetStaticIntField(mMediaCodecClass, jINFO_OUTPUT_BUFFERS_CHANGED); -} - -int32_t MediaCodec::getINFO_OUTPUT_FORMAT_CHANGED() { - JNIEnv *env = GetJNIForThread(); - return env->GetStaticIntField(mMediaCodecClass, jINFO_OUTPUT_FORMAT_CHANGED); -} - -int32_t MediaCodec::getINFO_TRY_AGAIN_LATER() { - JNIEnv *env = GetJNIForThread(); - return env->GetStaticIntField(mMediaCodecClass, jINFO_TRY_AGAIN_LATER); -} - -int32_t MediaCodec::getVIDEO_SCALING_MODE_SCALE_TO_FIT() { - JNIEnv *env = GetJNIForThread(); - return env->GetStaticIntField(mMediaCodecClass, jVIDEO_SCALING_MODE_SCALE_TO_FIT); -} - -int32_t MediaCodec::getVIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING() { - JNIEnv *env = GetJNIForThread(); - return env->GetStaticIntField(mMediaCodecClass, jVIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING); -} -jclass MediaFormat::mMediaFormatClass = 0; -jmethodID MediaFormat::jMediaFormat = 0; -jmethodID MediaFormat::jContainsKey = 0; -jmethodID MediaFormat::jCreateAudioFormat = 0; -jmethodID MediaFormat::jCreateVideoFormat = 0; -jmethodID MediaFormat::jGetByteBuffer = 0; -jmethodID MediaFormat::jGetFloat = 0; -jmethodID MediaFormat::jGetInteger = 0; -jmethodID MediaFormat::jGetLong = 0; -jmethodID MediaFormat::jGetString = 0; -jmethodID MediaFormat::jSetByteBuffer = 0; -jmethodID MediaFormat::jSetFloat = 0; -jmethodID MediaFormat::jSetInteger = 0; -jmethodID MediaFormat::jSetLong = 0; -jmethodID MediaFormat::jSetString = 0; -jmethodID MediaFormat::jToString = 0; -jfieldID MediaFormat::jKEY_AAC_PROFILE = 0; -jfieldID MediaFormat::jKEY_BIT_RATE = 0; -jfieldID MediaFormat::jKEY_CHANNEL_COUNT = 0; -jfieldID MediaFormat::jKEY_CHANNEL_MASK = 0; -jfieldID MediaFormat::jKEY_COLOR_FORMAT = 0; -jfieldID MediaFormat::jKEY_DURATION = 0; -jfieldID MediaFormat::jKEY_FLAC_COMPRESSION_LEVEL = 0; -jfieldID MediaFormat::jKEY_FRAME_RATE = 0; -jfieldID MediaFormat::jKEY_HEIGHT = 0; -jfieldID MediaFormat::jKEY_IS_ADTS = 0; -jfieldID MediaFormat::jKEY_I_FRAME_INTERVAL = 0; -jfieldID MediaFormat::jKEY_MAX_INPUT_SIZE = 0; -jfieldID MediaFormat::jKEY_MIME = 0; -jfieldID MediaFormat::jKEY_SAMPLE_RATE = 0; -jfieldID MediaFormat::jKEY_WIDTH = 0; -void MediaFormat::InitStubs(JNIEnv *jEnv) { - initInit(); - - mMediaFormatClass = getClassGlobalRef("android/media/MediaFormat"); - jMediaFormat = getMethod("", "()V"); - jContainsKey = getMethod("containsKey", "(Ljava/lang/String;)Z"); - jCreateAudioFormat = getStaticMethod("createAudioFormat", "(Ljava/lang/String;II)Landroid/media/MediaFormat;"); - jCreateVideoFormat = getStaticMethod("createVideoFormat", "(Ljava/lang/String;II)Landroid/media/MediaFormat;"); - jGetByteBuffer = getMethod("getByteBuffer", "(Ljava/lang/String;)Ljava/nio/ByteBuffer;"); - jGetFloat = getMethod("getFloat", "(Ljava/lang/String;)F"); - jGetInteger = getMethod("getInteger", "(Ljava/lang/String;)I"); - jGetLong = getMethod("getLong", "(Ljava/lang/String;)J"); - jGetString = getMethod("getString", "(Ljava/lang/String;)Ljava/lang/String;"); - jSetByteBuffer = getMethod("setByteBuffer", "(Ljava/lang/String;Ljava/nio/ByteBuffer;)V"); - jSetFloat = getMethod("setFloat", "(Ljava/lang/String;F)V"); - jSetInteger = getMethod("setInteger", "(Ljava/lang/String;I)V"); - jSetLong = getMethod("setLong", "(Ljava/lang/String;J)V"); - jSetString = getMethod("setString", "(Ljava/lang/String;Ljava/lang/String;)V"); - jToString = getMethod("toString", "()Ljava/lang/String;"); - jKEY_AAC_PROFILE = getStaticField("KEY_AAC_PROFILE", "Ljava/lang/String;"); - jKEY_BIT_RATE = getStaticField("KEY_BIT_RATE", "Ljava/lang/String;"); - jKEY_CHANNEL_COUNT = getStaticField("KEY_CHANNEL_COUNT", "Ljava/lang/String;"); - jKEY_CHANNEL_MASK = getStaticField("KEY_CHANNEL_MASK", "Ljava/lang/String;"); - jKEY_COLOR_FORMAT = getStaticField("KEY_COLOR_FORMAT", "Ljava/lang/String;"); - jKEY_DURATION = getStaticField("KEY_DURATION", "Ljava/lang/String;"); - jKEY_FLAC_COMPRESSION_LEVEL = getStaticField("KEY_FLAC_COMPRESSION_LEVEL", "Ljava/lang/String;"); - jKEY_FRAME_RATE = getStaticField("KEY_FRAME_RATE", "Ljava/lang/String;"); - jKEY_HEIGHT = getStaticField("KEY_HEIGHT", "Ljava/lang/String;"); - jKEY_IS_ADTS = getStaticField("KEY_IS_ADTS", "Ljava/lang/String;"); - jKEY_I_FRAME_INTERVAL = getStaticField("KEY_I_FRAME_INTERVAL", "Ljava/lang/String;"); - jKEY_MAX_INPUT_SIZE = getStaticField("KEY_MAX_INPUT_SIZE", "Ljava/lang/String;"); - jKEY_MIME = getStaticField("KEY_MIME", "Ljava/lang/String;"); - jKEY_SAMPLE_RATE = getStaticField("KEY_SAMPLE_RATE", "Ljava/lang/String;"); - jKEY_WIDTH = getStaticField("KEY_WIDTH", "Ljava/lang/String;"); -} - -MediaFormat* MediaFormat::Wrap(jobject obj) { - JNIEnv *env = GetJNIForThread(); - MediaFormat* ret = new MediaFormat(obj, env); - env->DeleteLocalRef(obj); - return ret; -} - -MediaFormat::MediaFormat() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - Init(env->NewObject(mMediaFormatClass, jMediaFormat), env); - env->PopLocalFrame(nullptr); -} - -bool MediaFormat::ContainsKey(const nsAString& a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jstring j0 = AndroidBridge::NewJavaString(env, a0); - - bool temp = env->CallBooleanMethod(wrapped_obj, jContainsKey, j0); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -jobject MediaFormat::CreateAudioFormat(const nsAString& a0, int32_t a1, int32_t a2) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(2) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jvalue args[3]; - args[0].l = AndroidBridge::NewJavaString(env, a0); - args[1].i = a1; - args[2].i = a2; - - jobject temp = env->CallStaticObjectMethodA(mMediaFormatClass, jCreateAudioFormat, args); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject MediaFormat::CreateVideoFormat(const nsAString& a0, int32_t a1, int32_t a2) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(2) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jvalue args[3]; - args[0].l = AndroidBridge::NewJavaString(env, a0); - args[1].i = a1; - args[2].i = a2; - - jobject temp = env->CallStaticObjectMethodA(mMediaFormatClass, jCreateVideoFormat, args); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject MediaFormat::GetByteBuffer(const nsAString& a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(2) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jstring j0 = AndroidBridge::NewJavaString(env, a0); - - jobject temp = env->CallObjectMethod(wrapped_obj, jGetByteBuffer, j0); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jfloat MediaFormat::GetFloat(const nsAString& a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jstring j0 = AndroidBridge::NewJavaString(env, a0); - - jfloat temp = env->CallFloatMethod(wrapped_obj, jGetFloat, j0); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -int32_t MediaFormat::GetInteger(const nsAString& a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jstring j0 = AndroidBridge::NewJavaString(env, a0); - - int32_t temp = env->CallIntMethod(wrapped_obj, jGetInteger, j0); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -int64_t MediaFormat::GetLong(const nsAString& a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jstring j0 = AndroidBridge::NewJavaString(env, a0); - - int64_t temp = env->CallLongMethod(wrapped_obj, jGetLong, j0); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -jstring MediaFormat::GetString(const nsAString& a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(2) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jstring j0 = AndroidBridge::NewJavaString(env, a0); - - jobject temp = env->CallObjectMethod(wrapped_obj, jGetString, j0); - AndroidBridge::HandleUncaughtException(env); - jstring ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -void MediaFormat::SetByteBuffer(const nsAString& a0, jobject a1) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(2) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jstring j0 = AndroidBridge::NewJavaString(env, a0); - - env->CallVoidMethod(wrapped_obj, jSetByteBuffer, j0, a1); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); -} - -void MediaFormat::SetFloat(const nsAString& a0, jfloat a1) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jstring j0 = AndroidBridge::NewJavaString(env, a0); - - env->CallVoidMethod(wrapped_obj, jSetFloat, j0, a1); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); -} - -void MediaFormat::SetInteger(const nsAString& a0, int32_t a1) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jstring j0 = AndroidBridge::NewJavaString(env, a0); - - env->CallVoidMethod(wrapped_obj, jSetInteger, j0, a1); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); -} - -void MediaFormat::SetLong(const nsAString& a0, int64_t a1) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jstring j0 = AndroidBridge::NewJavaString(env, a0); - - env->CallVoidMethod(wrapped_obj, jSetLong, j0, a1); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); -} - -void MediaFormat::SetString(const nsAString& a0, const nsAString& a1) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(2) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jstring j0 = AndroidBridge::NewJavaString(env, a0); - jstring j1 = AndroidBridge::NewJavaString(env, a1); - - env->CallVoidMethod(wrapped_obj, jSetString, j0, j1); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); -} - -jstring MediaFormat::ToString() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jToString); - AndroidBridge::HandleUncaughtException(env); - jstring ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jstring MediaFormat::getKEY_AAC_PROFILE() { - JNIEnv *env = GetJNIForThread(); - return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_AAC_PROFILE)); -} - -jstring MediaFormat::getKEY_BIT_RATE() { - JNIEnv *env = GetJNIForThread(); - return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_BIT_RATE)); -} - -jstring MediaFormat::getKEY_CHANNEL_COUNT() { - JNIEnv *env = GetJNIForThread(); - return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_CHANNEL_COUNT)); -} - -jstring MediaFormat::getKEY_CHANNEL_MASK() { - JNIEnv *env = GetJNIForThread(); - return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_CHANNEL_MASK)); -} - -jstring MediaFormat::getKEY_COLOR_FORMAT() { - JNIEnv *env = GetJNIForThread(); - return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_COLOR_FORMAT)); -} - -jstring MediaFormat::getKEY_DURATION() { - JNIEnv *env = GetJNIForThread(); - return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_DURATION)); -} - -jstring MediaFormat::getKEY_FLAC_COMPRESSION_LEVEL() { - JNIEnv *env = GetJNIForThread(); - return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_FLAC_COMPRESSION_LEVEL)); -} - -jstring MediaFormat::getKEY_FRAME_RATE() { - JNIEnv *env = GetJNIForThread(); - return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_FRAME_RATE)); -} - -jstring MediaFormat::getKEY_HEIGHT() { - JNIEnv *env = GetJNIForThread(); - return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_HEIGHT)); -} - -jstring MediaFormat::getKEY_IS_ADTS() { - JNIEnv *env = GetJNIForThread(); - return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_IS_ADTS)); -} - -jstring MediaFormat::getKEY_I_FRAME_INTERVAL() { - JNIEnv *env = GetJNIForThread(); - return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_I_FRAME_INTERVAL)); -} - -jstring MediaFormat::getKEY_MAX_INPUT_SIZE() { - JNIEnv *env = GetJNIForThread(); - return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_MAX_INPUT_SIZE)); -} - -jstring MediaFormat::getKEY_MIME() { - JNIEnv *env = GetJNIForThread(); - return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_MIME)); -} - -jstring MediaFormat::getKEY_SAMPLE_RATE() { - JNIEnv *env = GetJNIForThread(); - return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_SAMPLE_RATE)); -} - -jstring MediaFormat::getKEY_WIDTH() { - JNIEnv *env = GetJNIForThread(); - return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_WIDTH)); -} -jclass ByteBuffer::mByteBufferClass = 0; -jmethodID ByteBuffer::j_get = 0; -jmethodID ByteBuffer::j_put = 0; -jmethodID ByteBuffer::jAllocate = 0; -jmethodID ByteBuffer::jAllocateDirect = 0; -jmethodID ByteBuffer::jArray = 0; -jmethodID ByteBuffer::jArray1 = 0; -jmethodID ByteBuffer::jArrayOffset = 0; -jmethodID ByteBuffer::jAsCharBuffer = 0; -jmethodID ByteBuffer::jAsDoubleBuffer = 0; -jmethodID ByteBuffer::jAsFloatBuffer = 0; -jmethodID ByteBuffer::jAsIntBuffer = 0; -jmethodID ByteBuffer::jAsLongBuffer = 0; -jmethodID ByteBuffer::jAsReadOnlyBuffer = 0; -jmethodID ByteBuffer::jAsShortBuffer = 0; -jmethodID ByteBuffer::jCompact = 0; -jmethodID ByteBuffer::jCompareTo = 0; -jmethodID ByteBuffer::jCompareTo1 = 0; -jmethodID ByteBuffer::jDuplicate = 0; -jmethodID ByteBuffer::jEquals = 0; -jmethodID ByteBuffer::jGet = 0; -jmethodID ByteBuffer::jGet1 = 0; -jmethodID ByteBuffer::jGet10 = 0; -jmethodID ByteBuffer::jGet11 = 0; -jmethodID ByteBuffer::jGetChar = 0; -jmethodID ByteBuffer::jGetChar1 = 0; -jmethodID ByteBuffer::jGetDouble = 0; -jmethodID ByteBuffer::jGetDouble1 = 0; -jmethodID ByteBuffer::jGetFloat = 0; -jmethodID ByteBuffer::jGetFloat1 = 0; -jmethodID ByteBuffer::jGetInt = 0; -jmethodID ByteBuffer::jGetInt1 = 0; -jmethodID ByteBuffer::jGetLong = 0; -jmethodID ByteBuffer::jGetLong1 = 0; -jmethodID ByteBuffer::jGetShort = 0; -jmethodID ByteBuffer::jGetShort1 = 0; -jmethodID ByteBuffer::jHasArray = 0; -jmethodID ByteBuffer::jHashCode = 0; -jmethodID ByteBuffer::jIsDirect = 0; -jmethodID ByteBuffer::jOrder = 0; -jmethodID ByteBuffer::jOrder1 = 0; -jmethodID ByteBuffer::jPut = 0; -jmethodID ByteBuffer::jPut1 = 0; -jmethodID ByteBuffer::jPut12 = 0; -jmethodID ByteBuffer::jPut13 = 0; -jmethodID ByteBuffer::jPut14 = 0; -jmethodID ByteBuffer::jPutChar = 0; -jmethodID ByteBuffer::jPutChar1 = 0; -jmethodID ByteBuffer::jPutDouble = 0; -jmethodID ByteBuffer::jPutDouble1 = 0; -jmethodID ByteBuffer::jPutFloat = 0; -jmethodID ByteBuffer::jPutFloat1 = 0; -jmethodID ByteBuffer::jPutInt = 0; -jmethodID ByteBuffer::jPutInt1 = 0; -jmethodID ByteBuffer::jPutLong = 0; -jmethodID ByteBuffer::jPutLong1 = 0; -jmethodID ByteBuffer::jPutShort = 0; -jmethodID ByteBuffer::jPutShort1 = 0; -jmethodID ByteBuffer::jSlice = 0; -jmethodID ByteBuffer::jToString = 0; -jmethodID ByteBuffer::jWrap = 0; -jmethodID ByteBuffer::jWrap1 = 0; -jfieldID ByteBuffer::jBigEndian = 0; -jfieldID ByteBuffer::jHb = 0; -jfieldID ByteBuffer::jIsReadOnly = 0; -jfieldID ByteBuffer::jNativeByteOrder = 0; -jfieldID ByteBuffer::jOffset = 0; -void ByteBuffer::InitStubs(JNIEnv *jEnv) { - initInit(); - - mByteBufferClass = getClassGlobalRef("java/nio/ByteBuffer"); - //j_get = getMethod("_get", "(I)B"); - //j_put = getMethod("_put", "(IB)V"); - jAllocate = getStaticMethod("allocate", "(I)Ljava/nio/ByteBuffer;"); - jAllocateDirect = getStaticMethod("allocateDirect", "(I)Ljava/nio/ByteBuffer;"); - jArray = getMethod("array", "()Ljava/lang/Object;"); - jArray1 = getMethod("array", "()[B"); - jArrayOffset = getMethod("arrayOffset", "()I"); - jAsCharBuffer = getMethod("asCharBuffer", "()Ljava/nio/CharBuffer;"); - jAsDoubleBuffer = getMethod("asDoubleBuffer", "()Ljava/nio/DoubleBuffer;"); - jAsFloatBuffer = getMethod("asFloatBuffer", "()Ljava/nio/FloatBuffer;"); - jAsIntBuffer = getMethod("asIntBuffer", "()Ljava/nio/IntBuffer;"); - jAsLongBuffer = getMethod("asLongBuffer", "()Ljava/nio/LongBuffer;"); - jAsReadOnlyBuffer = getMethod("asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;"); - jAsShortBuffer = getMethod("asShortBuffer", "()Ljava/nio/ShortBuffer;"); - jCompact = getMethod("compact", "()Ljava/nio/ByteBuffer;"); - jCompareTo = getMethod("compareTo", "(Ljava/lang/Object;)I"); - jCompareTo1 = getMethod("compareTo", "(Ljava/nio/ByteBuffer;)I"); - jDuplicate = getMethod("duplicate", "()Ljava/nio/ByteBuffer;"); - jEquals = getMethod("equals", "(Ljava/lang/Object;)Z"); - jGet = getMethod("get", "()B"); - jGet1 = getMethod("get", "(I)B"); - jGet10 = getMethod("get", "([B)Ljava/nio/ByteBuffer;"); - jGet11 = getMethod("get", "([BII)Ljava/nio/ByteBuffer;"); - jGetChar = getMethod("getChar", "()C"); - jGetChar1 = getMethod("getChar", "(I)C"); - jGetDouble = getMethod("getDouble", "()D"); - jGetDouble1 = getMethod("getDouble", "(I)D"); - jGetFloat = getMethod("getFloat", "()F"); - jGetFloat1 = getMethod("getFloat", "(I)F"); - jGetInt = getMethod("getInt", "()I"); - jGetInt1 = getMethod("getInt", "(I)I"); - jGetLong = getMethod("getLong", "()J"); - jGetLong1 = getMethod("getLong", "(I)J"); - jGetShort = getMethod("getShort", "()S"); - jGetShort1 = getMethod("getShort", "(I)S"); - jHasArray = getMethod("hasArray", "()Z"); - jHashCode = getMethod("hashCode", "()I"); - jIsDirect = getMethod("isDirect", "()Z"); - jOrder = getMethod("order", "()Ljava/nio/ByteOrder;"); - jOrder1 = getMethod("order", "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;"); - jPut = getMethod("put", "(B)Ljava/nio/ByteBuffer;"); - jPut1 = getMethod("put", "(IB)Ljava/nio/ByteBuffer;"); - jPut12 = getMethod("put", "(Ljava/nio/ByteBuffer;)Ljava/nio/ByteBuffer;"); - jPut13 = getMethod("put", "([B)Ljava/nio/ByteBuffer;"); - jPut14 = getMethod("put", "([BII)Ljava/nio/ByteBuffer;"); - jPutChar = getMethod("putChar", "(C)Ljava/nio/ByteBuffer;"); - jPutChar1 = getMethod("putChar", "(IC)Ljava/nio/ByteBuffer;"); - jPutDouble = getMethod("putDouble", "(D)Ljava/nio/ByteBuffer;"); - jPutDouble1 = getMethod("putDouble", "(ID)Ljava/nio/ByteBuffer;"); - jPutFloat = getMethod("putFloat", "(F)Ljava/nio/ByteBuffer;"); - jPutFloat1 = getMethod("putFloat", "(IF)Ljava/nio/ByteBuffer;"); - jPutInt = getMethod("putInt", "(I)Ljava/nio/ByteBuffer;"); - jPutInt1 = getMethod("putInt", "(II)Ljava/nio/ByteBuffer;"); - jPutLong = getMethod("putLong", "(IJ)Ljava/nio/ByteBuffer;"); - jPutLong1 = getMethod("putLong", "(J)Ljava/nio/ByteBuffer;"); - jPutShort = getMethod("putShort", "(IS)Ljava/nio/ByteBuffer;"); - jPutShort1 = getMethod("putShort", "(S)Ljava/nio/ByteBuffer;"); - jSlice = getMethod("slice", "()Ljava/nio/ByteBuffer;"); - jToString = getMethod("toString", "()Ljava/lang/String;"); - jWrap = getStaticMethod("wrap", "([B)Ljava/nio/ByteBuffer;"); - jWrap1 = getStaticMethod("wrap", "([BII)Ljava/nio/ByteBuffer;"); - /* - jBigEndian = getField("bigEndian", "Z"); - jHb = getField("hb", "[B"); - jIsReadOnly = getField("isReadOnly", "Z"); - jNativeByteOrder = getField("nativeByteOrder", "Z"); - jOffset = getField("offset", "I"); - */ -} - -ByteBuffer* ByteBuffer::Wrap(jobject obj) { - JNIEnv *env = GetJNIForThread(); - ByteBuffer* ret = new ByteBuffer(obj, env); - env->DeleteLocalRef(obj); - return ret; -} - -int8_t ByteBuffer::_get(int32_t a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - int8_t temp = env->CallByteMethod(wrapped_obj, j_get, a0); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -void ByteBuffer::_put(int32_t a0, int8_t a1) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - env->CallVoidMethod(wrapped_obj, j_put, a0, a1); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); -} - -jobject ByteBuffer::Allocate(int32_t a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallStaticObjectMethod(mByteBufferClass, jAllocate, a0); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::AllocateDirect(int32_t a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallStaticObjectMethod(mByteBufferClass, jAllocateDirect, a0); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::Array() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jArray); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jbyteArray ByteBuffer::Array1() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jArray1); - AndroidBridge::HandleUncaughtException(env); - jbyteArray ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -int32_t ByteBuffer::ArrayOffset() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - int32_t temp = env->CallIntMethod(wrapped_obj, jArrayOffset); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -jstring ByteBuffer::AsCharBuffer() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jAsCharBuffer); - AndroidBridge::HandleUncaughtException(env); - jstring ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::AsDoubleBuffer() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jAsDoubleBuffer); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::AsFloatBuffer() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jAsFloatBuffer); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::AsIntBuffer() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jAsIntBuffer); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::AsLongBuffer() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jAsLongBuffer); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::AsReadOnlyBuffer() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jAsReadOnlyBuffer); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::AsShortBuffer() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jAsShortBuffer); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::Compact() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jCompact); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -int32_t ByteBuffer::CompareTo(jobject a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - int32_t temp = env->CallIntMethod(wrapped_obj, jCompareTo, a0); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -int32_t ByteBuffer::CompareTo1(jobject a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - int32_t temp = env->CallIntMethod(wrapped_obj, jCompareTo1, a0); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -jobject ByteBuffer::Duplicate() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jDuplicate); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -bool ByteBuffer::Equals(jobject a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - bool temp = env->CallBooleanMethod(wrapped_obj, jEquals, a0); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -int8_t ByteBuffer::Get() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - int8_t temp = env->CallByteMethod(wrapped_obj, jGet); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -int8_t ByteBuffer::Get1(int32_t a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - int8_t temp = env->CallByteMethod(wrapped_obj, jGet1, a0); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -jobject ByteBuffer::Get1(jbyteArray a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(2) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jGet10, a0); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::Get1(jbyteArray a0, int32_t a1, int32_t a2) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(2) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jvalue args[3]; - args[0].l = a0; - args[1].i = a1; - args[2].i = a2; - - jobject temp = env->CallObjectMethodA(wrapped_obj, jGet11, args); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -uint16_t ByteBuffer::GetChar() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - uint16_t temp = env->CallCharMethod(wrapped_obj, jGetChar); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -uint16_t ByteBuffer::GetChar1(int32_t a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - uint16_t temp = env->CallCharMethod(wrapped_obj, jGetChar1, a0); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -jdouble ByteBuffer::GetDouble() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jdouble temp = env->CallDoubleMethod(wrapped_obj, jGetDouble); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -jdouble ByteBuffer::GetDouble1(int32_t a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jdouble temp = env->CallDoubleMethod(wrapped_obj, jGetDouble1, a0); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -jfloat ByteBuffer::GetFloat() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jfloat temp = env->CallFloatMethod(wrapped_obj, jGetFloat); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -jfloat ByteBuffer::GetFloat1(int32_t a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jfloat temp = env->CallFloatMethod(wrapped_obj, jGetFloat1, a0); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -int32_t ByteBuffer::GetInt() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - int32_t temp = env->CallIntMethod(wrapped_obj, jGetInt); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -int32_t ByteBuffer::GetInt1(int32_t a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - int32_t temp = env->CallIntMethod(wrapped_obj, jGetInt1, a0); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -int64_t ByteBuffer::GetLong() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - int64_t temp = env->CallLongMethod(wrapped_obj, jGetLong); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -int64_t ByteBuffer::GetLong1(int32_t a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - int64_t temp = env->CallLongMethod(wrapped_obj, jGetLong1, a0); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -int16_t ByteBuffer::GetShort() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - int16_t temp = env->CallShortMethod(wrapped_obj, jGetShort); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -int16_t ByteBuffer::GetShort1(int32_t a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - int16_t temp = env->CallShortMethod(wrapped_obj, jGetShort1, a0); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -bool ByteBuffer::HasArray() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - bool temp = env->CallBooleanMethod(wrapped_obj, jHasArray); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -int32_t ByteBuffer::HashCode() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - int32_t temp = env->CallIntMethod(wrapped_obj, jHashCode); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -bool ByteBuffer::IsDirect() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - bool temp = env->CallBooleanMethod(wrapped_obj, jIsDirect); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); - return temp; -} - -jobject ByteBuffer::Order() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jOrder); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::Order1(jobject a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(2) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jOrder1, a0); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::Put(int8_t a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jPut, a0); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::Put1(int32_t a0, int8_t a1) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jPut1, a0, a1); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::Put1(jobject a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(2) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jPut12, a0); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::Put1(jbyteArray a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(2) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jPut13, a0); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::Put1(jbyteArray a0, int32_t a1, int32_t a2) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(2) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jvalue args[3]; - args[0].l = a0; - args[1].i = a1; - args[2].i = a2; - - jobject temp = env->CallObjectMethodA(wrapped_obj, jPut14, args); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::PutChar(uint16_t a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jPutChar, a0); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::PutChar1(int32_t a0, uint16_t a1) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jPutChar1, a0, a1); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::PutDouble(jdouble a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jPutDouble, a0); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::PutDouble1(int32_t a0, jdouble a1) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jPutDouble1, a0, a1); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::PutFloat(jfloat a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jPutFloat, a0); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::PutFloat1(int32_t a0, jfloat a1) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jPutFloat1, a0, a1); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::PutInt(int32_t a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jPutInt, a0); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::PutInt1(int32_t a0, int32_t a1) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jPutInt1, a0, a1); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::PutLong(int32_t a0, int64_t a1) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jPutLong, a0, a1); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::PutLong1(int64_t a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jPutLong1, a0); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::PutShort(int32_t a0, int16_t a1) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jPutShort, a0, a1); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::PutShort1(int16_t a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jPutShort1, a0); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::Slice() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jSlice); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jstring ByteBuffer::ToString() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(1) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallObjectMethod(wrapped_obj, jToString); - AndroidBridge::HandleUncaughtException(env); - jstring ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::Wrap1(jbyteArray a0) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(2) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jobject temp = env->CallStaticObjectMethod(mByteBufferClass, jWrap, a0); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -jobject ByteBuffer::Wrap2(jbyteArray a0, int32_t a1, int32_t a2) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(2) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jvalue args[3]; - args[0].l = a0; - args[1].i = a1; - args[2].i = a2; - - jobject temp = env->CallStaticObjectMethodA(mByteBufferClass, jWrap1, args); - AndroidBridge::HandleUncaughtException(env); - jobject ret = static_cast(env->PopLocalFrame(temp)); - return ret; -} - -bool ByteBuffer::getBigEndian() { - JNIEnv *env = GetJNIForThread(); - return env->GetBooleanField(wrapped_obj, jBigEndian); -} - -void ByteBuffer::setBigEndian(bool a0) { - JNIEnv *env = GetJNIForThread(); - env->SetBooleanField(wrapped_obj, jBigEndian, a0); -} - -jbyteArray ByteBuffer::getHb() { - JNIEnv *env = GetJNIForThread(); - return static_cast(env->GetObjectField(wrapped_obj, jHb)); -} - -bool ByteBuffer::getIsReadOnly() { - JNIEnv *env = GetJNIForThread(); - return env->GetBooleanField(wrapped_obj, jIsReadOnly); -} - -void ByteBuffer::setIsReadOnly(bool a0) { - JNIEnv *env = GetJNIForThread(); - env->SetBooleanField(wrapped_obj, jIsReadOnly, a0); -} - -bool ByteBuffer::getNativeByteOrder() { - JNIEnv *env = GetJNIForThread(); - return env->GetBooleanField(wrapped_obj, jNativeByteOrder); -} - -void ByteBuffer::setNativeByteOrder(bool a0) { - JNIEnv *env = GetJNIForThread(); - env->SetBooleanField(wrapped_obj, jNativeByteOrder, a0); -} - -int32_t ByteBuffer::getOffset() { - JNIEnv *env = GetJNIForThread(); - return env->GetIntField(wrapped_obj, jOffset); -} - -jclass BufferInfo::mBufferInfoClass = 0; -jmethodID BufferInfo::jBufferInfo = 0; -jmethodID BufferInfo::jSet = 0; -jfieldID BufferInfo::jFlags = 0; -jfieldID BufferInfo::jOffset = 0; -jfieldID BufferInfo::jPresentationTimeUs = 0; -jfieldID BufferInfo::jSize = 0; -void BufferInfo::InitStubs(JNIEnv *jEnv) { - initInit(); - - mBufferInfoClass = getClassGlobalRef("android/media/MediaCodec$BufferInfo"); - jBufferInfo = getMethod("", "()V"); - jSet = getMethod("set", "(IIJI)V"); - jFlags = getField("flags", "I"); - jOffset = getField("offset", "I"); - jPresentationTimeUs = getField("presentationTimeUs", "J"); - jSize = getField("size", "I"); -} - -BufferInfo* BufferInfo::Wrap(jobject obj) { - JNIEnv *env = GetJNIForThread(); - BufferInfo* ret = new BufferInfo(obj, env); - env->DeleteLocalRef(obj); - return ret; -} - -BufferInfo::BufferInfo() { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - Init(env->NewObject(mBufferInfoClass, jBufferInfo), env); - env->PopLocalFrame(nullptr); -} - -void BufferInfo::Set(int32_t a0, int32_t a1, int64_t a2, int32_t a3) { - JNIEnv *env = GetJNIForThread(); - if (env->PushLocalFrame(0) != 0) { - AndroidBridge::HandleUncaughtException(env); - MOZ_CRASH("Exception should have caused crash."); - } - - jvalue args[4]; - args[0].i = a0; - args[1].i = a1; - args[2].j = a2; - args[3].i = a3; - - env->CallVoidMethodA(wrapped_obj, jSet, args); - AndroidBridge::HandleUncaughtException(env); - env->PopLocalFrame(nullptr); -} - -int32_t BufferInfo::getFlags() { - JNIEnv *env = GetJNIForThread(); - return env->GetIntField(wrapped_obj, jFlags); -} - -void BufferInfo::setFlags(int32_t a0) { - JNIEnv *env = GetJNIForThread(); - env->SetIntField(wrapped_obj, jFlags, a0); -} - -int32_t BufferInfo::getOffset() { - JNIEnv *env = GetJNIForThread(); - return env->GetIntField(wrapped_obj, jOffset); -} - -void BufferInfo::setOffset(int32_t a0) { - JNIEnv *env = GetJNIForThread(); - env->SetIntField(wrapped_obj, jOffset, a0); -} - -int64_t BufferInfo::getPresentationTimeUs() { - JNIEnv *env = GetJNIForThread(); - return env->GetLongField(wrapped_obj, jPresentationTimeUs); -} - -void BufferInfo::setPresentationTimeUs(int64_t a0) { - JNIEnv *env = GetJNIForThread(); - env->SetLongField(wrapped_obj, jPresentationTimeUs, a0); -} - -int32_t BufferInfo::getSize() { - JNIEnv *env = GetJNIForThread(); - return env->GetIntField(wrapped_obj, jSize); -} - -void BufferInfo::setSize(int32_t a0) { - JNIEnv *env = GetJNIForThread(); - env->SetIntField(wrapped_obj, jSize, a0); -} - -void InitSDKStubs(JNIEnv *jEnv) { - MediaCodec::InitStubs(jEnv); - MediaFormat::InitStubs(jEnv); - ByteBuffer::InitStubs(jEnv); - BufferInfo::InitStubs(jEnv); -} -} /* android */ -} /* widget */ -} /* mozilla */ diff --git a/widget/android/GeneratedSDKWrappers.h b/widget/android/GeneratedSDKWrappers.h deleted file mode 100644 index 6368892fbb5c..000000000000 --- a/widget/android/GeneratedSDKWrappers.h +++ /dev/null @@ -1,335 +0,0 @@ -// GENERATED CODE - -// NOTE: This code has been doctored. The JarClassProcessor is still a work in progress, -// and so additions and deletions have been made to make this file valid. - -// Generated by the Java program at /build/jarClassProcessors at compile time from -// a given set of jars and a set of requested methods. To update, change the annotations -// on the corresponding Java methods and rerun the build. Manually updating this file -// will cause your build to fail. - -#ifndef GeneratedSDKWrappers_h__ -#define GeneratedSDKWrappers_h__ - -#include "nsXPCOMStrings.h" -#include "AndroidJavaWrappers.h" - -namespace mozilla { -namespace widget { -namespace android { - -#define MEDIACODEC_EXCEPTION_INDEX -255 - -void InitSDKStubs(JNIEnv *jEnv); - -class MediaCodec : public AutoGlobalWrappedJavaObject { -public: - static void InitStubs(JNIEnv *jEnv); - static MediaCodec* Wrap(jobject obj); - MediaCodec(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; - bool Configure(jobject a0, jobject a1, jobject a2, int32_t a3); - static jobject CreateByCodecName(const nsAString& a0); - static jobject CreateDecoderByType(const nsAString& a0); - static jobject CreateEncoderByType(const nsAString& a0); - int32_t DequeueInputBuffer(int64_t a0); - int32_t DequeueOutputBuffer(jobject a0, int64_t a1); - void Finalize(); - void Flush(); - jobjectArray GetInputBuffers(); - jobjectArray GetOutputBuffers(); - jobject GetOutputFormat(); - void QueueInputBuffer(int32_t a0, int32_t a1, int32_t a2, int64_t a3, int32_t a4); - void QueueSecureInputBuffer(int32_t a0, int32_t a1, jobject a2, int64_t a3, int32_t a4); - void Release(); - void ReleaseOutputBuffer(int32_t a0, bool a1); - void SetVideoScalingMode(int32_t a0); - bool Start(); - void Stop(); - static int32_t getBUFFER_FLAG_CODEC_CONFIG(); - static int32_t getBUFFER_FLAG_END_OF_STREAM(); - static int32_t getBUFFER_FLAG_SYNC_FRAME(); - static int32_t getCONFIGURE_FLAG_ENCODE(); - static int32_t getCRYPTO_MODE_AES_CTR(); - static int32_t getCRYPTO_MODE_UNENCRYPTED(); - static int32_t getINFO_OUTPUT_BUFFERS_CHANGED(); - static int32_t getINFO_OUTPUT_FORMAT_CHANGED(); - static int32_t getINFO_TRY_AGAIN_LATER(); - static int32_t getVIDEO_SCALING_MODE_SCALE_TO_FIT(); - static int32_t getVIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING(); - MediaCodec() : AutoGlobalWrappedJavaObject() {}; -protected: - static jclass mMediaCodecClass; - static jmethodID jConfigure; - static jmethodID jCreateByCodecName; - static jmethodID jCreateDecoderByType; - static jmethodID jCreateEncoderByType; - static jmethodID jDequeueInputBuffer; - static jmethodID jDequeueOutputBuffer; - static jmethodID jFinalize; - static jmethodID jFlush; - static jmethodID jGetInputBuffers; - static jmethodID jGetOutputBuffers; - static jmethodID jGetOutputFormat; - static jmethodID jQueueInputBuffer; - static jmethodID jQueueSecureInputBuffer; - static jmethodID jRelease; - static jmethodID jReleaseOutputBuffer; - static jmethodID jSetVideoScalingMode; - static jmethodID jStart; - static jmethodID jStop; - static jfieldID jBUFFER_FLAG_CODEC_CONFIG; - static jfieldID jBUFFER_FLAG_END_OF_STREAM; - static jfieldID jBUFFER_FLAG_SYNC_FRAME; - static jfieldID jCONFIGURE_FLAG_ENCODE; - static jfieldID jCRYPTO_MODE_AES_CTR; - static jfieldID jCRYPTO_MODE_UNENCRYPTED; - static jfieldID jINFO_OUTPUT_BUFFERS_CHANGED; - static jfieldID jINFO_OUTPUT_FORMAT_CHANGED; - static jfieldID jINFO_TRY_AGAIN_LATER; - static jfieldID jVIDEO_SCALING_MODE_SCALE_TO_FIT; - static jfieldID jVIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING; -}; - -class MediaFormat : public AutoGlobalWrappedJavaObject { -public: - static void InitStubs(JNIEnv *jEnv); - static MediaFormat* Wrap(jobject obj); - MediaFormat(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; - MediaFormat(); - bool ContainsKey(const nsAString& a0); - static jobject CreateAudioFormat(const nsAString& a0, int32_t a1, int32_t a2); - static jobject CreateVideoFormat(const nsAString& a0, int32_t a1, int32_t a2); - jobject GetByteBuffer(const nsAString& a0); - jfloat GetFloat(const nsAString& a0); - int32_t GetInteger(const nsAString& a0); - int64_t GetLong(const nsAString& a0); - jstring GetString(const nsAString& a0); - void SetByteBuffer(const nsAString& a0, jobject a1); - void SetFloat(const nsAString& a0, jfloat a1); - void SetInteger(const nsAString& a0, int32_t a1); - void SetLong(const nsAString& a0, int64_t a1); - void SetString(const nsAString& a0, const nsAString& a1); - jstring ToString(); - static jstring getKEY_AAC_PROFILE(); - static jstring getKEY_BIT_RATE(); - static jstring getKEY_CHANNEL_COUNT(); - static jstring getKEY_CHANNEL_MASK(); - static jstring getKEY_COLOR_FORMAT(); - static jstring getKEY_DURATION(); - static jstring getKEY_FLAC_COMPRESSION_LEVEL(); - static jstring getKEY_FRAME_RATE(); - static jstring getKEY_HEIGHT(); - static jstring getKEY_IS_ADTS(); - static jstring getKEY_I_FRAME_INTERVAL(); - static jstring getKEY_MAX_INPUT_SIZE(); - static jstring getKEY_MIME(); - static jstring getKEY_SAMPLE_RATE(); - static jstring getKEY_WIDTH(); -protected: - static jclass mMediaFormatClass; - static jmethodID jMediaFormat; - static jmethodID jContainsKey; - static jmethodID jCreateAudioFormat; - static jmethodID jCreateVideoFormat; - static jmethodID jGetByteBuffer; - static jmethodID jGetFloat; - static jmethodID jGetInteger; - static jmethodID jGetLong; - static jmethodID jGetString; - static jmethodID jSetByteBuffer; - static jmethodID jSetFloat; - static jmethodID jSetInteger; - static jmethodID jSetLong; - static jmethodID jSetString; - static jmethodID jToString; - static jfieldID jKEY_AAC_PROFILE; - static jfieldID jKEY_BIT_RATE; - static jfieldID jKEY_CHANNEL_COUNT; - static jfieldID jKEY_CHANNEL_MASK; - static jfieldID jKEY_COLOR_FORMAT; - static jfieldID jKEY_DURATION; - static jfieldID jKEY_FLAC_COMPRESSION_LEVEL; - static jfieldID jKEY_FRAME_RATE; - static jfieldID jKEY_HEIGHT; - static jfieldID jKEY_IS_ADTS; - static jfieldID jKEY_I_FRAME_INTERVAL; - static jfieldID jKEY_MAX_INPUT_SIZE; - static jfieldID jKEY_MIME; - static jfieldID jKEY_SAMPLE_RATE; - static jfieldID jKEY_WIDTH; -}; - -class ByteBuffer : public AutoGlobalWrappedJavaObject { -public: - static void InitStubs(JNIEnv *jEnv); - static ByteBuffer* Wrap(jobject obj); - ByteBuffer(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; - int8_t _get(int32_t a0); - void _put(int32_t a0, int8_t a1); - static jobject Allocate(int32_t a0); - static jobject AllocateDirect(int32_t a0); - jobject Array(); - jbyteArray Array1(); - int32_t ArrayOffset(); - jstring AsCharBuffer(); - jobject AsDoubleBuffer(); - jobject AsFloatBuffer(); - jobject AsIntBuffer(); - jobject AsLongBuffer(); - jobject AsReadOnlyBuffer(); - jobject AsShortBuffer(); - jobject Compact(); - int32_t CompareTo(jobject a0); - int32_t CompareTo1(jobject a0); - jobject Duplicate(); - bool Equals(jobject a0); - int8_t Get(); - int8_t Get1(int32_t a0); - jobject Get1(jbyteArray a0); - jobject Get1(jbyteArray a0, int32_t a1, int32_t a2); - uint16_t GetChar(); - uint16_t GetChar1(int32_t a0); - jdouble GetDouble(); - jdouble GetDouble1(int32_t a0); - jfloat GetFloat(); - jfloat GetFloat1(int32_t a0); - int32_t GetInt(); - int32_t GetInt1(int32_t a0); - int64_t GetLong(); - int64_t GetLong1(int32_t a0); - int16_t GetShort(); - int16_t GetShort1(int32_t a0); - bool HasArray(); - int32_t HashCode(); - bool IsDirect(); - jobject Order(); - jobject Order1(jobject a0); - jobject Put(int8_t a0); - jobject Put1(int32_t a0, int8_t a1); - jobject Put1(jobject a0); - jobject Put1(jbyteArray a0); - jobject Put1(jbyteArray a0, int32_t a1, int32_t a2); - jobject PutChar(uint16_t a0); - jobject PutChar1(int32_t a0, uint16_t a1); - jobject PutDouble(jdouble a0); - jobject PutDouble1(int32_t a0, jdouble a1); - jobject PutFloat(jfloat a0); - jobject PutFloat1(int32_t a0, jfloat a1); - jobject PutInt(int32_t a0); - jobject PutInt1(int32_t a0, int32_t a1); - jobject PutLong(int32_t a0, int64_t a1); - jobject PutLong1(int64_t a0); - jobject PutShort(int32_t a0, int16_t a1); - jobject PutShort1(int16_t a0); - jobject Slice(); - jstring ToString(); - static jobject Wrap1(jbyteArray a0); - static jobject Wrap2(jbyteArray a0, int32_t a1, int32_t a2); - bool getBigEndian(); - void setBigEndian(bool a0); - jbyteArray getHb(); - bool getIsReadOnly(); - void setIsReadOnly(bool a0); - bool getNativeByteOrder(); - void setNativeByteOrder(bool a0); - int32_t getOffset(); - ByteBuffer() : AutoGlobalWrappedJavaObject() {}; -protected: - static jclass mByteBufferClass; - static jmethodID j_get; - static jmethodID j_put; - static jmethodID jAllocate; - static jmethodID jAllocateDirect; - static jmethodID jArray; - static jmethodID jArray1; - static jmethodID jArrayOffset; - static jmethodID jAsCharBuffer; - static jmethodID jAsDoubleBuffer; - static jmethodID jAsFloatBuffer; - static jmethodID jAsIntBuffer; - static jmethodID jAsLongBuffer; - static jmethodID jAsReadOnlyBuffer; - static jmethodID jAsShortBuffer; - static jmethodID jCompact; - static jmethodID jCompareTo; - static jmethodID jCompareTo1; - static jmethodID jDuplicate; - static jmethodID jEquals; - static jmethodID jGet; - static jmethodID jGet1; - static jmethodID jGet10; - static jmethodID jGet11; - static jmethodID jGetChar; - static jmethodID jGetChar1; - static jmethodID jGetDouble; - static jmethodID jGetDouble1; - static jmethodID jGetFloat; - static jmethodID jGetFloat1; - static jmethodID jGetInt; - static jmethodID jGetInt1; - static jmethodID jGetLong; - static jmethodID jGetLong1; - static jmethodID jGetShort; - static jmethodID jGetShort1; - static jmethodID jHasArray; - static jmethodID jHashCode; - static jmethodID jIsDirect; - static jmethodID jOrder; - static jmethodID jOrder1; - static jmethodID jPut; - static jmethodID jPut1; - static jmethodID jPut12; - static jmethodID jPut13; - static jmethodID jPut14; - static jmethodID jPutChar; - static jmethodID jPutChar1; - static jmethodID jPutDouble; - static jmethodID jPutDouble1; - static jmethodID jPutFloat; - static jmethodID jPutFloat1; - static jmethodID jPutInt; - static jmethodID jPutInt1; - static jmethodID jPutLong; - static jmethodID jPutLong1; - static jmethodID jPutShort; - static jmethodID jPutShort1; - static jmethodID jSlice; - static jmethodID jToString; - static jmethodID jWrap; - static jmethodID jWrap1; - static jfieldID jBigEndian; - static jfieldID jHb; - static jfieldID jIsReadOnly; - static jfieldID jNativeByteOrder; - static jfieldID jOffset; -}; - -class BufferInfo : public AutoGlobalWrappedJavaObject { -public: - static void InitStubs(JNIEnv *jEnv); - static BufferInfo* Wrap(jobject obj); - BufferInfo(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; - BufferInfo(); - void Set(int32_t a0, int32_t a1, int64_t a2, int32_t a3); - int32_t getFlags(); - void setFlags(int32_t a0); - int32_t getOffset(); - void setOffset(int32_t a0); - int64_t getPresentationTimeUs(); - void setPresentationTimeUs(int64_t a0); - int32_t getSize(); - void setSize(int32_t a0); -protected: - static jclass mBufferInfoClass; - static jmethodID jBufferInfo; - static jmethodID jSet; - static jfieldID jFlags; - static jfieldID jOffset; - static jfieldID jPresentationTimeUs; - static jfieldID jSize; -}; - -} /* android */ -} /* widget */ -} /* mozilla */ -#endif diff --git a/widget/android/moz.build b/widget/android/moz.build index 70651dc215aa..dee4c7e2f41c 100644 --- a/widget/android/moz.build +++ b/widget/android/moz.build @@ -19,7 +19,6 @@ EXPORTS += [ 'AndroidJavaWrappers.h', 'AndroidJNIWrapper.h', 'GeneratedJNIWrappers.h', - 'GeneratedSDKWrappers.h', ] SOURCES += [ @@ -31,7 +30,6 @@ SOURCES += [ 'AndroidJNIWrapper.cpp', 'APZCCallbackHandler.cpp', 'GeneratedJNIWrappers.cpp', - 'GeneratedSDKWrappers.cpp', 'GfxInfo.cpp', 'NativeJSContainer.cpp', 'nsAndroidProtocolHandler.cpp', From ac342c12fa46d85ee2110e315bc102bf4e760437 Mon Sep 17 00:00:00 2001 From: James Willcox Date: Tue, 11 Nov 2014 14:46:09 -0600 Subject: [PATCH 46/47] Bug 1086693 - Add a Makefile target for updating GeneratedJNIWrappers r=nalexander a=ryanvm CLOSED TREE --HG-- extra : histedit_source : c8b445f2b9cf7fc9ac946c8b38070bded68fdecf --- mobile/android/base/Makefile.in | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index 27e1fde336ad..ffb2e1ece226 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -419,6 +419,13 @@ gradle-targets: .aapt.deps .PHONY: gradle-targets +update-generated-wrappers: + mv $(topsrcdir)/widget/android/GeneratedJNIWrappers.cpp $(topsrcdir)/widget/android/GeneratedJNIWrappers.cpp.old + mv $(topsrcdir)/widget/android/GeneratedJNIWrappers.h $(topsrcdir)/widget/android/GeneratedJNIWrappers.h.old + @cp $(CURDIR)/jni-stubs.inc $(topsrcdir)/mozglue/android + @cp $(CURDIR)/GeneratedJNIWrappers.* $(topsrcdir)/widget/android + @echo Updated GeneratedJNIWrappers + libs:: geckoview_resources.zip classes.dex jni-stubs.inc GeneratedJNIWrappers.cpp fennec_ids.txt $(INSTALL) geckoview_resources.zip $(FINAL_TARGET) $(INSTALL) classes.dex $(FINAL_TARGET) @@ -427,7 +434,7 @@ libs:: geckoview_resources.zip classes.dex jni-stubs.inc GeneratedJNIWrappers.cp echo '*** Error: The generated JNI code has changed ***' && \ echo '* To update generated code in the tree, please run *' && \ echo && \ - echo ' cp $(CURDIR)/jni-stubs.inc $(topsrcdir)/mozglue/android && cp $(CURDIR)/GeneratedJNIWrappers.* $(topsrcdir)/widget/android' && \ + echo ' make -C $(CURDIR) update-generated-wrappers' && \ echo && \ echo '* Repeat the build, and check in any changes. *' && \ echo '*****************************************************' && \ From dfa6d6b02a6ba20114044fcc036a9897e1f5ba15 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Tue, 11 Nov 2014 16:13:15 -0500 Subject: [PATCH 47/47] Backed out 7 changesets (bug 1086693) for Android bustage on a CLOSED TREE. DONTBUILD Backed out changeset 6eed18d830d2 (bug 1086693) Backed out changeset b67a2e48f281 (bug 1086693) Backed out changeset 2b4b439e7e6c (bug 1086693) Backed out changeset 3adfd767a92f (bug 1086693) Backed out changeset 6ea8b9247915 (bug 1086693) Backed out changeset 408af1e3b457 (bug 1086693) Backed out changeset 4c759b83892a (bug 1086693) --- .../annotationProcessors/AnnotationInfo.java | 9 +- .../AnnotationProcessor.java | 6 +- build/annotationProcessors/CodeGenerator.java | 160 +- build/annotationProcessors/Makefile.in | 4 +- build/annotationProcessors/SDKProcessor.java | 255 --- build/annotationProcessors/moz.build | 1 - .../utils/GeneratableElementIterator.java | 10 +- build/annotationProcessors/utils/Utils.java | 32 +- config/recurse.mk | 1 - .../fmp4/android/AndroidDecoderModule.cpp | 121 +- dom/media/fmp4/android/AndroidDecoderModule.h | 19 +- dom/plugins/base/nsNPAPIPluginInstance.cpp | 16 +- dom/plugins/base/nsNPAPIPluginInstance.h | 8 +- gfx/gl/AndroidSurfaceTexture.cpp | 275 ++- gfx/gl/AndroidSurfaceTexture.h | 21 +- gfx/gl/GLBlitHelper.cpp | 2 +- gfx/layers/opengl/TextureHostOGL.cpp | 4 +- mobile/android/base/Makefile.in | 9 +- .../WrapElementForJNI.java | 9 - widget/android/AndroidBridge.cpp | 11 +- widget/android/AndroidJavaWrappers.cpp | 1 + widget/android/GeneratedJNIWrappers.cpp | 438 ++-- widget/android/GeneratedJNIWrappers.h | 38 +- widget/android/GeneratedSDKWrappers.cpp | 1877 +++++++++++++++++ widget/android/GeneratedSDKWrappers.h | 335 +++ widget/android/bindings/Makefile.in | 26 - .../android/bindings/mediacodec-classes.txt | 3 - widget/android/bindings/moz.build | 24 - .../bindings/surfacetexture-classes.txt | 2 - widget/android/moz.build | 6 +- 30 files changed, 2820 insertions(+), 903 deletions(-) delete mode 100644 build/annotationProcessors/SDKProcessor.java create mode 100644 widget/android/GeneratedSDKWrappers.cpp create mode 100644 widget/android/GeneratedSDKWrappers.h delete mode 100644 widget/android/bindings/Makefile.in delete mode 100644 widget/android/bindings/mediacodec-classes.txt delete mode 100644 widget/android/bindings/moz.build delete mode 100644 widget/android/bindings/surfacetexture-classes.txt diff --git a/build/annotationProcessors/AnnotationInfo.java b/build/annotationProcessors/AnnotationInfo.java index 0f2da147d6a7..98fdb17d96fb 100644 --- a/build/annotationProcessors/AnnotationInfo.java +++ b/build/annotationProcessors/AnnotationInfo.java @@ -12,19 +12,12 @@ public class AnnotationInfo { public final boolean isMultithreaded; public final boolean noThrow; public final boolean narrowChars; - public final boolean catchException; public AnnotationInfo(String aWrapperName, boolean aIsMultithreaded, - boolean aNoThrow, boolean aNarrowChars, boolean aCatchException) { + boolean aNoThrow, boolean aNarrowChars) { wrapperName = aWrapperName; isMultithreaded = aIsMultithreaded; noThrow = aNoThrow; narrowChars = aNarrowChars; - catchException = aCatchException; - - if (!noThrow && catchException) { - // It doesn't make sense to have these together - throw new IllegalArgumentException("noThrow and catchException are not allowed together"); - } } } diff --git a/build/annotationProcessors/AnnotationProcessor.java b/build/annotationProcessors/AnnotationProcessor.java index 66c3918d2744..bcd70a58ee8f 100644 --- a/build/annotationProcessors/AnnotationProcessor.java +++ b/build/annotationProcessors/AnnotationProcessor.java @@ -52,7 +52,7 @@ public class AnnotationProcessor { "namespace mozilla {\n" + "namespace widget {\n" + "namespace android {\n" + - "void InitStubs(JNIEnv *env);\n\n"); + "void InitStubs(JNIEnv *jEnv);\n\n"); StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT); implementationFile.append("#include \"GeneratedJNIWrappers.h\"\n" + @@ -66,7 +66,7 @@ public class AnnotationProcessor { // Used to track the calls to the various class-specific initialisation functions. StringBuilder stubInitialiser = new StringBuilder(); - stubInitialiser.append("void InitStubs(JNIEnv *env) {\n"); + stubInitialiser.append("void InitStubs(JNIEnv *jEnv) {\n"); while (jarClassIterator.hasNext()) { ClassWithOptions aClassTuple = jarClassIterator.next(); @@ -81,7 +81,7 @@ public class AnnotationProcessor { } generatorInstance = new CodeGenerator(aClassTuple.wrappedClass, aClassTuple.generatedName); - stubInitialiser.append(" ").append(aClassTuple.generatedName).append("::InitStubs(env);\n"); + stubInitialiser.append(" ").append(aClassTuple.generatedName).append("::InitStubs(jEnv);\n"); // Iterate all annotated members in this class.. while (methodIterator.hasNext()) { diff --git a/build/annotationProcessors/CodeGenerator.java b/build/annotationProcessors/CodeGenerator.java index 215b0009e8dc..cb28e6fc4729 100644 --- a/build/annotationProcessors/CodeGenerator.java +++ b/build/annotationProcessors/CodeGenerator.java @@ -12,7 +12,6 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.HashSet; @@ -41,27 +40,21 @@ public class CodeGenerator { private final HashSet mTakenMemberNames = new HashSet(); private int mNameMunger; - private final boolean mLazyInit; - public CodeGenerator(Class aClass, String aGeneratedName) { - this(aClass, aGeneratedName, false); - } - - public CodeGenerator(Class aClass, String aGeneratedName, boolean aLazyInit) { mClassToWrap = aClass; mCClassName = aGeneratedName; - mLazyInit = aLazyInit; // Write the file header things. Includes and so forth. // GeneratedJNIWrappers.cpp is generated as the concatenation of wrapperStartupCode with // wrapperMethodBodies. Similarly, GeneratedJNIWrappers.h is the concatenation of headerPublic // with headerProtected. - wrapperStartupCode.append("void ").append(mCClassName).append("::InitStubs(JNIEnv *env) {\n"); + wrapperStartupCode.append("void ").append(mCClassName).append("::InitStubs(JNIEnv *jEnv) {\n" + + " initInit();\n"); // Now we write the various GetStaticMethodID calls here... headerPublic.append("class ").append(mCClassName).append(" : public AutoGlobalWrappedJavaObject {\n" + "public:\n" + - " static void InitStubs(JNIEnv *env);\n"); + " static void InitStubs(JNIEnv *jEnv);\n"); headerProtected.append("protected:"); generateWrapperMethod(); @@ -86,10 +79,7 @@ public class CodeGenerator { private void generateMemberCommon(Member theMethod, String aCMethodName, Class aClass) { ensureClassHeaderAndStartup(aClass); writeMemberIdField(theMethod, aCMethodName); - - if (!mLazyInit) { - writeMemberInit(theMethod, wrapperStartupCode); - } + writeStartupCode(theMethod); } /** @@ -111,10 +101,8 @@ public class CodeGenerator { Class returnType = theMethod.getReturnType(); // Get the C++ method signature for this method. - String implementationSignature = Utils.getCImplementationMethodSignature(parameterTypes, returnType, CMethodName, - mCClassName, aMethodTuple.mAnnotationInfo.narrowChars, aMethodTuple.mAnnotationInfo.catchException); - String headerSignature = Utils.getCHeaderMethodSignature(parameterTypes, theMethod.getParameterAnnotations(), returnType, - CMethodName, mCClassName, isFieldStatic, aMethodTuple.mAnnotationInfo.narrowChars, aMethodTuple.mAnnotationInfo.catchException); + String implementationSignature = Utils.getCImplementationMethodSignature(parameterTypes, returnType, CMethodName, mCClassName, aMethodTuple.mAnnotationInfo.narrowChars); + String headerSignature = Utils.getCHeaderMethodSignature(parameterTypes, theMethod.getParameterAnnotations(), returnType, CMethodName, mCClassName, isFieldStatic, aMethodTuple.mAnnotationInfo.narrowChars); // Add the header signature to the header file. writeSignatureToHeader(headerSignature); @@ -123,25 +111,19 @@ public class CodeGenerator { writeMethodBody(implementationSignature, theMethod, mClassToWrap, aMethodTuple.mAnnotationInfo.isMultithreaded, aMethodTuple.mAnnotationInfo.noThrow, - aMethodTuple.mAnnotationInfo.narrowChars, - aMethodTuple.mAnnotationInfo.catchException); + aMethodTuple.mAnnotationInfo.narrowChars); } - private void generateGetterOrSetterBody(Field aField, String aFieldName, boolean aIsFieldStatic, boolean isSetter, boolean aNarrowChars) { + private void generateGetterOrSetterBody(Class aFieldType, String aFieldName, boolean aIsFieldStatic, boolean isSetter, boolean aNarrowChars) { StringBuilder argumentContent = null; - Class fieldType = aField.getType(); if (isSetter) { - Class[] setterArguments = new Class[]{fieldType}; + Class[] setterArguments = new Class[]{aFieldType}; // Marshall the argument.. argumentContent = getArgumentMarshalling(setterArguments); } - if (mLazyInit) { - writeMemberInit(aField, wrapperMethodBodies); - } - - boolean isObjectReturningMethod = Utils.isObjectType(fieldType); + boolean isObjectReturningMethod = Utils.isObjectType(aFieldType); wrapperMethodBodies.append(" "); if (isSetter) { wrapperMethodBodies.append("env->Set"); @@ -149,7 +131,7 @@ public class CodeGenerator { wrapperMethodBodies.append("return "); if (isObjectReturningMethod) { - wrapperMethodBodies.append("static_cast<").append(Utils.getCReturnType(fieldType, aNarrowChars)).append(">("); + wrapperMethodBodies.append("static_cast<").append(Utils.getCReturnType(aFieldType, aNarrowChars)).append(">("); } wrapperMethodBodies.append("env->Get"); @@ -158,7 +140,7 @@ public class CodeGenerator { if (aIsFieldStatic) { wrapperMethodBodies.append("Static"); } - wrapperMethodBodies.append(Utils.getFieldType(fieldType)) + wrapperMethodBodies.append(Utils.getFieldType(aFieldType)) .append("Field("); // Static will require the class and the field id. Nonstatic, the object and the field id. @@ -199,14 +181,14 @@ public class CodeGenerator { boolean isFieldFinal = Utils.isMemberFinal(theField); String getterName = "get" + CFieldName; - String getterSignature = Utils.getCImplementationMethodSignature(EMPTY_CLASS_ARRAY, fieldType, getterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars, false); - String getterHeaderSignature = Utils.getCHeaderMethodSignature(EMPTY_CLASS_ARRAY, GETTER_ARGUMENT_ANNOTATIONS, fieldType, getterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars, false); + String getterSignature = Utils.getCImplementationMethodSignature(EMPTY_CLASS_ARRAY, fieldType, getterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars); + String getterHeaderSignature = Utils.getCHeaderMethodSignature(EMPTY_CLASS_ARRAY, GETTER_ARGUMENT_ANNOTATIONS, fieldType, getterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars); writeSignatureToHeader(getterHeaderSignature); writeFunctionStartupBoilerPlate(getterSignature, true); - generateGetterOrSetterBody(theField, CFieldName, isFieldStatic, false, aFieldTuple.mAnnotationInfo.narrowChars); + generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, false, aFieldTuple.mAnnotationInfo.narrowChars); // If field not final, also generate a setter function. if (!isFieldFinal) { @@ -214,14 +196,14 @@ public class CodeGenerator { Class[] setterArguments = new Class[]{fieldType}; - String setterSignature = Utils.getCImplementationMethodSignature(setterArguments, Void.class, setterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars, false); - String setterHeaderSignature = Utils.getCHeaderMethodSignature(setterArguments, SETTER_ARGUMENT_ANNOTATIONS, Void.class, setterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars, false); + String setterSignature = Utils.getCImplementationMethodSignature(setterArguments, Void.class, setterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars); + String setterHeaderSignature = Utils.getCHeaderMethodSignature(setterArguments, SETTER_ARGUMENT_ANNOTATIONS, Void.class, setterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars); writeSignatureToHeader(setterHeaderSignature); writeFunctionStartupBoilerPlate(setterSignature, true); - generateGetterOrSetterBody(theField, CFieldName, isFieldStatic, true, aFieldTuple.mAnnotationInfo.narrowChars); + generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, true, aFieldTuple.mAnnotationInfo.narrowChars); } } @@ -232,10 +214,8 @@ public class CodeGenerator { generateMemberCommon(theCtor, mCClassName, mClassToWrap); - String implementationSignature = Utils.getCImplementationMethodSignature(theCtor.getParameterTypes(), Void.class, CMethodName, - mCClassName, aCtorTuple.mAnnotationInfo.narrowChars, aCtorTuple.mAnnotationInfo.catchException); - String headerSignature = Utils.getCHeaderMethodSignature(theCtor.getParameterTypes(), theCtor.getParameterAnnotations(), Void.class, CMethodName, - mCClassName, false, aCtorTuple.mAnnotationInfo.narrowChars, aCtorTuple.mAnnotationInfo.catchException); + String implementationSignature = Utils.getCImplementationMethodSignature(theCtor.getParameterTypes(), Void.class, CMethodName, mCClassName, aCtorTuple.mAnnotationInfo.narrowChars); + String headerSignature = Utils.getCHeaderMethodSignature(theCtor.getParameterTypes(), theCtor.getParameterAnnotations(), Void.class, CMethodName, mCClassName, false, aCtorTuple.mAnnotationInfo.narrowChars); // Slice off the "void " from the start of the constructor declaration. headerSignature = headerSignature.substring(5); @@ -247,37 +227,13 @@ public class CodeGenerator { // Use the implementation signature to generate the method body... writeCtorBody(implementationSignature, theCtor, aCtorTuple.mAnnotationInfo.isMultithreaded, - aCtorTuple.mAnnotationInfo.noThrow, - aCtorTuple.mAnnotationInfo.catchException); + aCtorTuple.mAnnotationInfo.noThrow); if (theCtor.getParameterTypes().length == 0) { mHasEncounteredDefaultConstructor = true; } } - public void generateMembers(Member[] members) { - for (Member m : members) { - if (!Modifier.isPublic(m.getModifiers())) { - continue; - } - - String name = m.getName(); - name = name.substring(0, 1).toUpperCase() + name.substring(1); - - AnnotationInfo info = new AnnotationInfo(name, true, true, true, true); - AnnotatableEntity entity = new AnnotatableEntity(m, info); - if (m instanceof Constructor) { - generateConstructor(entity); - } else if (m instanceof Method) { - generateMethod(entity); - } else if (m instanceof Field) { - generateField(entity); - } else { - throw new IllegalArgumentException("expected member to be Constructor, Method, or Field"); - } - } - } - /** * Writes the appropriate header and startup code to ensure the existence of a reference to the * class specified. If this is already done, does nothing. @@ -302,7 +258,8 @@ public class CodeGenerator { .append(";\n"); // Add startup code to populate it.. - wrapperStartupCode.append(Utils.getStartupLineForClass(aClass)); + wrapperStartupCode.append('\n') + .append(Utils.getStartupLineForClass(aClass)); seenClasses.add(className); } @@ -414,30 +371,14 @@ public class CodeGenerator { return argumentContent; } - private void writeCatchException() { - wrapperMethodBodies.append( - " if (env->ExceptionCheck()) {\n" + - " env->ExceptionClear();\n" + - " if (aResult) {\n" + - " *aResult = NS_ERROR_FAILURE;\n" + - " }\n" + - " } else if (aResult) {\n" + - " *aResult = NS_OK;\n" + - " }\n\n"); - } - private void writeCtorBody(String implementationSignature, Constructor theCtor, - boolean aIsThreaded, boolean aNoThrow, boolean aCatchException) { + boolean aIsThreaded, boolean aNoThrow) { Class[] argumentTypes = theCtor.getParameterTypes(); writeFunctionStartupBoilerPlate(implementationSignature, aIsThreaded); writeFramePushBoilerplate(theCtor, false, aNoThrow); - if (mLazyInit) { - writeMemberInit(theCtor, wrapperMethodBodies); - } - // Marshall arguments for this constructor, if any... boolean hasArguments = argumentTypes.length != 0; @@ -461,14 +402,9 @@ public class CodeGenerator { wrapperMethodBodies.append(mMembersToIds.get(theCtor)) // Tack on the arguments, if any.. .append(argumentContent) - .append("), env);\n"); - - // Check for exception and set aResult - if (aCatchException) { - writeCatchException(); - } - - wrapperMethodBodies.append(" env->PopLocalFrame(nullptr);\n}\n"); + .append("), env);\n" + + " env->PopLocalFrame(nullptr);\n" + + "}\n"); } /** @@ -481,8 +417,7 @@ public class CodeGenerator { */ private void writeMethodBody(String methodSignature, Method aMethod, Class aClass, boolean aIsMultithreaded, - boolean aNoThrow, boolean aNarrowChars, - boolean aCatchException) { + boolean aNoThrow, boolean aNarrowChars) { Class[] argumentTypes = aMethod.getParameterTypes(); Class returnType = aMethod.getReturnType(); @@ -492,10 +427,6 @@ public class CodeGenerator { writeFramePushBoilerplate(aMethod, isObjectReturningMethod, aNoThrow); - if (mLazyInit) { - writeMemberInit(aMethod, wrapperMethodBodies); - } - // Marshall arguments, if we have any. boolean hasArguments = argumentTypes.length != 0; @@ -550,11 +481,6 @@ public class CodeGenerator { wrapperMethodBodies.append(" AndroidBridge::HandleUncaughtException(env);\n"); } - // Check for exception and set aResult - if (aCatchException) { - writeCatchException(); - } - // If we're returning an object, pop the callee's stack frame extracting our ref as the return // value. if (isObjectReturningMethod) { @@ -575,41 +501,33 @@ public class CodeGenerator { } /** - * Generates the code to get the id of the given member on startup or in the member body if lazy init - * is requested. + * Generates the code to get the id of the given member on startup. * * @param aMember The Java member being wrapped. */ - private void writeMemberInit(Member aMember, StringBuilder aOutput) { - if (mLazyInit) { - aOutput.append(" if (!" + mMembersToIds.get(aMember) + ") {\n "); - } - - aOutput.append(" " + mMembersToIds.get(aMember)).append(" = AndroidBridge::Get"); + private void writeStartupCode(Member aMember) { + wrapperStartupCode.append(" ") + .append(mMembersToIds.get(aMember)) + .append(" = get"); if (Utils.isMemberStatic(aMember)) { - aOutput.append("Static"); + wrapperStartupCode.append("Static"); } boolean isField = aMember instanceof Field; if (isField) { - aOutput.append("FieldID(env, " + Utils.getClassReferenceName(aMember.getDeclaringClass()) + ", \""); + wrapperStartupCode.append("Field(\""); } else { - aOutput.append("MethodID(env, " + Utils.getClassReferenceName(aMember.getDeclaringClass()) + ", \""); + wrapperStartupCode.append("Method(\""); } - if (aMember instanceof Constructor) { - aOutput.append(""); + wrapperStartupCode.append(""); } else { - aOutput.append(aMember.getName()); + wrapperStartupCode.append(aMember.getName()); } - aOutput.append("\", \"") + wrapperStartupCode.append("\", \"") .append(Utils.getTypeSignatureStringForMember(aMember)) .append("\");\n"); - - if (mLazyInit) { - aOutput.append(" }\n\n"); - } } private void writeZeroingFor(Member aMember, final String aMemberName) { diff --git a/build/annotationProcessors/Makefile.in b/build/annotationProcessors/Makefile.in index b21a52bbd1ff..c7661c36fd5f 100644 --- a/build/annotationProcessors/Makefile.in +++ b/build/annotationProcessors/Makefile.in @@ -4,9 +4,9 @@ include $(topsrcdir)/config/rules.mk -JAVA_CLASSPATH := $(ANDROID_SDK)/android.jar:$(ANDROID_SDK)/../../tools/lib/lint.jar:$(ANDROID_SDK)/../../tools/lib/lint-checks.jar +JAVA_CLASSPATH := $(ANDROID_SDK)/android.jar # Include Android specific java flags, instead of what's in rules.mk. include $(topsrcdir)/config/android-common.mk -export:: annotationProcessors.jar +libs:: annotationProcessors.jar diff --git a/build/annotationProcessors/SDKProcessor.java b/build/annotationProcessors/SDKProcessor.java deleted file mode 100644 index 2eab460468a8..000000000000 --- a/build/annotationProcessors/SDKProcessor.java +++ /dev/null @@ -1,255 +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/. */ - -package org.mozilla.gecko.annotationProcessors; - -import com.android.tools.lint.checks.ApiLookup; -import com.android.tools.lint.LintCliClient; - -import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity; -import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions; -import org.mozilla.gecko.annotationProcessors.classloader.IterableJarLoadingURLClassLoader; -import org.mozilla.gecko.annotationProcessors.utils.GeneratableElementIterator; -import org.mozilla.gecko.annotationProcessors.utils.Utils; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.Arrays; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.Iterator; -import java.util.Properties; -import java.util.Scanner; -import java.util.Vector; -import java.net.URL; -import java.net.URLClassLoader; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Member; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - -public class SDKProcessor { - public static final String GENERATED_COMMENT = - "// GENERATED CODE\n" + - "// Generated by the Java program at /build/annotationProcessors at compile time from\n" + - "// annotations on Java methods. To update, change the annotations on the corresponding Java\n" + - "// methods and rerun the build. Manually updating this file will cause your build to fail.\n\n"; - - private static ApiLookup sApiLookup; - private static int sMaxSdkVersion; - - public static void main(String[] args) { - // We expect a list of jars on the commandline. If missing, whinge about it. - if (args.length < 5) { - System.err.println("Usage: java SDKProcessor sdkjar classlistfile outdir fileprefix max-sdk-version"); - System.exit(1); - } - - System.out.println("Processing platform bindings..."); - - String sdkJar = args[0]; - Vector classes = getClassList(args[1]); - String outdir = args[2]; - String generatedFilePrefix = args[3]; - sMaxSdkVersion = Integer.parseInt(args[4]); - - Properties props = System.getProperties(); - props.setProperty("com.android.tools.lint.bindir", - new File(new File(sdkJar).getParentFile(), "../../tools").toString()); - - LintCliClient lintClient = new LintCliClient(); - sApiLookup = ApiLookup.get(lintClient); - - // Start the clock! - long s = System.currentTimeMillis(); - - // Get an iterator over the classes in the jar files given... - // Iterator jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args); - - StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT); - headerFile.append("#ifndef " + generatedFilePrefix + "_h__\n" + - "#define " + generatedFilePrefix + "_h__\n" + - "#include \"nsXPCOMStrings.h\"\n" + - "#include \"AndroidJavaWrappers.h\"\n" + - "\n" + - "namespace mozilla {\n" + - "namespace widget {\n" + - "namespace android {\n" + - "namespace sdk {\n" + - "void Init" + generatedFilePrefix + "Stubs(JNIEnv *jEnv);\n\n"); - - StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT); - implementationFile.append("#include \"" + generatedFilePrefix + ".h\"\n" + - "#include \"AndroidBridgeUtilities.h\"\n" + - "#include \"nsXPCOMStrings.h\"\n" + - "#include \"AndroidBridge.h\"\n" + - "\n" + - "namespace mozilla {\n" + - "namespace widget {\n" + - "namespace android {\n" + - "namespace sdk {\n"); - - // Used to track the calls to the various class-specific initialisation functions. - StringBuilder stubInitializer = new StringBuilder(); - stubInitializer.append("void Init" + generatedFilePrefix + "Stubs(JNIEnv *jEnv) {\n"); - - ClassLoader loader = null; - try { - loader = URLClassLoader.newInstance(new URL[] { new URL("file://" + sdkJar) }, - SDKProcessor.class.getClassLoader()); - } catch (Exception e) { - System.out.println(e); - } - - for (Iterator i = classes.iterator(); i.hasNext(); ) { - String className = i.next(); - System.out.println("Looking up: " + className); - - try { - Class c = Class.forName(className, true, loader); - - generateClass(Class.forName(className, true, loader), - stubInitializer, - implementationFile, - headerFile); - } catch (Exception e) { - System.out.println("Failed to generate class " + className + ": " + e); - } - } - - implementationFile.append('\n'); - stubInitializer.append("}"); - implementationFile.append(stubInitializer); - - implementationFile.append("\n} /* sdk */\n" + - "} /* android */\n" + - "} /* widget */\n" + - "} /* mozilla */\n"); - - headerFile.append("\n} /* sdk */\n" + - "} /* android */\n" + - "} /* widget */\n" + - "} /* mozilla */\n" + - "#endif\n"); - - writeOutputFiles(outdir, generatedFilePrefix, headerFile, implementationFile); - long e = System.currentTimeMillis(); - System.out.println("SDK processing complete in " + (e - s) + "ms"); - } - - private static Member[] sortAndFilterMembers(Member[] members) { - Arrays.sort(members, new Comparator() { - @Override - public int compare(Member a, Member b) { - return a.getName().compareTo(b.getName()); - } - }); - - ArrayList list = new ArrayList<>(); - for (Member m : members) { - int version = 0; - - if (m instanceof Method || m instanceof Constructor) { - version = sApiLookup.getCallVersion(Utils.getTypeSignatureStringForClass(m.getDeclaringClass()), - m.getName(), - Utils.getTypeSignatureStringForMember(m)); - } else if (m instanceof Field) { - version = sApiLookup.getFieldVersion(Utils.getTypeSignatureStringForClass(m.getDeclaringClass()), - m.getName()); - } else { - throw new IllegalArgumentException("expected member to be Method, Constructor, or Field"); - } - - if (version > sMaxSdkVersion) { - System.out.println("Skipping " + m.getDeclaringClass().getName() + "." + m.getName() + - ", version " + version + " > " + sMaxSdkVersion); - continue; - } - - list.add(m); - } - - return list.toArray(new Member[list.size()]); - } - - private static void generateClass(Class clazz, - StringBuilder stubInitializer, - StringBuilder implementationFile, - StringBuilder headerFile) { - String generatedName = clazz.getSimpleName(); - - CodeGenerator generator = new CodeGenerator(clazz, generatedName, true); - stubInitializer.append(" ").append(generatedName).append("::InitStubs(jEnv);\n"); - - generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredConstructors())); - generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredMethods())); - generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredFields())); - - headerFile.append(generator.getHeaderFileContents()); - implementationFile.append(generator.getWrapperFileContents()); - } - - private static Vector getClassList(String path) { - Scanner scanner = null; - try { - scanner = new Scanner(new FileInputStream(path)); - - Vector lines = new Vector(); - while (scanner.hasNextLine()) { - lines.add(scanner.nextLine()); - } - return lines; - } catch (Exception e) { - System.out.println(e.toString()); - return null; - } finally { - if (scanner != null) { - scanner.close(); - } - } - } - - private static void writeOutputFiles(String aOutputDir, String aPrefix, StringBuilder aHeaderFile, - StringBuilder aImplementationFile) { - FileOutputStream implStream = null; - try { - implStream = new FileOutputStream(new File(aOutputDir, aPrefix + ".cpp")); - implStream.write(aImplementationFile.toString().getBytes()); - } catch (IOException e) { - System.err.println("Unable to write " + aOutputDir + ". Perhaps a permissions issue?"); - e.printStackTrace(System.err); - } finally { - if (implStream != null) { - try { - implStream.close(); - } catch (IOException e) { - System.err.println("Unable to close implStream due to "+e); - e.printStackTrace(System.err); - } - } - } - - FileOutputStream headerStream = null; - try { - headerStream = new FileOutputStream(new File(aOutputDir, aPrefix + ".h")); - headerStream.write(aHeaderFile.toString().getBytes()); - } catch (IOException e) { - System.err.println("Unable to write " + aOutputDir + ". Perhaps a permissions issue?"); - e.printStackTrace(System.err); - } finally { - if (headerStream != null) { - try { - headerStream.close(); - } catch (IOException e) { - System.err.println("Unable to close headerStream due to "+e); - e.printStackTrace(System.err); - } - } - } - } -} \ No newline at end of file diff --git a/build/annotationProcessors/moz.build b/build/annotationProcessors/moz.build index c8e0fb8bdcfe..1fbf9938518e 100644 --- a/build/annotationProcessors/moz.build +++ b/build/annotationProcessors/moz.build @@ -13,7 +13,6 @@ jar.sources += [ 'classloader/IterableJarLoadingURLClassLoader.java', 'classloader/JarClassIterator.java', 'CodeGenerator.java', - 'SDKProcessor.java', 'utils/AlphabeticAnnotatableEntityComparator.java', 'utils/GeneratableElementIterator.java', 'utils/Utils.java', diff --git a/build/annotationProcessors/utils/GeneratableElementIterator.java b/build/annotationProcessors/utils/GeneratableElementIterator.java index 32dd2b963e05..6e7b1349fbb1 100644 --- a/build/annotationProcessors/utils/GeneratableElementIterator.java +++ b/build/annotationProcessors/utils/GeneratableElementIterator.java @@ -76,7 +76,6 @@ public class GeneratableElementIterator implements Iterator { boolean isMultithreadedStub = false; boolean noThrow = false; boolean narrowChars = false; - boolean catchException = false; try { // Determine the explicitly-given name of the stub to generate, if any. final Method stubNameMethod = annotationType.getDeclaredMethod("stubName"); @@ -98,11 +97,6 @@ public class GeneratableElementIterator implements Iterator { narrowCharsMethod.setAccessible(true); narrowChars = (Boolean) narrowCharsMethod.invoke(annotation); - // Determine if we should catch exceptions - final Method catchExceptionMethod = annotationType.getDeclaredMethod("catchException"); - catchExceptionMethod.setAccessible(true); - catchException = (Boolean) catchExceptionMethod.invoke(annotation); - } catch (NoSuchMethodException e) { System.err.println("Unable to find expected field on WrapElementForJNI annotation. Did the signature change?"); e.printStackTrace(System.err); @@ -124,7 +118,7 @@ public class GeneratableElementIterator implements Iterator { } AnnotationInfo annotationInfo = new AnnotationInfo( - stubName, isMultithreadedStub, noThrow, narrowChars, catchException); + stubName, isMultithreadedStub, noThrow, narrowChars); mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo); return; } @@ -134,7 +128,7 @@ public class GeneratableElementIterator implements Iterator { // thanks to the "Generate everything" annotation. if (mIterateEveryEntry) { AnnotationInfo annotationInfo = new AnnotationInfo( - candidateElement.getName(), false, false, false, false); + candidateElement.getName(), false, false, false); mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo); return; } diff --git a/build/annotationProcessors/utils/Utils.java b/build/annotationProcessors/utils/Utils.java index 44876ebb4b99..f13ae66e1461 100644 --- a/build/annotationProcessors/utils/Utils.java +++ b/build/annotationProcessors/utils/Utils.java @@ -318,10 +318,6 @@ public class Utils { } } - public static String getTypeSignatureStringForClass(Class clazz) { - return clazz.getCanonicalName().replace('.', '/'); - } - public static String getTypeSignatureString(Constructor aConstructor) { Class[] arguments = aConstructor.getParameterTypes(); StringBuilder sb = new StringBuilder(); @@ -345,7 +341,7 @@ public class Utils { * @param c The type of the element to write the subsignature of. */ private static void writeTypeSignature(StringBuilder sb, Class c) { - String name = Utils.getTypeSignatureStringForClass(c); + String name = c.getCanonicalName().replaceAll("\\.", "/"); // Determine if this is an array type and, if so, peel away the array operators.. int len = name.length(); @@ -388,8 +384,7 @@ public class Utils { * @param aCClassName Name of the C++ class into which the method is declared. * @return The C++ method implementation signature for the method described. */ - public static String getCImplementationMethodSignature(Class[] aArgumentTypes, Class aReturnType, - String aCMethodName, String aCClassName, boolean aNarrowChars, boolean aCatchException) { + public static String getCImplementationMethodSignature(Class[] aArgumentTypes, Class aReturnType, String aCMethodName, String aCClassName, boolean aNarrowChars) { StringBuilder retBuffer = new StringBuilder(); retBuffer.append(getCReturnType(aReturnType, aNarrowChars)); @@ -411,14 +406,6 @@ public class Utils { retBuffer.append(", "); } } - - if (aCatchException) { - if (aArgumentTypes.length > 0) { - retBuffer.append(", "); - } - retBuffer.append("nsresult* aResult"); - } - retBuffer.append(')'); return retBuffer.toString(); } @@ -436,8 +423,7 @@ public class Utils { * @param aIsStaticStub true if the generated C++ method should be static, false otherwise. * @return The generated C++ header method signature for the method described. */ - public static String getCHeaderMethodSignature(Class[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class aReturnType, - String aCMethodName, String aCClassName, boolean aIsStaticStub, boolean aNarrowChars, boolean aCatchException) { + public static String getCHeaderMethodSignature(Class[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class aReturnType, String aCMethodName, String aCClassName, boolean aIsStaticStub, boolean aNarrowChars) { StringBuilder retBuffer = new StringBuilder(); // Add the static keyword, if applicable. @@ -467,14 +453,6 @@ public class Utils { retBuffer.append(", "); } } - - if (aCatchException) { - if (aArgumentTypes.length > 0) { - retBuffer.append(", "); - } - retBuffer.append("nsresult* aResult = nullptr"); - } - retBuffer.append(')'); return retBuffer.toString(); } @@ -609,9 +587,9 @@ public class Utils { StringBuilder sb = new StringBuilder(); sb.append(" "); sb.append(getClassReferenceName(aClass)); - sb.append(" = AndroidBridge::GetClassGlobalRef(env, \""); + sb.append(" = getClassGlobalRef(\""); - String name = Utils.getTypeSignatureStringForClass(aClass); + String name = aClass.getCanonicalName().replaceAll("\\.", "/"); Class containerClass = aClass.getDeclaringClass(); if (containerClass != null) { // Is an inner class. Add the $ symbol. diff --git a/config/recurse.mk b/config/recurse.mk index 5ef0b8c26fb8..e22dde964d84 100644 --- a/config/recurse.mk +++ b/config/recurse.mk @@ -141,7 +141,6 @@ ifeq (.,$(DEPTH)) # Interdependencies for parallel export. js/xpconnect/src/export: dom/bindings/export xpcom/xpidl/export accessible/xpcom/export: xpcom/xpidl/export -widget/android/bindings/export: build/annotationProcessors/export ifdef ENABLE_CLANG_PLUGIN $(filter-out build/clang-plugin/%,$(compile_targets)): build/clang-plugin/target build/clang-plugin/tests/target build/clang-plugin/tests/target: build/clang-plugin/target diff --git a/dom/media/fmp4/android/AndroidDecoderModule.cpp b/dom/media/fmp4/android/AndroidDecoderModule.cpp index 9f16fb20fb25..6067f5fd5922 100644 --- a/dom/media/fmp4/android/AndroidDecoderModule.cpp +++ b/dom/media/fmp4/android/AndroidDecoderModule.cpp @@ -3,7 +3,13 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "AndroidDecoderModule.h" +#include "PlatformDecoderModule.h" +#include "GeneratedJNIWrappers.h" +#include "GeneratedSDKWrappers.h" #include "AndroidBridge.h" +#include "MediaTaskQueue.h" +#include "SharedThreadPool.h" +#include "TexturePoolOGL.h" #include "GLImages.h" #include "MediaData.h" @@ -20,7 +26,7 @@ using namespace mozilla; using namespace mozilla::gl; -using namespace mozilla::widget::android::sdk; +using namespace mozilla::widget::android; namespace mozilla { @@ -30,7 +36,10 @@ static MediaCodec* CreateDecoder(JNIEnv* aEnv, const char* aMimeType) return nullptr; } - jobject decoder = MediaCodec::CreateDecoderByType(nsCString(aMimeType)); + nsAutoString mimeType; + mimeType.AssignASCII(aMimeType); + + jobject decoder = MediaCodec::CreateDecoderByType(mimeType); return new MediaCodec(decoder, aEnv); } @@ -94,7 +103,7 @@ public: protected: layers::ImageContainer* mImageContainer; const mp4_demuxer::VideoDecoderConfig& mConfig; - RefPtr mSurfaceTexture; + nsRefPtr mSurfaceTexture; }; class AudioDataDecoder : public MediaCodecDataDecoder { @@ -106,11 +115,11 @@ public: virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE { if (!strcmp(mMimeType, "audio/mp4a-latm")) { - uint32_t numChannels = mFormat->GetInteger(NS_LITERAL_CSTRING("channel-count")); - uint32_t sampleRate = mFormat->GetInteger(NS_LITERAL_CSTRING("sample-rate")); + uint32_t numChannels = mFormat->GetInteger(NS_LITERAL_STRING("channel-count")); + uint32_t sampleRate = mFormat->GetInteger(NS_LITERAL_STRING("sample-rate")); uint8_t frequencyIndex = mp4_demuxer::Adts::GetFrequencyIndex(sampleRate); - uint32_t aacProfile = mFormat->GetInteger(NS_LITERAL_CSTRING("aac-profile")); + uint32_t aacProfile = mFormat->GetInteger(NS_LITERAL_STRING("aac-profile")); bool rv = mp4_demuxer::Adts::ConvertSample(numChannels, frequencyIndex, aacProfile, @@ -126,8 +135,8 @@ public: nsresult Output(BufferInfo* aInfo, void* aBuffer, MediaFormat* aFormat, Microseconds aDuration) { // The output on Android is always 16-bit signed - uint32_t numChannels = aFormat->GetInteger(NS_LITERAL_CSTRING("channel-count")); - uint32_t sampleRate = aFormat->GetInteger(NS_LITERAL_CSTRING("sample-rate")); + uint32_t numChannels = aFormat->GetInteger(NS_LITERAL_STRING("channel-count")); + uint32_t sampleRate = aFormat->GetInteger(NS_LITERAL_STRING("sample-rate")); uint32_t numFrames = (aInfo->getSize() / numChannels) / 2; AudioDataValue* audio = new AudioDataValue[aInfo->getSize()]; @@ -160,7 +169,10 @@ AndroidDecoderModule::CreateH264Decoder( MediaTaskQueue* aVideoTaskQueue, MediaDataDecoderCallback* aCallback) { - jobject jFormat = MediaFormat::CreateVideoFormat(nsCString(aConfig.mime_type), + nsAutoString mimeType; + mimeType.AssignASCII(aConfig.mime_type); + + jobject jFormat = MediaFormat::CreateVideoFormat(mimeType, aConfig.display_width, aConfig.display_height); @@ -187,7 +199,10 @@ AndroidDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& { MOZ_ASSERT(aConfig.bits_per_sample == 16, "We only handle 16-bit audio!"); - jobject jFormat = MediaFormat::CreateAudioFormat(nsCString(aConfig.mime_type), + nsAutoString mimeType; + mimeType.AssignASCII(aConfig.mime_type); + + jobject jFormat = MediaFormat::CreateAudioFormat(mimeType, aConfig.samples_per_second, aConfig.channel_count); @@ -201,21 +216,21 @@ AndroidDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& JNIEnv* env = GetJNIForThread(); - if (!format->GetByteBuffer(NS_LITERAL_CSTRING("csd-0"))) { + if (!format->GetByteBuffer(NS_LITERAL_STRING("csd-0"))) { uint8_t* csd0 = new uint8_t[2]; csd0[0] = aConfig.audio_specific_config[0]; csd0[1] = aConfig.audio_specific_config[1]; jobject buffer = env->NewDirectByteBuffer(csd0, 2); - format->SetByteBuffer(NS_LITERAL_CSTRING("csd-0"), buffer); + format->SetByteBuffer(NS_LITERAL_STRING("csd-0"), buffer); env->DeleteLocalRef(buffer); } - if (strcmp(aConfig.mime_type, "audio/mp4a-latm") == 0) { - format->SetInteger(NS_LITERAL_CSTRING("is-adts"), 1); - format->SetInteger(NS_LITERAL_CSTRING("aac-profile"), aConfig.aac_profile); + if (mimeType.EqualsLiteral("audio/mp4a-latm")) { + format->SetInteger(NS_LITERAL_STRING("is-adts"), 1); + format->SetInteger(NS_LITERAL_STRING("aac-profile"), aConfig.aac_profile); } nsRefPtr decoder = @@ -279,26 +294,15 @@ nsresult MediaCodecDataDecoder::InitDecoder(jobject aSurface) return NS_ERROR_FAILURE; } - nsresult res; - mDecoder->Configure(mFormat->wrappedObject(), aSurface, nullptr, 0, &res); - if (NS_FAILED(res)) { - return res; + if (!mDecoder->Configure(mFormat->wrappedObject(), aSurface, nullptr, 0)) { + mCallback->Error(); + return NS_ERROR_FAILURE; } - mDecoder->Start(&res); - if (NS_FAILED(res)) { - return res; - } + mDecoder->Start(); - res = ResetInputBuffers(); - if (NS_FAILED(res)) { - return res; - } - - res = ResetOutputBuffers(); - if (NS_FAILED(res)) { - return res; - } + ResetInputBuffers(); + ResetOutputBuffers(); NS_NewNamedThread("MC Decoder", getter_AddRefs(mThread), NS_NewRunnableMethod(this, &MediaCodecDataDecoder::DecoderLoop)); @@ -317,7 +321,6 @@ void MediaCodecDataDecoder::DecoderLoop() mp4_demuxer::MP4Sample* sample = nullptr; nsAutoPtr outputFormat; - nsresult res; for (;;) { { @@ -351,13 +354,7 @@ void MediaCodecDataDecoder::DecoderLoop() if (sample) { // We have a sample, try to feed it to the decoder - int inputIndex = mDecoder->DequeueInputBuffer(DECODER_TIMEOUT, &res); - if (NS_FAILED(res)) { - printf_stderr("exiting decoder loop due to exception while dequeuing input\n"); - mCallback->Error(); - break; - } - + int inputIndex = mDecoder->DequeueInputBuffer(DECODER_TIMEOUT); if (inputIndex >= 0) { jobject buffer = env->GetObjectArrayElement(mInputBuffers, inputIndex); void* directBuffer = env->GetDirectBufferAddress(buffer); @@ -372,13 +369,7 @@ void MediaCodecDataDecoder::DecoderLoop() PodCopy((uint8_t*)directBuffer, sample->data, sample->size); - mDecoder->QueueInputBuffer(inputIndex, 0, sample->size, sample->composition_timestamp, 0, &res); - if (NS_FAILED(res)) { - printf_stderr("exiting decoder loop due to exception while queuing input\n"); - mCallback->Error(); - break; - } - + mDecoder->QueueInputBuffer(inputIndex, 0, sample->size, sample->composition_timestamp, 0); mDurations.push(sample->duration); delete sample; @@ -392,23 +383,12 @@ void MediaCodecDataDecoder::DecoderLoop() if (!outputDone) { BufferInfo bufferInfo; - int outputStatus = mDecoder->DequeueOutputBuffer(bufferInfo.wrappedObject(), DECODER_TIMEOUT, &res); - if (NS_FAILED(res)) { - printf_stderr("exiting decoder loop due to exception while dequeuing output\n"); - mCallback->Error(); - break; - } - + int outputStatus = mDecoder->DequeueOutputBuffer(bufferInfo.wrappedObject(), DECODER_TIMEOUT); if (outputStatus == MediaCodec::getINFO_TRY_AGAIN_LATER()) { // We might want to call mCallback->InputExhausted() here, but there seems to be // some possible bad interactions here with the threading } else if (outputStatus == MediaCodec::getINFO_OUTPUT_BUFFERS_CHANGED()) { - res = ResetOutputBuffers(); - if (NS_FAILED(res)) { - printf_stderr("exiting decoder loop due to exception while restting output buffers\n"); - mCallback->Error(); - break; - } + ResetOutputBuffers(); } else if (outputStatus == MediaCodec::getINFO_OUTPUT_FORMAT_CHANGED()) { outputFormat = new MediaFormat(mDecoder->GetOutputFormat(), GetJNIForThread()); } else if (outputStatus < 0) { @@ -474,7 +454,7 @@ nsresult MediaCodecDataDecoder::Input(mp4_demuxer::MP4Sample* aSample) { return NS_OK; } -nsresult MediaCodecDataDecoder::ResetInputBuffers() +void MediaCodecDataDecoder::ResetInputBuffers() { JNIEnv* env = GetJNIForThread(); @@ -482,16 +462,10 @@ nsresult MediaCodecDataDecoder::ResetInputBuffers() env->DeleteGlobalRef(mInputBuffers); } - nsresult res; - mInputBuffers = (jobjectArray) env->NewGlobalRef(mDecoder->GetInputBuffers(&res)); - if (NS_FAILED(res)) { - return res; - } - - return NS_OK; + mInputBuffers = (jobjectArray) env->NewGlobalRef(mDecoder->GetInputBuffers()); } -nsresult MediaCodecDataDecoder::ResetOutputBuffers() +void MediaCodecDataDecoder::ResetOutputBuffers() { JNIEnv* env = GetJNIForThread(); @@ -499,13 +473,7 @@ nsresult MediaCodecDataDecoder::ResetOutputBuffers() env->DeleteGlobalRef(mOutputBuffers); } - nsresult res; - mOutputBuffers = (jobjectArray) env->NewGlobalRef(mDecoder->GetOutputBuffers(&res)); - if (NS_FAILED(res)) { - return res; - } - - return NS_OK; + mOutputBuffers = (jobjectArray) env->NewGlobalRef(mDecoder->GetOutputBuffers()); } nsresult MediaCodecDataDecoder::Flush() { @@ -547,7 +515,6 @@ nsresult MediaCodecDataDecoder::Shutdown() { mDecoder->Stop(); mDecoder->Release(); - return NS_OK; } diff --git a/dom/media/fmp4/android/AndroidDecoderModule.h b/dom/media/fmp4/android/AndroidDecoderModule.h index 0ae43138e684..74beab3271a1 100644 --- a/dom/media/fmp4/android/AndroidDecoderModule.h +++ b/dom/media/fmp4/android/AndroidDecoderModule.h @@ -6,9 +6,10 @@ #define AndroidDecoderModule_h_ #include "PlatformDecoderModule.h" +#include "AndroidJavaWrappers.h" #include "AndroidSurfaceTexture.h" -#include "MediaCodec.h" +#include "GeneratedSDKWrappers.h" #include "mozilla/Monitor.h" #include @@ -19,13 +20,11 @@ typedef std::queue SampleQueue; namespace widget { namespace android { -namespace sdk { class MediaCodec; class MediaFormat; class ByteBuffer; } } -} class MediaCodecDataDecoder; @@ -57,7 +56,7 @@ public: MediaCodecDataDecoder(MediaData::Type aType, const char* aMimeType, - mozilla::widget::android::sdk::MediaFormat* aFormat, + mozilla::widget::android::MediaFormat* aFormat, MediaDataDecoderCallback* aCallback); virtual ~MediaCodecDataDecoder(); @@ -74,11 +73,11 @@ protected: MediaData::Type mType; nsAutoPtr mMimeType; - nsAutoPtr mFormat; + nsAutoPtr mFormat; MediaDataDecoderCallback* mCallback; - nsAutoPtr mDecoder; + nsAutoPtr mDecoder; jobjectArray mInputBuffers; jobjectArray mOutputBuffers; @@ -95,11 +94,11 @@ protected: virtual nsresult InitDecoder(jobject aSurface = nullptr); - virtual nsresult Output(mozilla::widget::android::sdk::BufferInfo* aInfo, void* aBuffer, mozilla::widget::android::sdk::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; } - virtual nsresult PostOutput(mozilla::widget::android::sdk::BufferInfo* aInfo, mozilla::widget::android::sdk::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; } + virtual nsresult Output(mozilla::widget::android::BufferInfo* aInfo, void* aBuffer, mozilla::widget::android::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; } + virtual nsresult PostOutput(mozilla::widget::android::BufferInfo* aInfo, mozilla::widget::android::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; } - nsresult ResetInputBuffers(); - nsresult ResetOutputBuffers(); + void ResetInputBuffers(); + void ResetOutputBuffers(); void DecoderLoop(); virtual void ClearQueue(); diff --git a/dom/plugins/base/nsNPAPIPluginInstance.cpp b/dom/plugins/base/nsNPAPIPluginInstance.cpp index c42f47e09b11..c2a85e8bf76e 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.cpp +++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp @@ -952,7 +952,7 @@ void nsNPAPIPluginInstance::ReleaseContentTexture(nsNPAPIPluginInstance::Texture mContentTexture->Release(aTextureInfo); } -TemporaryRef nsNPAPIPluginInstance::CreateSurfaceTexture() +AndroidSurfaceTexture* nsNPAPIPluginInstance::CreateSurfaceTexture() { if (!EnsureGLContext()) return nullptr; @@ -961,15 +961,14 @@ TemporaryRef nsNPAPIPluginInstance::CreateSurfaceTexture( if (!texture) return nullptr; - RefPtr surface = AndroidSurfaceTexture::Create(TexturePoolOGL::GetGLContext(), - texture); - if (!surface) { + AndroidSurfaceTexture* surface = AndroidSurfaceTexture::Create(TexturePoolOGL::GetGLContext(), + texture); + if (!surface) return nullptr; - } nsCOMPtr frameCallback = NS_NewRunnableMethod(this, &nsNPAPIPluginInstance::OnSurfaceTextureFrameAvailable); surface->SetFrameAvailableCallback(frameCallback); - return surface.forget(); + return surface; } void nsNPAPIPluginInstance::OnSurfaceTextureFrameAvailable() @@ -1010,10 +1009,9 @@ nsNPAPIPluginInstance::AsSurfaceTexture() void* nsNPAPIPluginInstance::AcquireVideoWindow() { - RefPtr surface = CreateSurfaceTexture(); - if (!surface) { + AndroidSurfaceTexture* surface = CreateSurfaceTexture(); + if (!surface) return nullptr; - } VideoInfo* info = new VideoInfo(surface); diff --git a/dom/plugins/base/nsNPAPIPluginInstance.h b/dom/plugins/base/nsNPAPIPluginInstance.h index 6454c627c3da..c3a35488bd66 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.h +++ b/dom/plugins/base/nsNPAPIPluginInstance.h @@ -207,7 +207,7 @@ public: mSurfaceTexture = nullptr; } - mozilla::RefPtr mSurfaceTexture; + nsRefPtr mSurfaceTexture; gfxRect mDimensions; }; @@ -328,8 +328,8 @@ protected: bool mFullScreen; bool mInverted; - mozilla::RefPtr mContentTexture; - mozilla::RefPtr mContentSurface; + nsRefPtr mContentTexture; + nsRefPtr mContentSurface; #endif enum { @@ -378,7 +378,7 @@ private: #ifdef MOZ_WIDGET_ANDROID void EnsureSharedTexture(); - mozilla::TemporaryRef CreateSurfaceTexture(); + mozilla::gl::AndroidSurfaceTexture* CreateSurfaceTexture(); std::map mVideos; bool mOnScreen; diff --git a/gfx/gl/AndroidSurfaceTexture.cpp b/gfx/gl/AndroidSurfaceTexture.cpp index 06783922fc8e..c5740c2b3d1a 100644 --- a/gfx/gl/AndroidSurfaceTexture.cpp +++ b/gfx/gl/AndroidSurfaceTexture.cpp @@ -15,12 +15,10 @@ #include "nsThreadUtils.h" #include "mozilla/gfx/Matrix.h" #include "GeneratedJNIWrappers.h" -#include "SurfaceTexture.h" #include "GLContext.h" using namespace mozilla; using namespace mozilla::widget::android; -using namespace mozilla::widget::android::sdk; namespace mozilla { namespace gl { @@ -41,26 +39,192 @@ IsSTSupported() return AndroidBridge::Bridge()->GetAPIVersion() >= 14; /* ICS */ } -TemporaryRef +static class JNIFunctions { +public: + + JNIFunctions() : mInitialized(false) + { + } + + bool EnsureInitialized() + { + if (mInitialized) { + return true; + } + + if (!IsSTSupported()) { + return false; + } + + JNIEnv* env = GetJNIForThread(); + + AutoLocalJNIFrame jniFrame(env); + + jSurfaceTextureClass = (jclass)env->NewGlobalRef(env->FindClass("android/graphics/SurfaceTexture")); + jSurfaceTexture_Ctor = env->GetMethodID(jSurfaceTextureClass, "", "(I)V"); + jSurfaceTexture_updateTexImage = env->GetMethodID(jSurfaceTextureClass, "updateTexImage", "()V"); + jSurfaceTexture_getTransformMatrix = env->GetMethodID(jSurfaceTextureClass, "getTransformMatrix", "([F)V"); + jSurfaceTexture_setDefaultBufferSize = env->GetMethodID(jSurfaceTextureClass, "setDefaultBufferSize", "(II)V"); + + if (IsDetachSupported()) { + jSurfaceTexture_attachToGLContext = env->GetMethodID(jSurfaceTextureClass, "attachToGLContext", "(I)V"); + jSurfaceTexture_detachFromGLContext = env->GetMethodID(jSurfaceTextureClass, "detachFromGLContext", "()V"); + } else { + jSurfaceTexture_attachToGLContext = jSurfaceTexture_detachFromGLContext = 0; + } + + jSurfaceClass = (jclass)env->NewGlobalRef(env->FindClass("android/view/Surface")); + jSurface_Ctor = env->GetMethodID(jSurfaceClass, "", "(Landroid/graphics/SurfaceTexture;)V"); + + mInitialized = true; + return true; + } + + jobject CreateSurfaceTexture(GLuint aTexture) + { + if (!EnsureInitialized()) + return nullptr; + + JNIEnv* env = GetJNIForThread(); + + AutoLocalJNIFrame jniFrame(env); + + return env->NewGlobalRef(env->NewObject(jSurfaceTextureClass, jSurfaceTexture_Ctor, (int) aTexture)); + } + + jobject CreateSurface(jobject aSurfaceTexture) + { + if (!EnsureInitialized()) + return nullptr; + + JNIEnv* env = GetJNIForThread(); + AutoLocalJNIFrame jniFrame(env); + return env->NewGlobalRef(env->NewObject(jSurfaceClass, jSurface_Ctor, aSurfaceTexture)); + } + + void ReleaseSurfaceTexture(jobject aSurfaceTexture) + { + JNIEnv* env = GetJNIForThread(); + + env->DeleteGlobalRef(aSurfaceTexture); + } + + void UpdateTexImage(jobject aSurfaceTexture) + { + JNIEnv* env = GetJNIForThread(); + + AutoLocalJNIFrame jniFrame(env); + env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_updateTexImage); + } + + bool GetTransformMatrix(jobject aSurfaceTexture, gfx::Matrix4x4& aMatrix) + { + JNIEnv* env = GetJNIForThread(); + + AutoLocalJNIFrame jniFrame(env); + + jfloatArray jarray = env->NewFloatArray(16); + env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_getTransformMatrix, jarray); + + jfloat* array = env->GetFloatArrayElements(jarray, nullptr); + + aMatrix._11 = array[0]; + aMatrix._12 = array[1]; + aMatrix._13 = array[2]; + aMatrix._14 = array[3]; + + aMatrix._21 = array[4]; + aMatrix._22 = array[5]; + aMatrix._23 = array[6]; + aMatrix._24 = array[7]; + + aMatrix._31 = array[8]; + aMatrix._32 = array[9]; + aMatrix._33 = array[10]; + aMatrix._34 = array[11]; + + aMatrix._41 = array[12]; + aMatrix._42 = array[13]; + aMatrix._43 = array[14]; + aMatrix._44 = array[15]; + + env->ReleaseFloatArrayElements(jarray, array, 0); + + return false; + } + + void SetDefaultBufferSize(jobject aSurfaceTexture, int32_t width, int32_t height) + { + JNIEnv* env = GetJNIForThread(); + + AutoLocalJNIFrame jniFrame(env); + env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_setDefaultBufferSize, width, height); + } + + void AttachToGLContext(jobject aSurfaceTexture, int32_t texName) + { + MOZ_ASSERT(jSurfaceTexture_attachToGLContext); + + JNIEnv* env = GetJNIForThread(); + + env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_attachToGLContext, texName); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + } + + void DetachFromGLContext(jobject aSurfaceTexture) + { + MOZ_ASSERT(jSurfaceTexture_detachFromGLContext); + + JNIEnv* env = GetJNIForThread(); + + env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_detachFromGLContext); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + } + +private: + bool mInitialized; + + jclass jSurfaceTextureClass; + jmethodID jSurfaceTexture_Ctor; + jmethodID jSurfaceTexture_updateTexImage; + jmethodID jSurfaceTexture_getTransformMatrix; + jmethodID jSurfaceTexture_setDefaultBufferSize; + + jmethodID jSurfaceTexture_attachToGLContext; + jmethodID jSurfaceTexture_detachFromGLContext; + + jclass jSurfaceClass; + jmethodID jSurface_Ctor; + +} sJNIFunctions; + +AndroidSurfaceTexture* AndroidSurfaceTexture::Create() { return Create(nullptr, 0); } -TemporaryRef +AndroidSurfaceTexture* AndroidSurfaceTexture::Create(GLContext* aContext, GLuint aTexture) { if (!IsSTSupported()) { return nullptr; } - RefPtr st = new AndroidSurfaceTexture(); + AndroidSurfaceTexture* st = new AndroidSurfaceTexture(); if (!st->Init(aContext, aTexture)) { printf_stderr("Failed to initialize AndroidSurfaceTexture"); + delete st; st = nullptr; } - return st.forget(); + return st; } AndroidSurfaceTexture* @@ -75,25 +239,30 @@ AndroidSurfaceTexture::Find(int id) return it->second; } +bool +AndroidSurfaceTexture::Check() +{ + return sJNIFunctions.EnsureInitialized(); +} -nsresult +bool AndroidSurfaceTexture::Attach(GLContext* aContext, PRIntervalTime aTimeout) { MonitorAutoLock lock(mMonitor); if (mAttachedContext == aContext) { NS_WARNING("Tried to attach same GLContext to AndroidSurfaceTexture"); - return NS_OK; + return true; } if (!IsDetachSupported()) { - return NS_ERROR_NOT_AVAILABLE; + return false; } while (mAttachedContext) { // Wait until it's detached (or we time out) if (NS_FAILED(lock.Wait(aTimeout))) { - return NS_ERROR_NOT_AVAILABLE; + return false; } } @@ -103,29 +272,29 @@ AndroidSurfaceTexture::Attach(GLContext* aContext, PRIntervalTime aTimeout) mAttachedContext->MakeCurrent(); aContext->fGenTextures(1, &mTexture); - nsresult res; - mSurfaceTexture->AttachToGLContext(mTexture, &res); - return res; + sJNIFunctions.AttachToGLContext(mSurfaceTexture, mTexture); + return true; } -nsresult +bool AndroidSurfaceTexture::Detach() { MonitorAutoLock lock(mMonitor); if (!IsDetachSupported() || !mAttachedContext || !mAttachedContext->IsOwningThreadCurrent()) { - return NS_ERROR_FAILURE; + return false; } mAttachedContext->MakeCurrent(); - mSurfaceTexture->DetachFromGLContext(); + // This call takes care of deleting the texture + sJNIFunctions.DetachFromGLContext(mSurfaceTexture); mTexture = 0; mAttachedContext = nullptr; lock.NotifyAll(); - return NS_OK; + return true; } bool @@ -136,26 +305,28 @@ AndroidSurfaceTexture::Init(GLContext* aContext, GLuint aTexture) return false; } - nsresult res; - mSurfaceTexture = new SurfaceTexture(aTexture, &res); - if (NS_FAILED(res)) { + if (!sJNIFunctions.EnsureInitialized()) + return false; + + JNIEnv* env = GetJNIForThread(); + + mSurfaceTexture = sJNIFunctions.CreateSurfaceTexture(aTexture); + if (!mSurfaceTexture) { return false; } if (!aTexture) { - mSurfaceTexture->DetachFromGLContext(); + sJNIFunctions.DetachFromGLContext(mSurfaceTexture); } mAttachedContext = aContext; - mSurface = new Surface(mSurfaceTexture->wrappedObject(), &res); - if (NS_FAILED(res)) { + mSurface = sJNIFunctions.CreateSurface(mSurfaceTexture); + if (!mSurface) { return false; } - mNativeWindow = AndroidNativeWindow::CreateFromSurface(GetJNIForThread(), - mSurface->wrappedObject()); - MOZ_ASSERT(mNativeWindow, "Failed to create native window from surface"); + mNativeWindow = AndroidNativeWindow::CreateFromSurface(env, mSurface); mID = ++sNextID; sInstances.insert(std::pair(mID, this)); @@ -178,60 +349,40 @@ AndroidSurfaceTexture::~AndroidSurfaceTexture() mFrameAvailableCallback = nullptr; + JNIEnv* env = GetJNIForThread(); + if (mSurfaceTexture) { - GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture->wrappedObject()); + GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture); + + env->DeleteGlobalRef(mSurfaceTexture); mSurfaceTexture = nullptr; } + + if (mSurface) { + env->DeleteGlobalRef(mSurface); + mSurface = nullptr; + } } void AndroidSurfaceTexture::UpdateTexImage() { - mSurfaceTexture->UpdateTexImage(); + sJNIFunctions.UpdateTexImage(mSurfaceTexture); } -void +bool AndroidSurfaceTexture::GetTransformMatrix(gfx::Matrix4x4& aMatrix) { - JNIEnv* env = GetJNIForThread(); - - AutoLocalJNIFrame jniFrame(env); - - jfloatArray jarray = env->NewFloatArray(16); - mSurfaceTexture->GetTransformMatrix(jarray); - - jfloat* array = env->GetFloatArrayElements(jarray, nullptr); - - aMatrix._11 = array[0]; - aMatrix._12 = array[1]; - aMatrix._13 = array[2]; - aMatrix._14 = array[3]; - - aMatrix._21 = array[4]; - aMatrix._22 = array[5]; - aMatrix._23 = array[6]; - aMatrix._24 = array[7]; - - aMatrix._31 = array[8]; - aMatrix._32 = array[9]; - aMatrix._33 = array[10]; - aMatrix._34 = array[11]; - - aMatrix._41 = array[12]; - aMatrix._42 = array[13]; - aMatrix._43 = array[14]; - aMatrix._44 = array[15]; - - env->ReleaseFloatArrayElements(jarray, array, 0); + return sJNIFunctions.GetTransformMatrix(mSurfaceTexture, aMatrix); } void AndroidSurfaceTexture::SetFrameAvailableCallback(nsIRunnable* aRunnable) { if (aRunnable) { - GeckoAppShell::RegisterSurfaceTextureFrameListener(mSurfaceTexture->wrappedObject(), mID); + GeckoAppShell::RegisterSurfaceTextureFrameListener(mSurfaceTexture, mID); } else { - GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture->wrappedObject()); + GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture); } mFrameAvailableCallback = aRunnable; @@ -240,7 +391,7 @@ AndroidSurfaceTexture::SetFrameAvailableCallback(nsIRunnable* aRunnable) void AndroidSurfaceTexture::SetDefaultSize(mozilla::gfx::IntSize size) { - mSurfaceTexture->SetDefaultBufferSize(size.width, size.height); + sJNIFunctions.SetDefaultBufferSize(mSurfaceTexture, size.width, size.height); } void diff --git a/gfx/gl/AndroidSurfaceTexture.h b/gfx/gl/AndroidSurfaceTexture.h index 5f601bcc7424..76fe8227cce5 100644 --- a/gfx/gl/AndroidSurfaceTexture.h +++ b/gfx/gl/AndroidSurfaceTexture.h @@ -15,7 +15,6 @@ #include "mozilla/gfx/2D.h" #include "mozilla/Monitor.h" -#include "SurfaceTexture.h" #include "AndroidNativeWindow.h" class gfxASurface; @@ -43,26 +42,30 @@ public: // The SurfaceTexture is created in an attached state. This method requires // Android Ice Cream Sandwich. - static TemporaryRef Create(GLContext* aGLContext, GLuint aTexture); + static AndroidSurfaceTexture* Create(GLContext* aGLContext, GLuint aTexture); // Here the SurfaceTexture will be created in a detached state. You must call // Attach() with the GLContext you wish to composite with. It must be done // on the thread where that GLContext is current. This method requires // Android Jelly Bean. - static TemporaryRef Create(); + static AndroidSurfaceTexture* Create(); static AndroidSurfaceTexture* Find(int id); + // Returns with reasonable certainty whether or not we'll + // be able to create and use a SurfaceTexture + static bool Check(); + // If we are on Jelly Bean, the SurfaceTexture can be detached and reattached // to allow consumption from different GLContexts. It is recommended to only // attach while you are consuming in order to allow this. // // Only one GLContext may be attached at any given time. If another is already // attached, we try to wait for it to become detached. - nsresult Attach(GLContext* aContext, PRIntervalTime aTiemout = PR_INTERVAL_NO_TIMEOUT); + bool Attach(GLContext* aContext, PRIntervalTime aTiemout = PR_INTERVAL_NO_TIMEOUT); // This is a noop on ICS, and will always fail - nsresult Detach(); + bool Detach(); GLContext* GetAttachedContext() { return mAttachedContext; } @@ -73,7 +76,7 @@ public: // This attaches the updated data to the TEXTURE_EXTERNAL target void UpdateTexImage(); - void GetTransformMatrix(mozilla::gfx::Matrix4x4& aMatrix); + bool GetTransformMatrix(mozilla::gfx::Matrix4x4& aMatrix); int ID() { return mID; } void SetDefaultSize(mozilla::gfx::IntSize size); @@ -87,7 +90,7 @@ public: void NotifyFrameAvailable(); GLuint Texture() { return mTexture; } - jobject JavaSurface() { return mSurface->wrappedObject(); } + jobject JavaSurface() { return mSurface; } private: AndroidSurfaceTexture(); ~AndroidSurfaceTexture(); @@ -95,8 +98,8 @@ private: bool Init(GLContext* aContext, GLuint aTexture); GLuint mTexture; - nsAutoPtr mSurfaceTexture; - nsAutoPtr mSurface; + jobject mSurfaceTexture; + jobject mSurface; Monitor mMonitor; GLContext* mAttachedContext; diff --git a/gfx/gl/GLBlitHelper.cpp b/gfx/gl/GLBlitHelper.cpp index fa44819869ad..7e47f0b2d75e 100644 --- a/gfx/gl/GLBlitHelper.cpp +++ b/gfx/gl/GLBlitHelper.cpp @@ -728,7 +728,7 @@ GLBlitHelper::BlitSurfaceTextureImage(layers::SurfaceTextureImage* stImage) ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0); mGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT); - if (NS_FAILED(surfaceTexture->Attach(mGL))) { + if (!surfaceTexture->Attach(mGL)) { return false; } diff --git a/gfx/layers/opengl/TextureHostOGL.cpp b/gfx/layers/opengl/TextureHostOGL.cpp index 6f45c849580f..5540d5c8d804 100644 --- a/gfx/layers/opengl/TextureHostOGL.cpp +++ b/gfx/layers/opengl/TextureHostOGL.cpp @@ -534,7 +534,9 @@ SurfaceTextureHost::Lock() mSize); } - return NS_SUCCEEDED(mSurfTex->Attach(gl())); + mSurfTex->Attach(gl()); + + return true; } void diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index ffb2e1ece226..27e1fde336ad 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -419,13 +419,6 @@ gradle-targets: .aapt.deps .PHONY: gradle-targets -update-generated-wrappers: - mv $(topsrcdir)/widget/android/GeneratedJNIWrappers.cpp $(topsrcdir)/widget/android/GeneratedJNIWrappers.cpp.old - mv $(topsrcdir)/widget/android/GeneratedJNIWrappers.h $(topsrcdir)/widget/android/GeneratedJNIWrappers.h.old - @cp $(CURDIR)/jni-stubs.inc $(topsrcdir)/mozglue/android - @cp $(CURDIR)/GeneratedJNIWrappers.* $(topsrcdir)/widget/android - @echo Updated GeneratedJNIWrappers - libs:: geckoview_resources.zip classes.dex jni-stubs.inc GeneratedJNIWrappers.cpp fennec_ids.txt $(INSTALL) geckoview_resources.zip $(FINAL_TARGET) $(INSTALL) classes.dex $(FINAL_TARGET) @@ -434,7 +427,7 @@ libs:: geckoview_resources.zip classes.dex jni-stubs.inc GeneratedJNIWrappers.cp echo '*** Error: The generated JNI code has changed ***' && \ echo '* To update generated code in the tree, please run *' && \ echo && \ - echo ' make -C $(CURDIR) update-generated-wrappers' && \ + echo ' cp $(CURDIR)/jni-stubs.inc $(topsrcdir)/mozglue/android && cp $(CURDIR)/GeneratedJNIWrappers.* $(topsrcdir)/widget/android' && \ echo && \ echo '* Repeat the build, and check in any changes. *' && \ echo '*****************************************************' && \ diff --git a/mobile/android/base/mozglue/generatorannotations/WrapElementForJNI.java b/mobile/android/base/mozglue/generatorannotations/WrapElementForJNI.java index a73d2d91b35f..3036ecbf4954 100644 --- a/mobile/android/base/mozglue/generatorannotations/WrapElementForJNI.java +++ b/mobile/android/base/mozglue/generatorannotations/WrapElementForJNI.java @@ -44,14 +44,5 @@ public @interface WrapElementForJNI { */ boolean noThrow() default false; - /** - * If set, uses UTF-8 strings - */ boolean narrowChars() default false; - - /** - * If set, the generated stub will catch any exception thrown and - * set a passed-in nsresult to NS_ERROR_FAILURE - */ - boolean catchException() default false; } diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp index 6c46e3c36ae1..d713b5db7f1f 100644 --- a/widget/android/AndroidBridge.cpp +++ b/widget/android/AndroidBridge.cpp @@ -41,9 +41,7 @@ #include "nsContentUtils.h" #include "nsIScriptError.h" #include "nsIHttpChannel.h" - -#include "MediaCodec.h" -#include "SurfaceTexture.h" +#include "GeneratedSDKWrappers.h" using namespace mozilla; using namespace mozilla::widget::android; @@ -224,11 +222,8 @@ AndroidBridge::Init(JNIEnv *jEnv) InitAndroidJavaWrappers(jEnv); if (mAPIVersion >= 16 /* Jelly Bean */) { - sdk::InitMediaCodecStubs(jEnv); - } - - if (mAPIVersion >= 14 /* ICS */) { - sdk::InitSurfaceTextureStubs(jEnv); + // We only use this for MediaCodec right now + InitSDKStubs(jEnv); } // jEnv should NOT be cached here by anything -- the jEnv here diff --git a/widget/android/AndroidJavaWrappers.cpp b/widget/android/AndroidJavaWrappers.cpp index b22e9f07a4ca..3a3ad60b56f9 100644 --- a/widget/android/AndroidJavaWrappers.cpp +++ b/widget/android/AndroidJavaWrappers.cpp @@ -11,6 +11,7 @@ #include "mozilla/BasicEvents.h" #include "mozilla/TimeStamp.h" #include "mozilla/TouchEvents.h" +#include "GeneratedSDKWrappers.h" using namespace mozilla; using namespace mozilla::dom; diff --git a/widget/android/GeneratedJNIWrappers.cpp b/widget/android/GeneratedJNIWrappers.cpp index e8aed3f5a092..304849b91b72 100644 --- a/widget/android/GeneratedJNIWrappers.cpp +++ b/widget/android/GeneratedJNIWrappers.cpp @@ -13,9 +13,11 @@ namespace widget { namespace android { jclass DownloadsIntegration::mDownloadsIntegrationClass = 0; jmethodID DownloadsIntegration::jScanMedia = 0; -void DownloadsIntegration::InitStubs(JNIEnv *env) { - mDownloadsIntegrationClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/DownloadsIntegration"); - jScanMedia = AndroidBridge::GetStaticMethodID(env, mDownloadsIntegrationClass, "scanMedia", "(Ljava/lang/String;Ljava/lang/String;)V"); +void DownloadsIntegration::InitStubs(JNIEnv *jEnv) { + initInit(); + + mDownloadsIntegrationClass = getClassGlobalRef("org/mozilla/gecko/DownloadsIntegration"); + jScanMedia = getStaticMethod("scanMedia", "(Ljava/lang/String;Ljava/lang/String;)V"); } DownloadsIntegration* DownloadsIntegration::Wrap(jobject obj) { @@ -122,90 +124,92 @@ jmethodID GeckoAppShell::jUnlockScreenOrientation = 0; jmethodID GeckoAppShell::jUnregisterSurfaceTextureFrameListener = 0; jmethodID GeckoAppShell::jVibrate1 = 0; jmethodID GeckoAppShell::jVibrateA = 0; -void GeckoAppShell::InitStubs(JNIEnv *env) { - mGeckoAppShellClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/GeckoAppShell"); - jAcknowledgeEvent = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "acknowledgeEvent", "()V"); - jAddPluginViewWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "addPluginView", "(Landroid/view/View;FFFFZ)V"); - jAlertsProgressListener_OnProgress = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "alertsProgressListener_OnProgress", "(Ljava/lang/String;JJLjava/lang/String;)V"); - jCancelVibrate = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "cancelVibrate", "()V"); - jCheckURIVisited = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "checkUriVisited", "(Ljava/lang/String;)V"); - jClearMessageList = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "clearMessageList", "(I)V"); - jCloseCamera = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "closeCamera", "()V"); - jCloseNotification = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "closeNotification", "(Ljava/lang/String;)V"); - jConnectionGetMimeType = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "connectionGetMimeType", "(Ljava/net/URLConnection;)Ljava/lang/String;"); - jCreateInputStream = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "createInputStream", "(Ljava/net/URLConnection;)Ljava/io/InputStream;"); - jCreateMessageListWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "createMessageList", "(JJ[Ljava/lang/String;ILjava/lang/String;ZZJZI)V"); - jCreateShortcut = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "createShortcut", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); - jDeleteMessageWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "deleteMessage", "(II)V"); - jDisableBatteryNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "disableBatteryNotifications", "()V"); - jDisableNetworkNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "disableNetworkNotifications", "()V"); - jDisableScreenOrientationNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "disableScreenOrientationNotifications", "()V"); - jDisableSensor = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "disableSensor", "(I)V"); - jEnableBatteryNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableBatteryNotifications", "()V"); - jEnableLocation = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableLocation", "(Z)V"); - jEnableLocationHighAccuracy = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableLocationHighAccuracy", "(Z)V"); - jEnableNetworkNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableNetworkNotifications", "()V"); - jEnableScreenOrientationNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableScreenOrientationNotifications", "()V"); - jEnableSensor = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableSensor", "(I)V"); - jGamepadAdded = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "gamepadAdded", "(II)V"); - jGetConnection = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getConnection", "(Ljava/lang/String;)Ljava/net/URLConnection;"); - jGetContext = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getContext", "()Landroid/content/Context;"); - jGetCurrentBatteryInformationWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getCurrentBatteryInformation", "()[D"); - jGetCurrentNetworkInformationWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getCurrentNetworkInformation", "()[D"); - jGetDensity = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getDensity", "()F"); - jGetDpiWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getDpi", "()I"); - jGetExtensionFromMimeTypeWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getExtensionFromMimeType", "(Ljava/lang/String;)Ljava/lang/String;"); - jGetExternalPublicDirectory = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getExternalPublicDirectory", "(Ljava/lang/String;)Ljava/lang/String;"); - jGetHandlersForMimeTypeWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getHandlersForMimeType", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"); - jGetHandlersForURLWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getHandlersForURL", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"); - jGetIconForExtensionWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getIconForExtension", "(Ljava/lang/String;I)[B"); - jGetMessageWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getMessage", "(II)V"); - jGetMimeTypeFromExtensionsWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getMimeTypeFromExtensions", "(Ljava/lang/String;)Ljava/lang/String;"); - jGetNextMessageInListWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getNextMessageInList", "(II)V"); - jGetProxyForURIWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getProxyForURI", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;"); - jGetScreenDepthWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getScreenDepth", "()I"); - jGetScreenOrientationWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getScreenOrientation", "()S"); - jGetShowPasswordSetting = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getShowPasswordSetting", "()Z"); - jGetSystemColoursWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getSystemColors", "()[I"); - jHandleGeckoMessageWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "handleGeckoMessage", "(Lorg/mozilla/gecko/util/NativeJSContainer;)V"); - jHandleUncaughtException = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "handleUncaughtException", "(Ljava/lang/Thread;Ljava/lang/Throwable;)V"); - jHideProgressDialog = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "hideProgressDialog", "()V"); - jInitCameraWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "initCamera", "(Ljava/lang/String;III)[I"); - jIsNetworkLinkKnown = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "isNetworkLinkKnown", "()Z"); - jIsNetworkLinkUp = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "isNetworkLinkUp", "()Z"); - jIsTablet = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "isTablet", "()Z"); - jKillAnyZombies = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "killAnyZombies", "()V"); - jLoadPluginClass = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "loadPluginClass", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;"); - jLockScreenOrientation = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "lockScreenOrientation", "(I)V"); - jMarkURIVisited = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "markUriVisited", "(Ljava/lang/String;)V"); - jMoveTaskToBack = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "moveTaskToBack", "()V"); - jNetworkLinkType = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "networkLinkType", "()I"); - jNotifyDefaultPrevented = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyDefaultPrevented", "(Z)V"); - jNotifyIME = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyIME", "(I)V"); - jNotifyIMEChange = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyIMEChange", "(Ljava/lang/String;III)V"); - jNotifyIMEContext = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyIMEContext", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); - jNotifyWakeLockChanged = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyWakeLockChanged", "(Ljava/lang/String;Ljava/lang/String;)V"); - jNotifyXreExit = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "onXreExit", "()V"); - jOpenUriExternal = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "openUriExternal", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z"); - jPerformHapticFeedback = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "performHapticFeedback", "(Z)V"); - jPumpMessageLoop = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "pumpMessageLoop", "()Z"); - jRegisterSurfaceTextureFrameListener = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "registerSurfaceTextureFrameListener", "(Ljava/lang/Object;I)V"); - jRemovePluginView = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "removePluginView", "(Landroid/view/View;Z)V"); - jRequestUiThreadCallback = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "requestUiThreadCallback", "(J)V"); - jScheduleRestart = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "scheduleRestart", "()V"); - jSendMessageWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "sendMessage", "(Ljava/lang/String;Ljava/lang/String;I)V"); - jSetFullScreen = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "setFullScreen", "(Z)V"); - jSetKeepScreenOn = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "setKeepScreenOn", "(Z)V"); - jSetURITitle = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "setUriTitle", "(Ljava/lang/String;Ljava/lang/String;)V"); - jShowAlertNotificationWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "showAlertNotification", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); - jShowInputMethodPicker = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "showInputMethodPicker", "()V"); - jStartMonitoringGamepad = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "startMonitoringGamepad", "()V"); - jStopMonitoringGamepad = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "stopMonitoringGamepad", "()V"); - jUnlockProfile = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "unlockProfile", "()Z"); - jUnlockScreenOrientation = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "unlockScreenOrientation", "()V"); - jUnregisterSurfaceTextureFrameListener = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "unregisterSurfaceTextureFrameListener", "(Ljava/lang/Object;)V"); - jVibrate1 = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "vibrate", "(J)V"); - jVibrateA = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "vibrate", "([JI)V"); +void GeckoAppShell::InitStubs(JNIEnv *jEnv) { + initInit(); + + mGeckoAppShellClass = getClassGlobalRef("org/mozilla/gecko/GeckoAppShell"); + jAcknowledgeEvent = getStaticMethod("acknowledgeEvent", "()V"); + jAddPluginViewWrapper = getStaticMethod("addPluginView", "(Landroid/view/View;FFFFZ)V"); + jAlertsProgressListener_OnProgress = getStaticMethod("alertsProgressListener_OnProgress", "(Ljava/lang/String;JJLjava/lang/String;)V"); + jCancelVibrate = getStaticMethod("cancelVibrate", "()V"); + jCheckURIVisited = getStaticMethod("checkUriVisited", "(Ljava/lang/String;)V"); + jClearMessageList = getStaticMethod("clearMessageList", "(I)V"); + jCloseCamera = getStaticMethod("closeCamera", "()V"); + jCloseNotification = getStaticMethod("closeNotification", "(Ljava/lang/String;)V"); + jConnectionGetMimeType = getStaticMethod("connectionGetMimeType", "(Ljava/net/URLConnection;)Ljava/lang/String;"); + jCreateInputStream = getStaticMethod("createInputStream", "(Ljava/net/URLConnection;)Ljava/io/InputStream;"); + jCreateMessageListWrapper = getStaticMethod("createMessageList", "(JJ[Ljava/lang/String;ILjava/lang/String;ZZJZI)V"); + jCreateShortcut = getStaticMethod("createShortcut", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + jDeleteMessageWrapper = getStaticMethod("deleteMessage", "(II)V"); + jDisableBatteryNotifications = getStaticMethod("disableBatteryNotifications", "()V"); + jDisableNetworkNotifications = getStaticMethod("disableNetworkNotifications", "()V"); + jDisableScreenOrientationNotifications = getStaticMethod("disableScreenOrientationNotifications", "()V"); + jDisableSensor = getStaticMethod("disableSensor", "(I)V"); + jEnableBatteryNotifications = getStaticMethod("enableBatteryNotifications", "()V"); + jEnableLocation = getStaticMethod("enableLocation", "(Z)V"); + jEnableLocationHighAccuracy = getStaticMethod("enableLocationHighAccuracy", "(Z)V"); + jEnableNetworkNotifications = getStaticMethod("enableNetworkNotifications", "()V"); + jEnableScreenOrientationNotifications = getStaticMethod("enableScreenOrientationNotifications", "()V"); + jEnableSensor = getStaticMethod("enableSensor", "(I)V"); + jGamepadAdded = getStaticMethod("gamepadAdded", "(II)V"); + jGetConnection = getStaticMethod("getConnection", "(Ljava/lang/String;)Ljava/net/URLConnection;"); + jGetContext = getStaticMethod("getContext", "()Landroid/content/Context;"); + jGetCurrentBatteryInformationWrapper = getStaticMethod("getCurrentBatteryInformation", "()[D"); + jGetCurrentNetworkInformationWrapper = getStaticMethod("getCurrentNetworkInformation", "()[D"); + jGetDensity = getStaticMethod("getDensity", "()F"); + jGetDpiWrapper = getStaticMethod("getDpi", "()I"); + jGetExtensionFromMimeTypeWrapper = getStaticMethod("getExtensionFromMimeType", "(Ljava/lang/String;)Ljava/lang/String;"); + jGetExternalPublicDirectory = getStaticMethod("getExternalPublicDirectory", "(Ljava/lang/String;)Ljava/lang/String;"); + jGetHandlersForMimeTypeWrapper = getStaticMethod("getHandlersForMimeType", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"); + jGetHandlersForURLWrapper = getStaticMethod("getHandlersForURL", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"); + jGetIconForExtensionWrapper = getStaticMethod("getIconForExtension", "(Ljava/lang/String;I)[B"); + jGetMessageWrapper = getStaticMethod("getMessage", "(II)V"); + jGetMimeTypeFromExtensionsWrapper = getStaticMethod("getMimeTypeFromExtensions", "(Ljava/lang/String;)Ljava/lang/String;"); + jGetNextMessageInListWrapper = getStaticMethod("getNextMessageInList", "(II)V"); + jGetProxyForURIWrapper = getStaticMethod("getProxyForURI", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;"); + jGetScreenDepthWrapper = getStaticMethod("getScreenDepth", "()I"); + jGetScreenOrientationWrapper = getStaticMethod("getScreenOrientation", "()S"); + jGetShowPasswordSetting = getStaticMethod("getShowPasswordSetting", "()Z"); + jGetSystemColoursWrapper = getStaticMethod("getSystemColors", "()[I"); + jHandleGeckoMessageWrapper = getStaticMethod("handleGeckoMessage", "(Lorg/mozilla/gecko/util/NativeJSContainer;)V"); + jHandleUncaughtException = getStaticMethod("handleUncaughtException", "(Ljava/lang/Thread;Ljava/lang/Throwable;)V"); + jHideProgressDialog = getStaticMethod("hideProgressDialog", "()V"); + jInitCameraWrapper = getStaticMethod("initCamera", "(Ljava/lang/String;III)[I"); + jIsNetworkLinkKnown = getStaticMethod("isNetworkLinkKnown", "()Z"); + jIsNetworkLinkUp = getStaticMethod("isNetworkLinkUp", "()Z"); + jIsTablet = getStaticMethod("isTablet", "()Z"); + jKillAnyZombies = getStaticMethod("killAnyZombies", "()V"); + jLoadPluginClass = getStaticMethod("loadPluginClass", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;"); + jLockScreenOrientation = getStaticMethod("lockScreenOrientation", "(I)V"); + jMarkURIVisited = getStaticMethod("markUriVisited", "(Ljava/lang/String;)V"); + jMoveTaskToBack = getStaticMethod("moveTaskToBack", "()V"); + jNetworkLinkType = getStaticMethod("networkLinkType", "()I"); + jNotifyDefaultPrevented = getStaticMethod("notifyDefaultPrevented", "(Z)V"); + jNotifyIME = getStaticMethod("notifyIME", "(I)V"); + jNotifyIMEChange = getStaticMethod("notifyIMEChange", "(Ljava/lang/String;III)V"); + jNotifyIMEContext = getStaticMethod("notifyIMEContext", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + jNotifyWakeLockChanged = getStaticMethod("notifyWakeLockChanged", "(Ljava/lang/String;Ljava/lang/String;)V"); + jNotifyXreExit = getStaticMethod("onXreExit", "()V"); + jOpenUriExternal = getStaticMethod("openUriExternal", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z"); + jPerformHapticFeedback = getStaticMethod("performHapticFeedback", "(Z)V"); + jPumpMessageLoop = getStaticMethod("pumpMessageLoop", "()Z"); + jRegisterSurfaceTextureFrameListener = getStaticMethod("registerSurfaceTextureFrameListener", "(Ljava/lang/Object;I)V"); + jRemovePluginView = getStaticMethod("removePluginView", "(Landroid/view/View;Z)V"); + jRequestUiThreadCallback = getStaticMethod("requestUiThreadCallback", "(J)V"); + jScheduleRestart = getStaticMethod("scheduleRestart", "()V"); + jSendMessageWrapper = getStaticMethod("sendMessage", "(Ljava/lang/String;Ljava/lang/String;I)V"); + jSetFullScreen = getStaticMethod("setFullScreen", "(Z)V"); + jSetKeepScreenOn = getStaticMethod("setKeepScreenOn", "(Z)V"); + jSetURITitle = getStaticMethod("setUriTitle", "(Ljava/lang/String;Ljava/lang/String;)V"); + jShowAlertNotificationWrapper = getStaticMethod("showAlertNotification", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + jShowInputMethodPicker = getStaticMethod("showInputMethodPicker", "()V"); + jStartMonitoringGamepad = getStaticMethod("startMonitoringGamepad", "()V"); + jStopMonitoringGamepad = getStaticMethod("stopMonitoringGamepad", "()V"); + jUnlockProfile = getStaticMethod("unlockProfile", "()Z"); + jUnlockScreenOrientation = getStaticMethod("unlockScreenOrientation", "()V"); + jUnregisterSurfaceTextureFrameListener = getStaticMethod("unregisterSurfaceTextureFrameListener", "(Ljava/lang/Object;)V"); + jVibrate1 = getStaticMethod("vibrate", "(J)V"); + jVibrateA = getStaticMethod("vibrate", "([JI)V"); } GeckoAppShell* GeckoAppShell::Wrap(jobject obj) { @@ -1338,15 +1342,17 @@ jmethodID GeckoJavaSampler::jPauseJavaProfiling = 0; jmethodID GeckoJavaSampler::jStartJavaProfiling = 0; jmethodID GeckoJavaSampler::jStopJavaProfiling = 0; jmethodID GeckoJavaSampler::jUnpauseJavaProfiling = 0; -void GeckoJavaSampler::InitStubs(JNIEnv *env) { - mGeckoJavaSamplerClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/GeckoJavaSampler"); - jGetFrameNameJavaProfilingWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "getFrameName", "(III)Ljava/lang/String;"); - jGetSampleTimeJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "getSampleTime", "(II)D"); - jGetThreadNameJavaProfilingWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "getThreadName", "(I)Ljava/lang/String;"); - jPauseJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "pause", "()V"); - jStartJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "start", "(II)V"); - jStopJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "stop", "()V"); - jUnpauseJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "unpause", "()V"); +void GeckoJavaSampler::InitStubs(JNIEnv *jEnv) { + initInit(); + + mGeckoJavaSamplerClass = getClassGlobalRef("org/mozilla/gecko/GeckoJavaSampler"); + jGetFrameNameJavaProfilingWrapper = getStaticMethod("getFrameName", "(III)Ljava/lang/String;"); + jGetSampleTimeJavaProfiling = getStaticMethod("getSampleTime", "(II)D"); + jGetThreadNameJavaProfilingWrapper = getStaticMethod("getThreadName", "(I)Ljava/lang/String;"); + jPauseJavaProfiling = getStaticMethod("pause", "()V"); + jStartJavaProfiling = getStaticMethod("start", "(II)V"); + jStopJavaProfiling = getStaticMethod("stop", "()V"); + jUnpauseJavaProfiling = getStaticMethod("unpause", "()V"); } GeckoJavaSampler* GeckoJavaSampler::Wrap(jobject obj) { @@ -1451,11 +1457,13 @@ jclass RestrictedProfiles::mRestrictedProfilesClass = 0; jmethodID RestrictedProfiles::jGetUserRestrictions = 0; jmethodID RestrictedProfiles::jIsAllowed = 0; jmethodID RestrictedProfiles::jIsUserRestricted = 0; -void RestrictedProfiles::InitStubs(JNIEnv *env) { - mRestrictedProfilesClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/RestrictedProfiles"); - jGetUserRestrictions = AndroidBridge::GetStaticMethodID(env, mRestrictedProfilesClass, "getUserRestrictions", "()Ljava/lang/String;"); - jIsAllowed = AndroidBridge::GetStaticMethodID(env, mRestrictedProfilesClass, "isAllowed", "(ILjava/lang/String;)Z"); - jIsUserRestricted = AndroidBridge::GetStaticMethodID(env, mRestrictedProfilesClass, "isUserRestricted", "()Z"); +void RestrictedProfiles::InitStubs(JNIEnv *jEnv) { + initInit(); + + mRestrictedProfilesClass = getClassGlobalRef("org/mozilla/gecko/RestrictedProfiles"); + jGetUserRestrictions = getStaticMethod("getUserRestrictions", "()Ljava/lang/String;"); + jIsAllowed = getStaticMethod("isAllowed", "(ILjava/lang/String;)Z"); + jIsUserRestricted = getStaticMethod("isUserRestricted", "()Z"); } RestrictedProfiles* RestrictedProfiles::Wrap(jobject obj) { @@ -1511,13 +1519,15 @@ jfieldID SurfaceBits::jbuffer = 0; jfieldID SurfaceBits::jformat = 0; jfieldID SurfaceBits::jheight = 0; jfieldID SurfaceBits::jwidth = 0; -void SurfaceBits::InitStubs(JNIEnv *env) { - mSurfaceBitsClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/SurfaceBits"); - jSurfaceBits = AndroidBridge::GetMethodID(env, mSurfaceBitsClass, "", "()V"); - jbuffer = AndroidBridge::GetFieldID(env, mSurfaceBitsClass, "buffer", "Ljava/nio/ByteBuffer;"); - jformat = AndroidBridge::GetFieldID(env, mSurfaceBitsClass, "format", "I"); - jheight = AndroidBridge::GetFieldID(env, mSurfaceBitsClass, "height", "I"); - jwidth = AndroidBridge::GetFieldID(env, mSurfaceBitsClass, "width", "I"); +void SurfaceBits::InitStubs(JNIEnv *jEnv) { + initInit(); + + mSurfaceBitsClass = getClassGlobalRef("org/mozilla/gecko/SurfaceBits"); + jSurfaceBits = getMethod("", "()V"); + jbuffer = getField("buffer", "Ljava/nio/ByteBuffer;"); + jformat = getField("format", "I"); + jheight = getField("height", "I"); + jwidth = getField("width", "I"); } SurfaceBits* SurfaceBits::Wrap(jobject obj) { @@ -1579,9 +1589,11 @@ void SurfaceBits::setwidth(int32_t a0) { } jclass ThumbnailHelper::mThumbnailHelperClass = 0; jmethodID ThumbnailHelper::jSendThumbnail = 0; -void ThumbnailHelper::InitStubs(JNIEnv *env) { - mThumbnailHelperClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/ThumbnailHelper"); - jSendThumbnail = AndroidBridge::GetStaticMethodID(env, mThumbnailHelperClass, "notifyThumbnail", "(Ljava/nio/ByteBuffer;IZZ)V"); +void ThumbnailHelper::InitStubs(JNIEnv *jEnv) { + initInit(); + + mThumbnailHelperClass = getClassGlobalRef("org/mozilla/gecko/ThumbnailHelper"); + jSendThumbnail = getStaticMethod("notifyThumbnail", "(Ljava/nio/ByteBuffer;IZZ)V"); } ThumbnailHelper* ThumbnailHelper::Wrap(jobject obj) { @@ -1612,11 +1624,13 @@ jclass DisplayPortMetrics::mDisplayPortMetricsClass = 0; jmethodID DisplayPortMetrics::jDisplayPortMetrics = 0; jfieldID DisplayPortMetrics::jMPosition = 0; jfieldID DisplayPortMetrics::jResolution = 0; -void DisplayPortMetrics::InitStubs(JNIEnv *env) { - mDisplayPortMetricsClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/DisplayPortMetrics"); - jDisplayPortMetrics = AndroidBridge::GetMethodID(env, mDisplayPortMetricsClass, "", "(FFFFF)V"); - jMPosition = AndroidBridge::GetFieldID(env, mDisplayPortMetricsClass, "mPosition", "Landroid/graphics/RectF;"); - jResolution = AndroidBridge::GetFieldID(env, mDisplayPortMetricsClass, "resolution", "F"); +void DisplayPortMetrics::InitStubs(JNIEnv *jEnv) { + initInit(); + + mDisplayPortMetricsClass = getClassGlobalRef("org/mozilla/gecko/gfx/DisplayPortMetrics"); + jDisplayPortMetrics = getMethod("", "(FFFFF)V"); + jMPosition = getField("mPosition", "Landroid/graphics/RectF;"); + jResolution = getField("resolution", "F"); } DisplayPortMetrics* DisplayPortMetrics::Wrap(jobject obj) { @@ -1655,9 +1669,11 @@ jfloat DisplayPortMetrics::getResolution() { } jclass GLController::mGLControllerClass = 0; jmethodID GLController::jCreateEGLSurfaceForCompositorWrapper = 0; -void GLController::InitStubs(JNIEnv *env) { - mGLControllerClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/GLController"); - jCreateEGLSurfaceForCompositorWrapper = AndroidBridge::GetMethodID(env, mGLControllerClass, "createEGLSurfaceForCompositor", "()Ljavax/microedition/khronos/egl/EGLSurface;"); +void GLController::InitStubs(JNIEnv *jEnv) { + initInit(); + + mGLControllerClass = getClassGlobalRef("org/mozilla/gecko/gfx/GLController"); + jCreateEGLSurfaceForCompositorWrapper = getMethod("createEGLSurfaceForCompositor", "()Ljavax/microedition/khronos/egl/EGLSurface;"); } GLController* GLController::Wrap(jobject obj) { @@ -1691,19 +1707,21 @@ jmethodID GeckoLayerClient::jSetFirstPaintViewport = 0; jmethodID GeckoLayerClient::jSetPageRect = 0; jmethodID GeckoLayerClient::jSyncFrameMetrics = 0; jmethodID GeckoLayerClient::jSyncViewportInfo = 0; -void GeckoLayerClient::InitStubs(JNIEnv *env) { - mGeckoLayerClientClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/GeckoLayerClient"); - jActivateProgram = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "activateProgram", "()V"); - jContentDocumentChanged = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "contentDocumentChanged", "()V"); - jCreateFrame = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "createFrame", "()Lorg/mozilla/gecko/gfx/LayerRenderer$Frame;"); - jDeactivateProgramAndRestoreState = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "deactivateProgramAndRestoreState", "(ZIIII)V"); - jGetDisplayPort = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "getDisplayPort", "(ZZILorg/mozilla/gecko/gfx/ImmutableViewportMetrics;)Lorg/mozilla/gecko/gfx/DisplayPortMetrics;"); - jIsContentDocumentDisplayed = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "isContentDocumentDisplayed", "()Z"); - jProgressiveUpdateCallback = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "progressiveUpdateCallback", "(ZFFFFFZ)Lorg/mozilla/gecko/gfx/ProgressiveUpdateData;"); - jSetFirstPaintViewport = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "setFirstPaintViewport", "(FFFFFFF)V"); - jSetPageRect = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "setPageRect", "(FFFF)V"); - jSyncFrameMetrics = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "syncFrameMetrics", "(FFFFFFFZIIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;"); - jSyncViewportInfo = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "syncViewportInfo", "(IIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;"); +void GeckoLayerClient::InitStubs(JNIEnv *jEnv) { + initInit(); + + mGeckoLayerClientClass = getClassGlobalRef("org/mozilla/gecko/gfx/GeckoLayerClient"); + jActivateProgram = getMethod("activateProgram", "()V"); + jContentDocumentChanged = getMethod("contentDocumentChanged", "()V"); + jCreateFrame = getMethod("createFrame", "()Lorg/mozilla/gecko/gfx/LayerRenderer$Frame;"); + jDeactivateProgramAndRestoreState = getMethod("deactivateProgramAndRestoreState", "(ZIIII)V"); + jGetDisplayPort = getMethod("getDisplayPort", "(ZZILorg/mozilla/gecko/gfx/ImmutableViewportMetrics;)Lorg/mozilla/gecko/gfx/DisplayPortMetrics;"); + jIsContentDocumentDisplayed = getMethod("isContentDocumentDisplayed", "()Z"); + jProgressiveUpdateCallback = getMethod("progressiveUpdateCallback", "(ZFFFFFZ)Lorg/mozilla/gecko/gfx/ProgressiveUpdateData;"); + jSetFirstPaintViewport = getMethod("setFirstPaintViewport", "(FFFFFFF)V"); + jSetPageRect = getMethod("setPageRect", "(FFFF)V"); + jSyncFrameMetrics = getMethod("syncFrameMetrics", "(FFFFFFFZIIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;"); + jSyncViewportInfo = getMethod("syncViewportInfo", "(IIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;"); } GeckoLayerClient* GeckoLayerClient::Wrap(jobject obj) { @@ -1913,9 +1931,11 @@ jobject GeckoLayerClient::SyncViewportInfo(int32_t a0, int32_t a1, int32_t a2, i } jclass ImmutableViewportMetrics::mImmutableViewportMetricsClass = 0; jmethodID ImmutableViewportMetrics::jImmutableViewportMetrics = 0; -void ImmutableViewportMetrics::InitStubs(JNIEnv *env) { - mImmutableViewportMetricsClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/ImmutableViewportMetrics"); - jImmutableViewportMetrics = AndroidBridge::GetMethodID(env, mImmutableViewportMetricsClass, "", "(FFFFFFFFFFFFF)V"); +void ImmutableViewportMetrics::InitStubs(JNIEnv *jEnv) { + initInit(); + + mImmutableViewportMetricsClass = getClassGlobalRef("org/mozilla/gecko/gfx/ImmutableViewportMetrics"); + jImmutableViewportMetrics = getMethod("", "(FFFFFFFFFFFFF)V"); } ImmutableViewportMetrics* ImmutableViewportMetrics::Wrap(jobject obj) { @@ -1952,9 +1972,11 @@ ImmutableViewportMetrics::ImmutableViewportMetrics(jfloat a0, jfloat a1, jfloat } jclass LayerView::mLayerViewClass = 0; jmethodID LayerView::jRegisterCompositorWrapper = 0; -void LayerView::InitStubs(JNIEnv *env) { - mLayerViewClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/LayerView"); - jRegisterCompositorWrapper = AndroidBridge::GetStaticMethodID(env, mLayerViewClass, "registerCxxCompositor", "()Lorg/mozilla/gecko/gfx/GLController;"); +void LayerView::InitStubs(JNIEnv *jEnv) { + initInit(); + + mLayerViewClass = getClassGlobalRef("org/mozilla/gecko/gfx/LayerView"); + jRegisterCompositorWrapper = getStaticMethod("registerCxxCompositor", "()Lorg/mozilla/gecko/gfx/GLController;"); } LayerView* LayerView::Wrap(jobject obj) { @@ -1978,9 +2000,11 @@ jobject LayerView::RegisterCompositorWrapper() { } jclass NativePanZoomController::mNativePanZoomControllerClass = 0; jmethodID NativePanZoomController::jRequestContentRepaintWrapper = 0; -void NativePanZoomController::InitStubs(JNIEnv *env) { - mNativePanZoomControllerClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/NativePanZoomController"); - jRequestContentRepaintWrapper = AndroidBridge::GetMethodID(env, mNativePanZoomControllerClass, "requestContentRepaint", "(FFFFF)V"); +void NativePanZoomController::InitStubs(JNIEnv *jEnv) { + initInit(); + + mNativePanZoomControllerClass = getClassGlobalRef("org/mozilla/gecko/gfx/NativePanZoomController"); + jRequestContentRepaintWrapper = getMethod("requestContentRepaint", "(FFFFF)V"); } NativePanZoomController* NativePanZoomController::Wrap(jobject obj) { @@ -2015,14 +2039,16 @@ jfieldID ProgressiveUpdateData::jabort = 0; jfieldID ProgressiveUpdateData::jscale = 0; jfieldID ProgressiveUpdateData::jx = 0; jfieldID ProgressiveUpdateData::jy = 0; -void ProgressiveUpdateData::InitStubs(JNIEnv *env) { - mProgressiveUpdateDataClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/ProgressiveUpdateData"); - jProgressiveUpdateData = AndroidBridge::GetMethodID(env, mProgressiveUpdateDataClass, "", "()V"); - jsetViewport = AndroidBridge::GetMethodID(env, mProgressiveUpdateDataClass, "setViewport", "(Lorg/mozilla/gecko/gfx/ImmutableViewportMetrics;)V"); - jabort = AndroidBridge::GetFieldID(env, mProgressiveUpdateDataClass, "abort", "Z"); - jscale = AndroidBridge::GetFieldID(env, mProgressiveUpdateDataClass, "scale", "F"); - jx = AndroidBridge::GetFieldID(env, mProgressiveUpdateDataClass, "x", "F"); - jy = AndroidBridge::GetFieldID(env, mProgressiveUpdateDataClass, "y", "F"); +void ProgressiveUpdateData::InitStubs(JNIEnv *jEnv) { + initInit(); + + mProgressiveUpdateDataClass = getClassGlobalRef("org/mozilla/gecko/gfx/ProgressiveUpdateData"); + jProgressiveUpdateData = getMethod("", "()V"); + jsetViewport = getMethod("setViewport", "(Lorg/mozilla/gecko/gfx/ImmutableViewportMetrics;)V"); + jabort = getField("abort", "Z"); + jscale = getField("scale", "F"); + jx = getField("x", "F"); + jy = getField("y", "F"); } ProgressiveUpdateData* ProgressiveUpdateData::Wrap(jobject obj) { @@ -2105,18 +2131,20 @@ jfieldID ViewTransform::joffsetY = 0; jfieldID ViewTransform::jscale = 0; jfieldID ViewTransform::jx = 0; jfieldID ViewTransform::jy = 0; -void ViewTransform::InitStubs(JNIEnv *env) { - mViewTransformClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/ViewTransform"); - jViewTransform = AndroidBridge::GetMethodID(env, mViewTransformClass, "", "(FFF)V"); - jfixedLayerMarginBottom = AndroidBridge::GetFieldID(env, mViewTransformClass, "fixedLayerMarginBottom", "F"); - jfixedLayerMarginLeft = AndroidBridge::GetFieldID(env, mViewTransformClass, "fixedLayerMarginLeft", "F"); - jfixedLayerMarginRight = AndroidBridge::GetFieldID(env, mViewTransformClass, "fixedLayerMarginRight", "F"); - jfixedLayerMarginTop = AndroidBridge::GetFieldID(env, mViewTransformClass, "fixedLayerMarginTop", "F"); - joffsetX = AndroidBridge::GetFieldID(env, mViewTransformClass, "offsetX", "F"); - joffsetY = AndroidBridge::GetFieldID(env, mViewTransformClass, "offsetY", "F"); - jscale = AndroidBridge::GetFieldID(env, mViewTransformClass, "scale", "F"); - jx = AndroidBridge::GetFieldID(env, mViewTransformClass, "x", "F"); - jy = AndroidBridge::GetFieldID(env, mViewTransformClass, "y", "F"); +void ViewTransform::InitStubs(JNIEnv *jEnv) { + initInit(); + + mViewTransformClass = getClassGlobalRef("org/mozilla/gecko/gfx/ViewTransform"); + jViewTransform = getMethod("", "(FFF)V"); + jfixedLayerMarginBottom = getField("fixedLayerMarginBottom", "F"); + jfixedLayerMarginLeft = getField("fixedLayerMarginLeft", "F"); + jfixedLayerMarginRight = getField("fixedLayerMarginRight", "F"); + jfixedLayerMarginTop = getField("fixedLayerMarginTop", "F"); + joffsetX = getField("offsetX", "F"); + joffsetY = getField("offsetY", "F"); + jscale = getField("scale", "F"); + jx = getField("x", "F"); + jy = getField("y", "F"); } ViewTransform* ViewTransform::Wrap(jobject obj) { @@ -2233,9 +2261,11 @@ void ViewTransform::sety(jfloat a0) { } jclass NativeZip::mNativeZipClass = 0; jmethodID NativeZip::jCreateInputStream = 0; -void NativeZip::InitStubs(JNIEnv *env) { - mNativeZipClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/mozglue/NativeZip"); - jCreateInputStream = AndroidBridge::GetMethodID(env, mNativeZipClass, "createInputStream", "(Ljava/nio/ByteBuffer;I)Ljava/io/InputStream;"); +void NativeZip::InitStubs(JNIEnv *jEnv) { + initInit(); + + mNativeZipClass = getClassGlobalRef("org/mozilla/gecko/mozglue/NativeZip"); + jCreateInputStream = getMethod("createInputStream", "(Ljava/nio/ByteBuffer;I)Ljava/io/InputStream;"); } NativeZip* NativeZip::Wrap(jobject obj) { @@ -2263,13 +2293,15 @@ jmethodID MatrixBlobCursor::jMatrixBlobCursor0 = 0; jmethodID MatrixBlobCursor::jAddRow = 0; jmethodID MatrixBlobCursor::jAddRow1 = 0; jmethodID MatrixBlobCursor::jAddRow2 = 0; -void MatrixBlobCursor::InitStubs(JNIEnv *env) { - mMatrixBlobCursorClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/sqlite/MatrixBlobCursor"); - jMatrixBlobCursor = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "", "([Ljava/lang/String;)V"); - jMatrixBlobCursor0 = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "", "([Ljava/lang/String;I)V"); - jAddRow = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "addRow", "(Ljava/lang/Iterable;)V"); - jAddRow1 = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "addRow", "(Ljava/util/ArrayList;I)V"); - jAddRow2 = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "addRow", "([Ljava/lang/Object;)V"); +void MatrixBlobCursor::InitStubs(JNIEnv *jEnv) { + initInit(); + + mMatrixBlobCursorClass = getClassGlobalRef("org/mozilla/gecko/sqlite/MatrixBlobCursor"); + jMatrixBlobCursor = getMethod("", "([Ljava/lang/String;)V"); + jMatrixBlobCursor0 = getMethod("", "([Ljava/lang/String;I)V"); + jAddRow = getMethod("addRow", "(Ljava/lang/Iterable;)V"); + jAddRow1 = getMethod("addRow", "(Ljava/util/ArrayList;I)V"); + jAddRow2 = getMethod("addRow", "([Ljava/lang/Object;)V"); } MatrixBlobCursor* MatrixBlobCursor::Wrap(jobject obj) { @@ -2340,11 +2372,13 @@ jclass SQLiteBridgeException::mSQLiteBridgeExceptionClass = 0; jmethodID SQLiteBridgeException::jSQLiteBridgeException = 0; jmethodID SQLiteBridgeException::jSQLiteBridgeException0 = 0; jfieldID SQLiteBridgeException::jserialVersionUID = 0; -void SQLiteBridgeException::InitStubs(JNIEnv *env) { - mSQLiteBridgeExceptionClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/sqlite/SQLiteBridgeException"); - jSQLiteBridgeException = AndroidBridge::GetMethodID(env, mSQLiteBridgeExceptionClass, "", "()V"); - jSQLiteBridgeException0 = AndroidBridge::GetMethodID(env, mSQLiteBridgeExceptionClass, "", "(Ljava/lang/String;)V"); - jserialVersionUID = AndroidBridge::GetStaticFieldID(env, mSQLiteBridgeExceptionClass, "serialVersionUID", "J"); +void SQLiteBridgeException::InitStubs(JNIEnv *jEnv) { + initInit(); + + mSQLiteBridgeExceptionClass = getClassGlobalRef("org/mozilla/gecko/sqlite/SQLiteBridgeException"); + jSQLiteBridgeException = getMethod("", "()V"); + jSQLiteBridgeException0 = getMethod("", "(Ljava/lang/String;)V"); + jserialVersionUID = getStaticField("serialVersionUID", "J"); } SQLiteBridgeException* SQLiteBridgeException::Wrap(jobject obj) { @@ -2387,12 +2421,14 @@ jmethodID Clipboard::jClearText = 0; jmethodID Clipboard::jGetClipboardTextWrapper = 0; jmethodID Clipboard::jHasText = 0; jmethodID Clipboard::jSetClipboardText = 0; -void Clipboard::InitStubs(JNIEnv *env) { - mClipboardClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/util/Clipboard"); - jClearText = AndroidBridge::GetStaticMethodID(env, mClipboardClass, "clearText", "()V"); - jGetClipboardTextWrapper = AndroidBridge::GetStaticMethodID(env, mClipboardClass, "getText", "()Ljava/lang/String;"); - jHasText = AndroidBridge::GetStaticMethodID(env, mClipboardClass, "hasText", "()Z"); - jSetClipboardText = AndroidBridge::GetStaticMethodID(env, mClipboardClass, "setText", "(Ljava/lang/CharSequence;)V"); +void Clipboard::InitStubs(JNIEnv *jEnv) { + initInit(); + + mClipboardClass = getClassGlobalRef("org/mozilla/gecko/util/Clipboard"); + jClearText = getStaticMethod("clearText", "()V"); + jGetClipboardTextWrapper = getStaticMethod("getText", "()Ljava/lang/String;"); + jHasText = getStaticMethod("hasText", "()Z"); + jSetClipboardText = getStaticMethod("setText", "(Ljava/lang/CharSequence;)V"); } Clipboard* Clipboard::Wrap(jobject obj) { @@ -2454,25 +2490,25 @@ void Clipboard::SetClipboardText(const nsAString& a0) { env->PopLocalFrame(nullptr); } -void InitStubs(JNIEnv *env) { - DownloadsIntegration::InitStubs(env); - GeckoAppShell::InitStubs(env); - GeckoJavaSampler::InitStubs(env); - RestrictedProfiles::InitStubs(env); - SurfaceBits::InitStubs(env); - ThumbnailHelper::InitStubs(env); - DisplayPortMetrics::InitStubs(env); - GLController::InitStubs(env); - GeckoLayerClient::InitStubs(env); - ImmutableViewportMetrics::InitStubs(env); - LayerView::InitStubs(env); - NativePanZoomController::InitStubs(env); - ProgressiveUpdateData::InitStubs(env); - ViewTransform::InitStubs(env); - NativeZip::InitStubs(env); - MatrixBlobCursor::InitStubs(env); - SQLiteBridgeException::InitStubs(env); - Clipboard::InitStubs(env); +void InitStubs(JNIEnv *jEnv) { + DownloadsIntegration::InitStubs(jEnv); + GeckoAppShell::InitStubs(jEnv); + GeckoJavaSampler::InitStubs(jEnv); + RestrictedProfiles::InitStubs(jEnv); + SurfaceBits::InitStubs(jEnv); + ThumbnailHelper::InitStubs(jEnv); + DisplayPortMetrics::InitStubs(jEnv); + GLController::InitStubs(jEnv); + GeckoLayerClient::InitStubs(jEnv); + ImmutableViewportMetrics::InitStubs(jEnv); + LayerView::InitStubs(jEnv); + NativePanZoomController::InitStubs(jEnv); + ProgressiveUpdateData::InitStubs(jEnv); + ViewTransform::InitStubs(jEnv); + NativeZip::InitStubs(jEnv); + MatrixBlobCursor::InitStubs(jEnv); + SQLiteBridgeException::InitStubs(jEnv); + Clipboard::InitStubs(jEnv); } } /* android */ } /* widget */ diff --git a/widget/android/GeneratedJNIWrappers.h b/widget/android/GeneratedJNIWrappers.h index 7aa326e8e895..2a143a4e4863 100644 --- a/widget/android/GeneratedJNIWrappers.h +++ b/widget/android/GeneratedJNIWrappers.h @@ -12,11 +12,11 @@ namespace mozilla { namespace widget { namespace android { -void InitStubs(JNIEnv *env); +void InitStubs(JNIEnv *jEnv); class DownloadsIntegration : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *env); + static void InitStubs(JNIEnv *jEnv); static DownloadsIntegration* Wrap(jobject obj); DownloadsIntegration(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; static void ScanMedia(const nsAString& a0, const nsAString& a1); @@ -28,7 +28,7 @@ protected: class GeckoAppShell : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *env); + static void InitStubs(JNIEnv *jEnv); static GeckoAppShell* Wrap(jobject obj); GeckoAppShell(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; static void AcknowledgeEvent(); @@ -202,7 +202,7 @@ protected: class GeckoJavaSampler : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *env); + static void InitStubs(JNIEnv *jEnv); static GeckoJavaSampler* Wrap(jobject obj); GeckoJavaSampler(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; static jstring GetFrameNameJavaProfilingWrapper(int32_t a0, int32_t a1, int32_t a2); @@ -226,7 +226,7 @@ protected: class RestrictedProfiles : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *env); + static void InitStubs(JNIEnv *jEnv); static RestrictedProfiles* Wrap(jobject obj); RestrictedProfiles(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; static jstring GetUserRestrictions(); @@ -242,7 +242,7 @@ protected: class SurfaceBits : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *env); + static void InitStubs(JNIEnv *jEnv); static SurfaceBits* Wrap(jobject obj); SurfaceBits(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; SurfaceBits(); @@ -265,7 +265,7 @@ protected: class ThumbnailHelper : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *env); + static void InitStubs(JNIEnv *jEnv); static ThumbnailHelper* Wrap(jobject obj); ThumbnailHelper(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; static void SendThumbnail(jobject a0, int32_t a1, bool a2, bool a3); @@ -277,7 +277,7 @@ protected: class DisplayPortMetrics : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *env); + static void InitStubs(JNIEnv *jEnv); static DisplayPortMetrics* Wrap(jobject obj); DisplayPortMetrics(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; DisplayPortMetrics(jfloat a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4); @@ -293,7 +293,7 @@ protected: class GLController : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *env); + static void InitStubs(JNIEnv *jEnv); static GLController* Wrap(jobject obj); GLController(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; jobject CreateEGLSurfaceForCompositorWrapper(); @@ -305,7 +305,7 @@ protected: class GeckoLayerClient : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *env); + static void InitStubs(JNIEnv *jEnv); static GeckoLayerClient* Wrap(jobject obj); GeckoLayerClient(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; void ActivateProgram(); @@ -337,7 +337,7 @@ protected: class ImmutableViewportMetrics : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *env); + static void InitStubs(JNIEnv *jEnv); static ImmutableViewportMetrics* Wrap(jobject obj); ImmutableViewportMetrics(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; ImmutableViewportMetrics(jfloat a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4, jfloat a5, jfloat a6, jfloat a7, jfloat a8, jfloat a9, jfloat a10, jfloat a11, jfloat a12); @@ -349,7 +349,7 @@ protected: class LayerView : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *env); + static void InitStubs(JNIEnv *jEnv); static LayerView* Wrap(jobject obj); LayerView(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; static jobject RegisterCompositorWrapper(); @@ -361,7 +361,7 @@ protected: class NativePanZoomController : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *env); + static void InitStubs(JNIEnv *jEnv); static NativePanZoomController* Wrap(jobject obj); NativePanZoomController(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; void RequestContentRepaintWrapper(jfloat a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4); @@ -373,7 +373,7 @@ protected: class ProgressiveUpdateData : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *env); + static void InitStubs(JNIEnv *jEnv); static ProgressiveUpdateData* Wrap(jobject obj); ProgressiveUpdateData(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; ProgressiveUpdateData(); @@ -398,7 +398,7 @@ protected: class ViewTransform : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *env); + static void InitStubs(JNIEnv *jEnv); static ViewTransform* Wrap(jobject obj); ViewTransform(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; ViewTransform(jfloat a0, jfloat a1, jfloat a2); @@ -437,7 +437,7 @@ protected: class NativeZip : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *env); + static void InitStubs(JNIEnv *jEnv); static NativeZip* Wrap(jobject obj); NativeZip(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; jobject CreateInputStream(jobject a0, int32_t a1); @@ -449,7 +449,7 @@ protected: class MatrixBlobCursor : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *env); + static void InitStubs(JNIEnv *jEnv); static MatrixBlobCursor* Wrap(jobject obj); MatrixBlobCursor(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; MatrixBlobCursor(jobjectArray a0); @@ -469,7 +469,7 @@ protected: class SQLiteBridgeException : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *env); + static void InitStubs(JNIEnv *jEnv); static SQLiteBridgeException* Wrap(jobject obj); SQLiteBridgeException(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; SQLiteBridgeException(); @@ -484,7 +484,7 @@ protected: class Clipboard : public AutoGlobalWrappedJavaObject { public: - static void InitStubs(JNIEnv *env); + static void InitStubs(JNIEnv *jEnv); static Clipboard* Wrap(jobject obj); Clipboard(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; static void ClearText(); diff --git a/widget/android/GeneratedSDKWrappers.cpp b/widget/android/GeneratedSDKWrappers.cpp new file mode 100644 index 000000000000..28c85a960874 --- /dev/null +++ b/widget/android/GeneratedSDKWrappers.cpp @@ -0,0 +1,1877 @@ +// GENERATED CODE +// Generated by the Java program at /build/jarClassProcessors at compile time from +// a given set of jars and a set of requested methods. To update, change the annotations +// on the corresponding Java methods and rerun the build. Manually updating this file +// will cause your build to fail. + +#include "GeneratedSDKWrappers.h" +#include "AndroidBridgeUtilities.h" +#include "nsXPCOMStrings.h" +#include "AndroidBridge.h" +#include "nsDebug.h" + +namespace mozilla { +namespace widget { +namespace android { +jclass MediaCodec::mMediaCodecClass = 0; +jmethodID MediaCodec::jConfigure = 0; +jmethodID MediaCodec::jCreateByCodecName = 0; +jmethodID MediaCodec::jCreateDecoderByType = 0; +jmethodID MediaCodec::jCreateEncoderByType = 0; +jmethodID MediaCodec::jDequeueInputBuffer = 0; +jmethodID MediaCodec::jDequeueOutputBuffer = 0; +jmethodID MediaCodec::jFinalize = 0; +jmethodID MediaCodec::jFlush = 0; +jmethodID MediaCodec::jGetInputBuffers = 0; +jmethodID MediaCodec::jGetOutputBuffers = 0; +jmethodID MediaCodec::jGetOutputFormat = 0; +jmethodID MediaCodec::jQueueInputBuffer = 0; +jmethodID MediaCodec::jQueueSecureInputBuffer = 0; +jmethodID MediaCodec::jRelease = 0; +jmethodID MediaCodec::jReleaseOutputBuffer = 0; +jmethodID MediaCodec::jSetVideoScalingMode = 0; +jmethodID MediaCodec::jStart = 0; +jmethodID MediaCodec::jStop = 0; +jfieldID MediaCodec::jBUFFER_FLAG_CODEC_CONFIG = 0; +jfieldID MediaCodec::jBUFFER_FLAG_END_OF_STREAM = 0; +jfieldID MediaCodec::jBUFFER_FLAG_SYNC_FRAME = 0; +jfieldID MediaCodec::jCONFIGURE_FLAG_ENCODE = 0; +jfieldID MediaCodec::jCRYPTO_MODE_AES_CTR = 0; +jfieldID MediaCodec::jCRYPTO_MODE_UNENCRYPTED = 0; +jfieldID MediaCodec::jINFO_OUTPUT_BUFFERS_CHANGED = 0; +jfieldID MediaCodec::jINFO_OUTPUT_FORMAT_CHANGED = 0; +jfieldID MediaCodec::jINFO_TRY_AGAIN_LATER = 0; +jfieldID MediaCodec::jVIDEO_SCALING_MODE_SCALE_TO_FIT = 0; +jfieldID MediaCodec::jVIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 0; +void MediaCodec::InitStubs(JNIEnv *jEnv) { + initInit(); + + mMediaCodecClass = getClassGlobalRef("android/media/MediaCodec"); + jConfigure = getMethod("configure", "(Landroid/media/MediaFormat;Landroid/view/Surface;Landroid/media/MediaCrypto;I)V"); + jCreateByCodecName = getStaticMethod("createByCodecName", "(Ljava/lang/String;)Landroid/media/MediaCodec;"); + jCreateDecoderByType = getStaticMethod("createDecoderByType", "(Ljava/lang/String;)Landroid/media/MediaCodec;"); + jCreateEncoderByType = getStaticMethod("createEncoderByType", "(Ljava/lang/String;)Landroid/media/MediaCodec;"); + jDequeueInputBuffer = getMethod("dequeueInputBuffer", "(J)I"); + jDequeueOutputBuffer = getMethod("dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I"); + jFinalize = getMethod("finalize", "()V"); + jFlush = getMethod("flush", "()V"); + jGetInputBuffers = getMethod("getInputBuffers", "()[Ljava/nio/ByteBuffer;"); + jGetOutputBuffers = getMethod("getOutputBuffers", "()[Ljava/nio/ByteBuffer;"); + jGetOutputFormat = getMethod("getOutputFormat", "()Landroid/media/MediaFormat;"); + jQueueInputBuffer = getMethod("queueInputBuffer", "(IIIJI)V"); + jQueueSecureInputBuffer = getMethod("queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V"); + jRelease = getMethod("release", "()V"); + jReleaseOutputBuffer = getMethod("releaseOutputBuffer", "(IZ)V"); + jSetVideoScalingMode = getMethod("setVideoScalingMode", "(I)V"); + jStart = getMethod("start", "()V"); + jStop = getMethod("stop", "()V"); + jBUFFER_FLAG_CODEC_CONFIG = getStaticField("BUFFER_FLAG_CODEC_CONFIG", "I"); + jBUFFER_FLAG_END_OF_STREAM = getStaticField("BUFFER_FLAG_END_OF_STREAM", "I"); + jBUFFER_FLAG_SYNC_FRAME = getStaticField("BUFFER_FLAG_SYNC_FRAME", "I"); + jCONFIGURE_FLAG_ENCODE = getStaticField("CONFIGURE_FLAG_ENCODE", "I"); + jCRYPTO_MODE_AES_CTR = getStaticField("CRYPTO_MODE_AES_CTR", "I"); + jCRYPTO_MODE_UNENCRYPTED = getStaticField("CRYPTO_MODE_UNENCRYPTED", "I"); + jINFO_OUTPUT_BUFFERS_CHANGED = getStaticField("INFO_OUTPUT_BUFFERS_CHANGED", "I"); + jINFO_OUTPUT_FORMAT_CHANGED = getStaticField("INFO_OUTPUT_FORMAT_CHANGED", "I"); + jINFO_TRY_AGAIN_LATER = getStaticField("INFO_TRY_AGAIN_LATER", "I"); + jVIDEO_SCALING_MODE_SCALE_TO_FIT = getStaticField("VIDEO_SCALING_MODE_SCALE_TO_FIT", "I"); + jVIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = getStaticField("VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING", "I"); +} + +MediaCodec* MediaCodec::Wrap(jobject obj) { + JNIEnv *env = GetJNIForThread(); + MediaCodec* ret = new MediaCodec(obj, env); + env->DeleteLocalRef(obj); + return ret; +} + +bool MediaCodec::Configure(jobject a0, jobject a1, jobject a2, int32_t a3) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(3) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jvalue args[4]; + args[0].l = a0; + args[1].l = a1; + args[2].l = a2; + args[3].i = a3; + + env->CallVoidMethodA(wrapped_obj, jConfigure, args); + if (env->ExceptionCheck()) { + env->ExceptionClear(); + env->PopLocalFrame(nullptr); + return false; + } + env->PopLocalFrame(nullptr); + return true; +} + +jobject MediaCodec::CreateByCodecName(const nsAString& a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(2) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jstring j0 = AndroidBridge::NewJavaString(env, a0); + + jobject temp = env->CallStaticObjectMethod(mMediaCodecClass, jCreateByCodecName, j0); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject MediaCodec::CreateDecoderByType(const nsAString& a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(2) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jstring j0 = AndroidBridge::NewJavaString(env, a0); + + jobject temp = env->CallStaticObjectMethod(mMediaCodecClass, jCreateDecoderByType, j0); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject MediaCodec::CreateEncoderByType(const nsAString& a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(2) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jstring j0 = AndroidBridge::NewJavaString(env, a0); + + jobject temp = env->CallStaticObjectMethod(mMediaCodecClass, jCreateEncoderByType, j0); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +int32_t MediaCodec::DequeueInputBuffer(int64_t a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + int32_t temp = env->CallIntMethod(wrapped_obj, jDequeueInputBuffer, a0); + if (env->ExceptionCheck()) { + env->ExceptionClear(); + env->PopLocalFrame(nullptr); + return MEDIACODEC_EXCEPTION_INDEX; + } + env->PopLocalFrame(nullptr); + return temp; +} + +int32_t MediaCodec::DequeueOutputBuffer(jobject a0, int64_t a1) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + int32_t temp = env->CallIntMethod(wrapped_obj, jDequeueOutputBuffer, a0, a1); + if (env->ExceptionCheck()) { + env->ExceptionClear(); + env->PopLocalFrame(nullptr); + return MEDIACODEC_EXCEPTION_INDEX; + } + env->PopLocalFrame(nullptr); + return temp; +} + +void MediaCodec::Finalize() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + env->CallVoidMethod(wrapped_obj, jFinalize); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); +} + +void MediaCodec::Flush() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + env->CallVoidMethod(wrapped_obj, jFlush); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); +} + +jobjectArray MediaCodec::GetInputBuffers() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jGetInputBuffers); + AndroidBridge::HandleUncaughtException(env); + jobjectArray ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobjectArray MediaCodec::GetOutputBuffers() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jGetOutputBuffers); + AndroidBridge::HandleUncaughtException(env); + jobjectArray ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject MediaCodec::GetOutputFormat() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jGetOutputFormat); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +void MediaCodec::QueueInputBuffer(int32_t a0, int32_t a1, int32_t a2, int64_t a3, int32_t a4) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(5) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jvalue args[5]; + args[0].i = a0; + args[1].i = a1; + args[2].i = a2; + args[3].j = a3; + args[4].i = a4; + + env->CallVoidMethodA(wrapped_obj, jQueueInputBuffer, args); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); +} + +void MediaCodec::QueueSecureInputBuffer(int32_t a0, int32_t a1, jobject a2, int64_t a3, int32_t a4) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jvalue args[5]; + args[0].i = a0; + args[1].i = a1; + args[2].l = a2; + args[3].j = a3; + args[4].i = a4; + + env->CallVoidMethodA(wrapped_obj, jQueueSecureInputBuffer, args); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); +} + +void MediaCodec::Release() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + env->CallVoidMethod(wrapped_obj, jRelease); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); +} + +void MediaCodec::ReleaseOutputBuffer(int32_t a0, bool a1) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + env->CallVoidMethod(wrapped_obj, jReleaseOutputBuffer, a0, a1); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); +} + +void MediaCodec::SetVideoScalingMode(int32_t a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + env->CallVoidMethod(wrapped_obj, jSetVideoScalingMode, a0); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); +} + +bool MediaCodec::Start() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + env->CallVoidMethod(wrapped_obj, jStart); + if (env->ExceptionCheck()) { + env->ExceptionClear(); + env->PopLocalFrame(nullptr); + return false; + } + env->PopLocalFrame(nullptr); + return true; +} + +void MediaCodec::Stop() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + env->CallVoidMethod(wrapped_obj, jStop); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); +} + +int32_t MediaCodec::getBUFFER_FLAG_CODEC_CONFIG() { + JNIEnv *env = GetJNIForThread(); + return env->GetStaticIntField(mMediaCodecClass, jBUFFER_FLAG_CODEC_CONFIG); +} + +int32_t MediaCodec::getBUFFER_FLAG_END_OF_STREAM() { + JNIEnv *env = GetJNIForThread(); + return env->GetStaticIntField(mMediaCodecClass, jBUFFER_FLAG_END_OF_STREAM); +} + +int32_t MediaCodec::getBUFFER_FLAG_SYNC_FRAME() { + JNIEnv *env = GetJNIForThread(); + return env->GetStaticIntField(mMediaCodecClass, jBUFFER_FLAG_SYNC_FRAME); +} + +int32_t MediaCodec::getCONFIGURE_FLAG_ENCODE() { + JNIEnv *env = GetJNIForThread(); + return env->GetStaticIntField(mMediaCodecClass, jCONFIGURE_FLAG_ENCODE); +} + +int32_t MediaCodec::getCRYPTO_MODE_AES_CTR() { + JNIEnv *env = GetJNIForThread(); + return env->GetStaticIntField(mMediaCodecClass, jCRYPTO_MODE_AES_CTR); +} + +int32_t MediaCodec::getCRYPTO_MODE_UNENCRYPTED() { + JNIEnv *env = GetJNIForThread(); + return env->GetStaticIntField(mMediaCodecClass, jCRYPTO_MODE_UNENCRYPTED); +} + +int32_t MediaCodec::getINFO_OUTPUT_BUFFERS_CHANGED() { + JNIEnv *env = GetJNIForThread(); + return env->GetStaticIntField(mMediaCodecClass, jINFO_OUTPUT_BUFFERS_CHANGED); +} + +int32_t MediaCodec::getINFO_OUTPUT_FORMAT_CHANGED() { + JNIEnv *env = GetJNIForThread(); + return env->GetStaticIntField(mMediaCodecClass, jINFO_OUTPUT_FORMAT_CHANGED); +} + +int32_t MediaCodec::getINFO_TRY_AGAIN_LATER() { + JNIEnv *env = GetJNIForThread(); + return env->GetStaticIntField(mMediaCodecClass, jINFO_TRY_AGAIN_LATER); +} + +int32_t MediaCodec::getVIDEO_SCALING_MODE_SCALE_TO_FIT() { + JNIEnv *env = GetJNIForThread(); + return env->GetStaticIntField(mMediaCodecClass, jVIDEO_SCALING_MODE_SCALE_TO_FIT); +} + +int32_t MediaCodec::getVIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING() { + JNIEnv *env = GetJNIForThread(); + return env->GetStaticIntField(mMediaCodecClass, jVIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING); +} +jclass MediaFormat::mMediaFormatClass = 0; +jmethodID MediaFormat::jMediaFormat = 0; +jmethodID MediaFormat::jContainsKey = 0; +jmethodID MediaFormat::jCreateAudioFormat = 0; +jmethodID MediaFormat::jCreateVideoFormat = 0; +jmethodID MediaFormat::jGetByteBuffer = 0; +jmethodID MediaFormat::jGetFloat = 0; +jmethodID MediaFormat::jGetInteger = 0; +jmethodID MediaFormat::jGetLong = 0; +jmethodID MediaFormat::jGetString = 0; +jmethodID MediaFormat::jSetByteBuffer = 0; +jmethodID MediaFormat::jSetFloat = 0; +jmethodID MediaFormat::jSetInteger = 0; +jmethodID MediaFormat::jSetLong = 0; +jmethodID MediaFormat::jSetString = 0; +jmethodID MediaFormat::jToString = 0; +jfieldID MediaFormat::jKEY_AAC_PROFILE = 0; +jfieldID MediaFormat::jKEY_BIT_RATE = 0; +jfieldID MediaFormat::jKEY_CHANNEL_COUNT = 0; +jfieldID MediaFormat::jKEY_CHANNEL_MASK = 0; +jfieldID MediaFormat::jKEY_COLOR_FORMAT = 0; +jfieldID MediaFormat::jKEY_DURATION = 0; +jfieldID MediaFormat::jKEY_FLAC_COMPRESSION_LEVEL = 0; +jfieldID MediaFormat::jKEY_FRAME_RATE = 0; +jfieldID MediaFormat::jKEY_HEIGHT = 0; +jfieldID MediaFormat::jKEY_IS_ADTS = 0; +jfieldID MediaFormat::jKEY_I_FRAME_INTERVAL = 0; +jfieldID MediaFormat::jKEY_MAX_INPUT_SIZE = 0; +jfieldID MediaFormat::jKEY_MIME = 0; +jfieldID MediaFormat::jKEY_SAMPLE_RATE = 0; +jfieldID MediaFormat::jKEY_WIDTH = 0; +void MediaFormat::InitStubs(JNIEnv *jEnv) { + initInit(); + + mMediaFormatClass = getClassGlobalRef("android/media/MediaFormat"); + jMediaFormat = getMethod("", "()V"); + jContainsKey = getMethod("containsKey", "(Ljava/lang/String;)Z"); + jCreateAudioFormat = getStaticMethod("createAudioFormat", "(Ljava/lang/String;II)Landroid/media/MediaFormat;"); + jCreateVideoFormat = getStaticMethod("createVideoFormat", "(Ljava/lang/String;II)Landroid/media/MediaFormat;"); + jGetByteBuffer = getMethod("getByteBuffer", "(Ljava/lang/String;)Ljava/nio/ByteBuffer;"); + jGetFloat = getMethod("getFloat", "(Ljava/lang/String;)F"); + jGetInteger = getMethod("getInteger", "(Ljava/lang/String;)I"); + jGetLong = getMethod("getLong", "(Ljava/lang/String;)J"); + jGetString = getMethod("getString", "(Ljava/lang/String;)Ljava/lang/String;"); + jSetByteBuffer = getMethod("setByteBuffer", "(Ljava/lang/String;Ljava/nio/ByteBuffer;)V"); + jSetFloat = getMethod("setFloat", "(Ljava/lang/String;F)V"); + jSetInteger = getMethod("setInteger", "(Ljava/lang/String;I)V"); + jSetLong = getMethod("setLong", "(Ljava/lang/String;J)V"); + jSetString = getMethod("setString", "(Ljava/lang/String;Ljava/lang/String;)V"); + jToString = getMethod("toString", "()Ljava/lang/String;"); + jKEY_AAC_PROFILE = getStaticField("KEY_AAC_PROFILE", "Ljava/lang/String;"); + jKEY_BIT_RATE = getStaticField("KEY_BIT_RATE", "Ljava/lang/String;"); + jKEY_CHANNEL_COUNT = getStaticField("KEY_CHANNEL_COUNT", "Ljava/lang/String;"); + jKEY_CHANNEL_MASK = getStaticField("KEY_CHANNEL_MASK", "Ljava/lang/String;"); + jKEY_COLOR_FORMAT = getStaticField("KEY_COLOR_FORMAT", "Ljava/lang/String;"); + jKEY_DURATION = getStaticField("KEY_DURATION", "Ljava/lang/String;"); + jKEY_FLAC_COMPRESSION_LEVEL = getStaticField("KEY_FLAC_COMPRESSION_LEVEL", "Ljava/lang/String;"); + jKEY_FRAME_RATE = getStaticField("KEY_FRAME_RATE", "Ljava/lang/String;"); + jKEY_HEIGHT = getStaticField("KEY_HEIGHT", "Ljava/lang/String;"); + jKEY_IS_ADTS = getStaticField("KEY_IS_ADTS", "Ljava/lang/String;"); + jKEY_I_FRAME_INTERVAL = getStaticField("KEY_I_FRAME_INTERVAL", "Ljava/lang/String;"); + jKEY_MAX_INPUT_SIZE = getStaticField("KEY_MAX_INPUT_SIZE", "Ljava/lang/String;"); + jKEY_MIME = getStaticField("KEY_MIME", "Ljava/lang/String;"); + jKEY_SAMPLE_RATE = getStaticField("KEY_SAMPLE_RATE", "Ljava/lang/String;"); + jKEY_WIDTH = getStaticField("KEY_WIDTH", "Ljava/lang/String;"); +} + +MediaFormat* MediaFormat::Wrap(jobject obj) { + JNIEnv *env = GetJNIForThread(); + MediaFormat* ret = new MediaFormat(obj, env); + env->DeleteLocalRef(obj); + return ret; +} + +MediaFormat::MediaFormat() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + Init(env->NewObject(mMediaFormatClass, jMediaFormat), env); + env->PopLocalFrame(nullptr); +} + +bool MediaFormat::ContainsKey(const nsAString& a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jstring j0 = AndroidBridge::NewJavaString(env, a0); + + bool temp = env->CallBooleanMethod(wrapped_obj, jContainsKey, j0); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +jobject MediaFormat::CreateAudioFormat(const nsAString& a0, int32_t a1, int32_t a2) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(2) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jvalue args[3]; + args[0].l = AndroidBridge::NewJavaString(env, a0); + args[1].i = a1; + args[2].i = a2; + + jobject temp = env->CallStaticObjectMethodA(mMediaFormatClass, jCreateAudioFormat, args); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject MediaFormat::CreateVideoFormat(const nsAString& a0, int32_t a1, int32_t a2) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(2) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jvalue args[3]; + args[0].l = AndroidBridge::NewJavaString(env, a0); + args[1].i = a1; + args[2].i = a2; + + jobject temp = env->CallStaticObjectMethodA(mMediaFormatClass, jCreateVideoFormat, args); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject MediaFormat::GetByteBuffer(const nsAString& a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(2) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jstring j0 = AndroidBridge::NewJavaString(env, a0); + + jobject temp = env->CallObjectMethod(wrapped_obj, jGetByteBuffer, j0); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jfloat MediaFormat::GetFloat(const nsAString& a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jstring j0 = AndroidBridge::NewJavaString(env, a0); + + jfloat temp = env->CallFloatMethod(wrapped_obj, jGetFloat, j0); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +int32_t MediaFormat::GetInteger(const nsAString& a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jstring j0 = AndroidBridge::NewJavaString(env, a0); + + int32_t temp = env->CallIntMethod(wrapped_obj, jGetInteger, j0); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +int64_t MediaFormat::GetLong(const nsAString& a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jstring j0 = AndroidBridge::NewJavaString(env, a0); + + int64_t temp = env->CallLongMethod(wrapped_obj, jGetLong, j0); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +jstring MediaFormat::GetString(const nsAString& a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(2) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jstring j0 = AndroidBridge::NewJavaString(env, a0); + + jobject temp = env->CallObjectMethod(wrapped_obj, jGetString, j0); + AndroidBridge::HandleUncaughtException(env); + jstring ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +void MediaFormat::SetByteBuffer(const nsAString& a0, jobject a1) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(2) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jstring j0 = AndroidBridge::NewJavaString(env, a0); + + env->CallVoidMethod(wrapped_obj, jSetByteBuffer, j0, a1); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); +} + +void MediaFormat::SetFloat(const nsAString& a0, jfloat a1) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jstring j0 = AndroidBridge::NewJavaString(env, a0); + + env->CallVoidMethod(wrapped_obj, jSetFloat, j0, a1); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); +} + +void MediaFormat::SetInteger(const nsAString& a0, int32_t a1) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jstring j0 = AndroidBridge::NewJavaString(env, a0); + + env->CallVoidMethod(wrapped_obj, jSetInteger, j0, a1); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); +} + +void MediaFormat::SetLong(const nsAString& a0, int64_t a1) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jstring j0 = AndroidBridge::NewJavaString(env, a0); + + env->CallVoidMethod(wrapped_obj, jSetLong, j0, a1); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); +} + +void MediaFormat::SetString(const nsAString& a0, const nsAString& a1) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(2) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jstring j0 = AndroidBridge::NewJavaString(env, a0); + jstring j1 = AndroidBridge::NewJavaString(env, a1); + + env->CallVoidMethod(wrapped_obj, jSetString, j0, j1); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); +} + +jstring MediaFormat::ToString() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jToString); + AndroidBridge::HandleUncaughtException(env); + jstring ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jstring MediaFormat::getKEY_AAC_PROFILE() { + JNIEnv *env = GetJNIForThread(); + return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_AAC_PROFILE)); +} + +jstring MediaFormat::getKEY_BIT_RATE() { + JNIEnv *env = GetJNIForThread(); + return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_BIT_RATE)); +} + +jstring MediaFormat::getKEY_CHANNEL_COUNT() { + JNIEnv *env = GetJNIForThread(); + return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_CHANNEL_COUNT)); +} + +jstring MediaFormat::getKEY_CHANNEL_MASK() { + JNIEnv *env = GetJNIForThread(); + return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_CHANNEL_MASK)); +} + +jstring MediaFormat::getKEY_COLOR_FORMAT() { + JNIEnv *env = GetJNIForThread(); + return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_COLOR_FORMAT)); +} + +jstring MediaFormat::getKEY_DURATION() { + JNIEnv *env = GetJNIForThread(); + return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_DURATION)); +} + +jstring MediaFormat::getKEY_FLAC_COMPRESSION_LEVEL() { + JNIEnv *env = GetJNIForThread(); + return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_FLAC_COMPRESSION_LEVEL)); +} + +jstring MediaFormat::getKEY_FRAME_RATE() { + JNIEnv *env = GetJNIForThread(); + return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_FRAME_RATE)); +} + +jstring MediaFormat::getKEY_HEIGHT() { + JNIEnv *env = GetJNIForThread(); + return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_HEIGHT)); +} + +jstring MediaFormat::getKEY_IS_ADTS() { + JNIEnv *env = GetJNIForThread(); + return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_IS_ADTS)); +} + +jstring MediaFormat::getKEY_I_FRAME_INTERVAL() { + JNIEnv *env = GetJNIForThread(); + return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_I_FRAME_INTERVAL)); +} + +jstring MediaFormat::getKEY_MAX_INPUT_SIZE() { + JNIEnv *env = GetJNIForThread(); + return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_MAX_INPUT_SIZE)); +} + +jstring MediaFormat::getKEY_MIME() { + JNIEnv *env = GetJNIForThread(); + return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_MIME)); +} + +jstring MediaFormat::getKEY_SAMPLE_RATE() { + JNIEnv *env = GetJNIForThread(); + return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_SAMPLE_RATE)); +} + +jstring MediaFormat::getKEY_WIDTH() { + JNIEnv *env = GetJNIForThread(); + return static_cast(env->GetStaticObjectField(mMediaFormatClass, jKEY_WIDTH)); +} +jclass ByteBuffer::mByteBufferClass = 0; +jmethodID ByteBuffer::j_get = 0; +jmethodID ByteBuffer::j_put = 0; +jmethodID ByteBuffer::jAllocate = 0; +jmethodID ByteBuffer::jAllocateDirect = 0; +jmethodID ByteBuffer::jArray = 0; +jmethodID ByteBuffer::jArray1 = 0; +jmethodID ByteBuffer::jArrayOffset = 0; +jmethodID ByteBuffer::jAsCharBuffer = 0; +jmethodID ByteBuffer::jAsDoubleBuffer = 0; +jmethodID ByteBuffer::jAsFloatBuffer = 0; +jmethodID ByteBuffer::jAsIntBuffer = 0; +jmethodID ByteBuffer::jAsLongBuffer = 0; +jmethodID ByteBuffer::jAsReadOnlyBuffer = 0; +jmethodID ByteBuffer::jAsShortBuffer = 0; +jmethodID ByteBuffer::jCompact = 0; +jmethodID ByteBuffer::jCompareTo = 0; +jmethodID ByteBuffer::jCompareTo1 = 0; +jmethodID ByteBuffer::jDuplicate = 0; +jmethodID ByteBuffer::jEquals = 0; +jmethodID ByteBuffer::jGet = 0; +jmethodID ByteBuffer::jGet1 = 0; +jmethodID ByteBuffer::jGet10 = 0; +jmethodID ByteBuffer::jGet11 = 0; +jmethodID ByteBuffer::jGetChar = 0; +jmethodID ByteBuffer::jGetChar1 = 0; +jmethodID ByteBuffer::jGetDouble = 0; +jmethodID ByteBuffer::jGetDouble1 = 0; +jmethodID ByteBuffer::jGetFloat = 0; +jmethodID ByteBuffer::jGetFloat1 = 0; +jmethodID ByteBuffer::jGetInt = 0; +jmethodID ByteBuffer::jGetInt1 = 0; +jmethodID ByteBuffer::jGetLong = 0; +jmethodID ByteBuffer::jGetLong1 = 0; +jmethodID ByteBuffer::jGetShort = 0; +jmethodID ByteBuffer::jGetShort1 = 0; +jmethodID ByteBuffer::jHasArray = 0; +jmethodID ByteBuffer::jHashCode = 0; +jmethodID ByteBuffer::jIsDirect = 0; +jmethodID ByteBuffer::jOrder = 0; +jmethodID ByteBuffer::jOrder1 = 0; +jmethodID ByteBuffer::jPut = 0; +jmethodID ByteBuffer::jPut1 = 0; +jmethodID ByteBuffer::jPut12 = 0; +jmethodID ByteBuffer::jPut13 = 0; +jmethodID ByteBuffer::jPut14 = 0; +jmethodID ByteBuffer::jPutChar = 0; +jmethodID ByteBuffer::jPutChar1 = 0; +jmethodID ByteBuffer::jPutDouble = 0; +jmethodID ByteBuffer::jPutDouble1 = 0; +jmethodID ByteBuffer::jPutFloat = 0; +jmethodID ByteBuffer::jPutFloat1 = 0; +jmethodID ByteBuffer::jPutInt = 0; +jmethodID ByteBuffer::jPutInt1 = 0; +jmethodID ByteBuffer::jPutLong = 0; +jmethodID ByteBuffer::jPutLong1 = 0; +jmethodID ByteBuffer::jPutShort = 0; +jmethodID ByteBuffer::jPutShort1 = 0; +jmethodID ByteBuffer::jSlice = 0; +jmethodID ByteBuffer::jToString = 0; +jmethodID ByteBuffer::jWrap = 0; +jmethodID ByteBuffer::jWrap1 = 0; +jfieldID ByteBuffer::jBigEndian = 0; +jfieldID ByteBuffer::jHb = 0; +jfieldID ByteBuffer::jIsReadOnly = 0; +jfieldID ByteBuffer::jNativeByteOrder = 0; +jfieldID ByteBuffer::jOffset = 0; +void ByteBuffer::InitStubs(JNIEnv *jEnv) { + initInit(); + + mByteBufferClass = getClassGlobalRef("java/nio/ByteBuffer"); + //j_get = getMethod("_get", "(I)B"); + //j_put = getMethod("_put", "(IB)V"); + jAllocate = getStaticMethod("allocate", "(I)Ljava/nio/ByteBuffer;"); + jAllocateDirect = getStaticMethod("allocateDirect", "(I)Ljava/nio/ByteBuffer;"); + jArray = getMethod("array", "()Ljava/lang/Object;"); + jArray1 = getMethod("array", "()[B"); + jArrayOffset = getMethod("arrayOffset", "()I"); + jAsCharBuffer = getMethod("asCharBuffer", "()Ljava/nio/CharBuffer;"); + jAsDoubleBuffer = getMethod("asDoubleBuffer", "()Ljava/nio/DoubleBuffer;"); + jAsFloatBuffer = getMethod("asFloatBuffer", "()Ljava/nio/FloatBuffer;"); + jAsIntBuffer = getMethod("asIntBuffer", "()Ljava/nio/IntBuffer;"); + jAsLongBuffer = getMethod("asLongBuffer", "()Ljava/nio/LongBuffer;"); + jAsReadOnlyBuffer = getMethod("asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;"); + jAsShortBuffer = getMethod("asShortBuffer", "()Ljava/nio/ShortBuffer;"); + jCompact = getMethod("compact", "()Ljava/nio/ByteBuffer;"); + jCompareTo = getMethod("compareTo", "(Ljava/lang/Object;)I"); + jCompareTo1 = getMethod("compareTo", "(Ljava/nio/ByteBuffer;)I"); + jDuplicate = getMethod("duplicate", "()Ljava/nio/ByteBuffer;"); + jEquals = getMethod("equals", "(Ljava/lang/Object;)Z"); + jGet = getMethod("get", "()B"); + jGet1 = getMethod("get", "(I)B"); + jGet10 = getMethod("get", "([B)Ljava/nio/ByteBuffer;"); + jGet11 = getMethod("get", "([BII)Ljava/nio/ByteBuffer;"); + jGetChar = getMethod("getChar", "()C"); + jGetChar1 = getMethod("getChar", "(I)C"); + jGetDouble = getMethod("getDouble", "()D"); + jGetDouble1 = getMethod("getDouble", "(I)D"); + jGetFloat = getMethod("getFloat", "()F"); + jGetFloat1 = getMethod("getFloat", "(I)F"); + jGetInt = getMethod("getInt", "()I"); + jGetInt1 = getMethod("getInt", "(I)I"); + jGetLong = getMethod("getLong", "()J"); + jGetLong1 = getMethod("getLong", "(I)J"); + jGetShort = getMethod("getShort", "()S"); + jGetShort1 = getMethod("getShort", "(I)S"); + jHasArray = getMethod("hasArray", "()Z"); + jHashCode = getMethod("hashCode", "()I"); + jIsDirect = getMethod("isDirect", "()Z"); + jOrder = getMethod("order", "()Ljava/nio/ByteOrder;"); + jOrder1 = getMethod("order", "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;"); + jPut = getMethod("put", "(B)Ljava/nio/ByteBuffer;"); + jPut1 = getMethod("put", "(IB)Ljava/nio/ByteBuffer;"); + jPut12 = getMethod("put", "(Ljava/nio/ByteBuffer;)Ljava/nio/ByteBuffer;"); + jPut13 = getMethod("put", "([B)Ljava/nio/ByteBuffer;"); + jPut14 = getMethod("put", "([BII)Ljava/nio/ByteBuffer;"); + jPutChar = getMethod("putChar", "(C)Ljava/nio/ByteBuffer;"); + jPutChar1 = getMethod("putChar", "(IC)Ljava/nio/ByteBuffer;"); + jPutDouble = getMethod("putDouble", "(D)Ljava/nio/ByteBuffer;"); + jPutDouble1 = getMethod("putDouble", "(ID)Ljava/nio/ByteBuffer;"); + jPutFloat = getMethod("putFloat", "(F)Ljava/nio/ByteBuffer;"); + jPutFloat1 = getMethod("putFloat", "(IF)Ljava/nio/ByteBuffer;"); + jPutInt = getMethod("putInt", "(I)Ljava/nio/ByteBuffer;"); + jPutInt1 = getMethod("putInt", "(II)Ljava/nio/ByteBuffer;"); + jPutLong = getMethod("putLong", "(IJ)Ljava/nio/ByteBuffer;"); + jPutLong1 = getMethod("putLong", "(J)Ljava/nio/ByteBuffer;"); + jPutShort = getMethod("putShort", "(IS)Ljava/nio/ByteBuffer;"); + jPutShort1 = getMethod("putShort", "(S)Ljava/nio/ByteBuffer;"); + jSlice = getMethod("slice", "()Ljava/nio/ByteBuffer;"); + jToString = getMethod("toString", "()Ljava/lang/String;"); + jWrap = getStaticMethod("wrap", "([B)Ljava/nio/ByteBuffer;"); + jWrap1 = getStaticMethod("wrap", "([BII)Ljava/nio/ByteBuffer;"); + /* + jBigEndian = getField("bigEndian", "Z"); + jHb = getField("hb", "[B"); + jIsReadOnly = getField("isReadOnly", "Z"); + jNativeByteOrder = getField("nativeByteOrder", "Z"); + jOffset = getField("offset", "I"); + */ +} + +ByteBuffer* ByteBuffer::Wrap(jobject obj) { + JNIEnv *env = GetJNIForThread(); + ByteBuffer* ret = new ByteBuffer(obj, env); + env->DeleteLocalRef(obj); + return ret; +} + +int8_t ByteBuffer::_get(int32_t a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + int8_t temp = env->CallByteMethod(wrapped_obj, j_get, a0); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +void ByteBuffer::_put(int32_t a0, int8_t a1) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + env->CallVoidMethod(wrapped_obj, j_put, a0, a1); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); +} + +jobject ByteBuffer::Allocate(int32_t a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallStaticObjectMethod(mByteBufferClass, jAllocate, a0); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::AllocateDirect(int32_t a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallStaticObjectMethod(mByteBufferClass, jAllocateDirect, a0); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::Array() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jArray); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jbyteArray ByteBuffer::Array1() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jArray1); + AndroidBridge::HandleUncaughtException(env); + jbyteArray ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +int32_t ByteBuffer::ArrayOffset() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + int32_t temp = env->CallIntMethod(wrapped_obj, jArrayOffset); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +jstring ByteBuffer::AsCharBuffer() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jAsCharBuffer); + AndroidBridge::HandleUncaughtException(env); + jstring ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::AsDoubleBuffer() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jAsDoubleBuffer); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::AsFloatBuffer() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jAsFloatBuffer); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::AsIntBuffer() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jAsIntBuffer); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::AsLongBuffer() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jAsLongBuffer); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::AsReadOnlyBuffer() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jAsReadOnlyBuffer); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::AsShortBuffer() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jAsShortBuffer); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::Compact() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jCompact); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +int32_t ByteBuffer::CompareTo(jobject a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + int32_t temp = env->CallIntMethod(wrapped_obj, jCompareTo, a0); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +int32_t ByteBuffer::CompareTo1(jobject a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + int32_t temp = env->CallIntMethod(wrapped_obj, jCompareTo1, a0); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +jobject ByteBuffer::Duplicate() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jDuplicate); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +bool ByteBuffer::Equals(jobject a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + bool temp = env->CallBooleanMethod(wrapped_obj, jEquals, a0); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +int8_t ByteBuffer::Get() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + int8_t temp = env->CallByteMethod(wrapped_obj, jGet); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +int8_t ByteBuffer::Get1(int32_t a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + int8_t temp = env->CallByteMethod(wrapped_obj, jGet1, a0); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +jobject ByteBuffer::Get1(jbyteArray a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(2) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jGet10, a0); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::Get1(jbyteArray a0, int32_t a1, int32_t a2) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(2) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jvalue args[3]; + args[0].l = a0; + args[1].i = a1; + args[2].i = a2; + + jobject temp = env->CallObjectMethodA(wrapped_obj, jGet11, args); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +uint16_t ByteBuffer::GetChar() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + uint16_t temp = env->CallCharMethod(wrapped_obj, jGetChar); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +uint16_t ByteBuffer::GetChar1(int32_t a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + uint16_t temp = env->CallCharMethod(wrapped_obj, jGetChar1, a0); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +jdouble ByteBuffer::GetDouble() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jdouble temp = env->CallDoubleMethod(wrapped_obj, jGetDouble); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +jdouble ByteBuffer::GetDouble1(int32_t a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jdouble temp = env->CallDoubleMethod(wrapped_obj, jGetDouble1, a0); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +jfloat ByteBuffer::GetFloat() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jfloat temp = env->CallFloatMethod(wrapped_obj, jGetFloat); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +jfloat ByteBuffer::GetFloat1(int32_t a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jfloat temp = env->CallFloatMethod(wrapped_obj, jGetFloat1, a0); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +int32_t ByteBuffer::GetInt() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + int32_t temp = env->CallIntMethod(wrapped_obj, jGetInt); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +int32_t ByteBuffer::GetInt1(int32_t a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + int32_t temp = env->CallIntMethod(wrapped_obj, jGetInt1, a0); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +int64_t ByteBuffer::GetLong() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + int64_t temp = env->CallLongMethod(wrapped_obj, jGetLong); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +int64_t ByteBuffer::GetLong1(int32_t a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + int64_t temp = env->CallLongMethod(wrapped_obj, jGetLong1, a0); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +int16_t ByteBuffer::GetShort() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + int16_t temp = env->CallShortMethod(wrapped_obj, jGetShort); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +int16_t ByteBuffer::GetShort1(int32_t a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + int16_t temp = env->CallShortMethod(wrapped_obj, jGetShort1, a0); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +bool ByteBuffer::HasArray() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + bool temp = env->CallBooleanMethod(wrapped_obj, jHasArray); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +int32_t ByteBuffer::HashCode() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + int32_t temp = env->CallIntMethod(wrapped_obj, jHashCode); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +bool ByteBuffer::IsDirect() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + bool temp = env->CallBooleanMethod(wrapped_obj, jIsDirect); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); + return temp; +} + +jobject ByteBuffer::Order() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jOrder); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::Order1(jobject a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(2) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jOrder1, a0); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::Put(int8_t a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jPut, a0); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::Put1(int32_t a0, int8_t a1) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jPut1, a0, a1); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::Put1(jobject a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(2) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jPut12, a0); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::Put1(jbyteArray a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(2) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jPut13, a0); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::Put1(jbyteArray a0, int32_t a1, int32_t a2) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(2) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jvalue args[3]; + args[0].l = a0; + args[1].i = a1; + args[2].i = a2; + + jobject temp = env->CallObjectMethodA(wrapped_obj, jPut14, args); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::PutChar(uint16_t a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jPutChar, a0); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::PutChar1(int32_t a0, uint16_t a1) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jPutChar1, a0, a1); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::PutDouble(jdouble a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jPutDouble, a0); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::PutDouble1(int32_t a0, jdouble a1) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jPutDouble1, a0, a1); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::PutFloat(jfloat a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jPutFloat, a0); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::PutFloat1(int32_t a0, jfloat a1) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jPutFloat1, a0, a1); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::PutInt(int32_t a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jPutInt, a0); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::PutInt1(int32_t a0, int32_t a1) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jPutInt1, a0, a1); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::PutLong(int32_t a0, int64_t a1) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jPutLong, a0, a1); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::PutLong1(int64_t a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jPutLong1, a0); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::PutShort(int32_t a0, int16_t a1) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jPutShort, a0, a1); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::PutShort1(int16_t a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jPutShort1, a0); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::Slice() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jSlice); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jstring ByteBuffer::ToString() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(1) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallObjectMethod(wrapped_obj, jToString); + AndroidBridge::HandleUncaughtException(env); + jstring ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::Wrap1(jbyteArray a0) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(2) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jobject temp = env->CallStaticObjectMethod(mByteBufferClass, jWrap, a0); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +jobject ByteBuffer::Wrap2(jbyteArray a0, int32_t a1, int32_t a2) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(2) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jvalue args[3]; + args[0].l = a0; + args[1].i = a1; + args[2].i = a2; + + jobject temp = env->CallStaticObjectMethodA(mByteBufferClass, jWrap1, args); + AndroidBridge::HandleUncaughtException(env); + jobject ret = static_cast(env->PopLocalFrame(temp)); + return ret; +} + +bool ByteBuffer::getBigEndian() { + JNIEnv *env = GetJNIForThread(); + return env->GetBooleanField(wrapped_obj, jBigEndian); +} + +void ByteBuffer::setBigEndian(bool a0) { + JNIEnv *env = GetJNIForThread(); + env->SetBooleanField(wrapped_obj, jBigEndian, a0); +} + +jbyteArray ByteBuffer::getHb() { + JNIEnv *env = GetJNIForThread(); + return static_cast(env->GetObjectField(wrapped_obj, jHb)); +} + +bool ByteBuffer::getIsReadOnly() { + JNIEnv *env = GetJNIForThread(); + return env->GetBooleanField(wrapped_obj, jIsReadOnly); +} + +void ByteBuffer::setIsReadOnly(bool a0) { + JNIEnv *env = GetJNIForThread(); + env->SetBooleanField(wrapped_obj, jIsReadOnly, a0); +} + +bool ByteBuffer::getNativeByteOrder() { + JNIEnv *env = GetJNIForThread(); + return env->GetBooleanField(wrapped_obj, jNativeByteOrder); +} + +void ByteBuffer::setNativeByteOrder(bool a0) { + JNIEnv *env = GetJNIForThread(); + env->SetBooleanField(wrapped_obj, jNativeByteOrder, a0); +} + +int32_t ByteBuffer::getOffset() { + JNIEnv *env = GetJNIForThread(); + return env->GetIntField(wrapped_obj, jOffset); +} + +jclass BufferInfo::mBufferInfoClass = 0; +jmethodID BufferInfo::jBufferInfo = 0; +jmethodID BufferInfo::jSet = 0; +jfieldID BufferInfo::jFlags = 0; +jfieldID BufferInfo::jOffset = 0; +jfieldID BufferInfo::jPresentationTimeUs = 0; +jfieldID BufferInfo::jSize = 0; +void BufferInfo::InitStubs(JNIEnv *jEnv) { + initInit(); + + mBufferInfoClass = getClassGlobalRef("android/media/MediaCodec$BufferInfo"); + jBufferInfo = getMethod("", "()V"); + jSet = getMethod("set", "(IIJI)V"); + jFlags = getField("flags", "I"); + jOffset = getField("offset", "I"); + jPresentationTimeUs = getField("presentationTimeUs", "J"); + jSize = getField("size", "I"); +} + +BufferInfo* BufferInfo::Wrap(jobject obj) { + JNIEnv *env = GetJNIForThread(); + BufferInfo* ret = new BufferInfo(obj, env); + env->DeleteLocalRef(obj); + return ret; +} + +BufferInfo::BufferInfo() { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + Init(env->NewObject(mBufferInfoClass, jBufferInfo), env); + env->PopLocalFrame(nullptr); +} + +void BufferInfo::Set(int32_t a0, int32_t a1, int64_t a2, int32_t a3) { + JNIEnv *env = GetJNIForThread(); + if (env->PushLocalFrame(0) != 0) { + AndroidBridge::HandleUncaughtException(env); + MOZ_CRASH("Exception should have caused crash."); + } + + jvalue args[4]; + args[0].i = a0; + args[1].i = a1; + args[2].j = a2; + args[3].i = a3; + + env->CallVoidMethodA(wrapped_obj, jSet, args); + AndroidBridge::HandleUncaughtException(env); + env->PopLocalFrame(nullptr); +} + +int32_t BufferInfo::getFlags() { + JNIEnv *env = GetJNIForThread(); + return env->GetIntField(wrapped_obj, jFlags); +} + +void BufferInfo::setFlags(int32_t a0) { + JNIEnv *env = GetJNIForThread(); + env->SetIntField(wrapped_obj, jFlags, a0); +} + +int32_t BufferInfo::getOffset() { + JNIEnv *env = GetJNIForThread(); + return env->GetIntField(wrapped_obj, jOffset); +} + +void BufferInfo::setOffset(int32_t a0) { + JNIEnv *env = GetJNIForThread(); + env->SetIntField(wrapped_obj, jOffset, a0); +} + +int64_t BufferInfo::getPresentationTimeUs() { + JNIEnv *env = GetJNIForThread(); + return env->GetLongField(wrapped_obj, jPresentationTimeUs); +} + +void BufferInfo::setPresentationTimeUs(int64_t a0) { + JNIEnv *env = GetJNIForThread(); + env->SetLongField(wrapped_obj, jPresentationTimeUs, a0); +} + +int32_t BufferInfo::getSize() { + JNIEnv *env = GetJNIForThread(); + return env->GetIntField(wrapped_obj, jSize); +} + +void BufferInfo::setSize(int32_t a0) { + JNIEnv *env = GetJNIForThread(); + env->SetIntField(wrapped_obj, jSize, a0); +} + +void InitSDKStubs(JNIEnv *jEnv) { + MediaCodec::InitStubs(jEnv); + MediaFormat::InitStubs(jEnv); + ByteBuffer::InitStubs(jEnv); + BufferInfo::InitStubs(jEnv); +} +} /* android */ +} /* widget */ +} /* mozilla */ diff --git a/widget/android/GeneratedSDKWrappers.h b/widget/android/GeneratedSDKWrappers.h new file mode 100644 index 000000000000..6368892fbb5c --- /dev/null +++ b/widget/android/GeneratedSDKWrappers.h @@ -0,0 +1,335 @@ +// GENERATED CODE + +// NOTE: This code has been doctored. The JarClassProcessor is still a work in progress, +// and so additions and deletions have been made to make this file valid. + +// Generated by the Java program at /build/jarClassProcessors at compile time from +// a given set of jars and a set of requested methods. To update, change the annotations +// on the corresponding Java methods and rerun the build. Manually updating this file +// will cause your build to fail. + +#ifndef GeneratedSDKWrappers_h__ +#define GeneratedSDKWrappers_h__ + +#include "nsXPCOMStrings.h" +#include "AndroidJavaWrappers.h" + +namespace mozilla { +namespace widget { +namespace android { + +#define MEDIACODEC_EXCEPTION_INDEX -255 + +void InitSDKStubs(JNIEnv *jEnv); + +class MediaCodec : public AutoGlobalWrappedJavaObject { +public: + static void InitStubs(JNIEnv *jEnv); + static MediaCodec* Wrap(jobject obj); + MediaCodec(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; + bool Configure(jobject a0, jobject a1, jobject a2, int32_t a3); + static jobject CreateByCodecName(const nsAString& a0); + static jobject CreateDecoderByType(const nsAString& a0); + static jobject CreateEncoderByType(const nsAString& a0); + int32_t DequeueInputBuffer(int64_t a0); + int32_t DequeueOutputBuffer(jobject a0, int64_t a1); + void Finalize(); + void Flush(); + jobjectArray GetInputBuffers(); + jobjectArray GetOutputBuffers(); + jobject GetOutputFormat(); + void QueueInputBuffer(int32_t a0, int32_t a1, int32_t a2, int64_t a3, int32_t a4); + void QueueSecureInputBuffer(int32_t a0, int32_t a1, jobject a2, int64_t a3, int32_t a4); + void Release(); + void ReleaseOutputBuffer(int32_t a0, bool a1); + void SetVideoScalingMode(int32_t a0); + bool Start(); + void Stop(); + static int32_t getBUFFER_FLAG_CODEC_CONFIG(); + static int32_t getBUFFER_FLAG_END_OF_STREAM(); + static int32_t getBUFFER_FLAG_SYNC_FRAME(); + static int32_t getCONFIGURE_FLAG_ENCODE(); + static int32_t getCRYPTO_MODE_AES_CTR(); + static int32_t getCRYPTO_MODE_UNENCRYPTED(); + static int32_t getINFO_OUTPUT_BUFFERS_CHANGED(); + static int32_t getINFO_OUTPUT_FORMAT_CHANGED(); + static int32_t getINFO_TRY_AGAIN_LATER(); + static int32_t getVIDEO_SCALING_MODE_SCALE_TO_FIT(); + static int32_t getVIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING(); + MediaCodec() : AutoGlobalWrappedJavaObject() {}; +protected: + static jclass mMediaCodecClass; + static jmethodID jConfigure; + static jmethodID jCreateByCodecName; + static jmethodID jCreateDecoderByType; + static jmethodID jCreateEncoderByType; + static jmethodID jDequeueInputBuffer; + static jmethodID jDequeueOutputBuffer; + static jmethodID jFinalize; + static jmethodID jFlush; + static jmethodID jGetInputBuffers; + static jmethodID jGetOutputBuffers; + static jmethodID jGetOutputFormat; + static jmethodID jQueueInputBuffer; + static jmethodID jQueueSecureInputBuffer; + static jmethodID jRelease; + static jmethodID jReleaseOutputBuffer; + static jmethodID jSetVideoScalingMode; + static jmethodID jStart; + static jmethodID jStop; + static jfieldID jBUFFER_FLAG_CODEC_CONFIG; + static jfieldID jBUFFER_FLAG_END_OF_STREAM; + static jfieldID jBUFFER_FLAG_SYNC_FRAME; + static jfieldID jCONFIGURE_FLAG_ENCODE; + static jfieldID jCRYPTO_MODE_AES_CTR; + static jfieldID jCRYPTO_MODE_UNENCRYPTED; + static jfieldID jINFO_OUTPUT_BUFFERS_CHANGED; + static jfieldID jINFO_OUTPUT_FORMAT_CHANGED; + static jfieldID jINFO_TRY_AGAIN_LATER; + static jfieldID jVIDEO_SCALING_MODE_SCALE_TO_FIT; + static jfieldID jVIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING; +}; + +class MediaFormat : public AutoGlobalWrappedJavaObject { +public: + static void InitStubs(JNIEnv *jEnv); + static MediaFormat* Wrap(jobject obj); + MediaFormat(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; + MediaFormat(); + bool ContainsKey(const nsAString& a0); + static jobject CreateAudioFormat(const nsAString& a0, int32_t a1, int32_t a2); + static jobject CreateVideoFormat(const nsAString& a0, int32_t a1, int32_t a2); + jobject GetByteBuffer(const nsAString& a0); + jfloat GetFloat(const nsAString& a0); + int32_t GetInteger(const nsAString& a0); + int64_t GetLong(const nsAString& a0); + jstring GetString(const nsAString& a0); + void SetByteBuffer(const nsAString& a0, jobject a1); + void SetFloat(const nsAString& a0, jfloat a1); + void SetInteger(const nsAString& a0, int32_t a1); + void SetLong(const nsAString& a0, int64_t a1); + void SetString(const nsAString& a0, const nsAString& a1); + jstring ToString(); + static jstring getKEY_AAC_PROFILE(); + static jstring getKEY_BIT_RATE(); + static jstring getKEY_CHANNEL_COUNT(); + static jstring getKEY_CHANNEL_MASK(); + static jstring getKEY_COLOR_FORMAT(); + static jstring getKEY_DURATION(); + static jstring getKEY_FLAC_COMPRESSION_LEVEL(); + static jstring getKEY_FRAME_RATE(); + static jstring getKEY_HEIGHT(); + static jstring getKEY_IS_ADTS(); + static jstring getKEY_I_FRAME_INTERVAL(); + static jstring getKEY_MAX_INPUT_SIZE(); + static jstring getKEY_MIME(); + static jstring getKEY_SAMPLE_RATE(); + static jstring getKEY_WIDTH(); +protected: + static jclass mMediaFormatClass; + static jmethodID jMediaFormat; + static jmethodID jContainsKey; + static jmethodID jCreateAudioFormat; + static jmethodID jCreateVideoFormat; + static jmethodID jGetByteBuffer; + static jmethodID jGetFloat; + static jmethodID jGetInteger; + static jmethodID jGetLong; + static jmethodID jGetString; + static jmethodID jSetByteBuffer; + static jmethodID jSetFloat; + static jmethodID jSetInteger; + static jmethodID jSetLong; + static jmethodID jSetString; + static jmethodID jToString; + static jfieldID jKEY_AAC_PROFILE; + static jfieldID jKEY_BIT_RATE; + static jfieldID jKEY_CHANNEL_COUNT; + static jfieldID jKEY_CHANNEL_MASK; + static jfieldID jKEY_COLOR_FORMAT; + static jfieldID jKEY_DURATION; + static jfieldID jKEY_FLAC_COMPRESSION_LEVEL; + static jfieldID jKEY_FRAME_RATE; + static jfieldID jKEY_HEIGHT; + static jfieldID jKEY_IS_ADTS; + static jfieldID jKEY_I_FRAME_INTERVAL; + static jfieldID jKEY_MAX_INPUT_SIZE; + static jfieldID jKEY_MIME; + static jfieldID jKEY_SAMPLE_RATE; + static jfieldID jKEY_WIDTH; +}; + +class ByteBuffer : public AutoGlobalWrappedJavaObject { +public: + static void InitStubs(JNIEnv *jEnv); + static ByteBuffer* Wrap(jobject obj); + ByteBuffer(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; + int8_t _get(int32_t a0); + void _put(int32_t a0, int8_t a1); + static jobject Allocate(int32_t a0); + static jobject AllocateDirect(int32_t a0); + jobject Array(); + jbyteArray Array1(); + int32_t ArrayOffset(); + jstring AsCharBuffer(); + jobject AsDoubleBuffer(); + jobject AsFloatBuffer(); + jobject AsIntBuffer(); + jobject AsLongBuffer(); + jobject AsReadOnlyBuffer(); + jobject AsShortBuffer(); + jobject Compact(); + int32_t CompareTo(jobject a0); + int32_t CompareTo1(jobject a0); + jobject Duplicate(); + bool Equals(jobject a0); + int8_t Get(); + int8_t Get1(int32_t a0); + jobject Get1(jbyteArray a0); + jobject Get1(jbyteArray a0, int32_t a1, int32_t a2); + uint16_t GetChar(); + uint16_t GetChar1(int32_t a0); + jdouble GetDouble(); + jdouble GetDouble1(int32_t a0); + jfloat GetFloat(); + jfloat GetFloat1(int32_t a0); + int32_t GetInt(); + int32_t GetInt1(int32_t a0); + int64_t GetLong(); + int64_t GetLong1(int32_t a0); + int16_t GetShort(); + int16_t GetShort1(int32_t a0); + bool HasArray(); + int32_t HashCode(); + bool IsDirect(); + jobject Order(); + jobject Order1(jobject a0); + jobject Put(int8_t a0); + jobject Put1(int32_t a0, int8_t a1); + jobject Put1(jobject a0); + jobject Put1(jbyteArray a0); + jobject Put1(jbyteArray a0, int32_t a1, int32_t a2); + jobject PutChar(uint16_t a0); + jobject PutChar1(int32_t a0, uint16_t a1); + jobject PutDouble(jdouble a0); + jobject PutDouble1(int32_t a0, jdouble a1); + jobject PutFloat(jfloat a0); + jobject PutFloat1(int32_t a0, jfloat a1); + jobject PutInt(int32_t a0); + jobject PutInt1(int32_t a0, int32_t a1); + jobject PutLong(int32_t a0, int64_t a1); + jobject PutLong1(int64_t a0); + jobject PutShort(int32_t a0, int16_t a1); + jobject PutShort1(int16_t a0); + jobject Slice(); + jstring ToString(); + static jobject Wrap1(jbyteArray a0); + static jobject Wrap2(jbyteArray a0, int32_t a1, int32_t a2); + bool getBigEndian(); + void setBigEndian(bool a0); + jbyteArray getHb(); + bool getIsReadOnly(); + void setIsReadOnly(bool a0); + bool getNativeByteOrder(); + void setNativeByteOrder(bool a0); + int32_t getOffset(); + ByteBuffer() : AutoGlobalWrappedJavaObject() {}; +protected: + static jclass mByteBufferClass; + static jmethodID j_get; + static jmethodID j_put; + static jmethodID jAllocate; + static jmethodID jAllocateDirect; + static jmethodID jArray; + static jmethodID jArray1; + static jmethodID jArrayOffset; + static jmethodID jAsCharBuffer; + static jmethodID jAsDoubleBuffer; + static jmethodID jAsFloatBuffer; + static jmethodID jAsIntBuffer; + static jmethodID jAsLongBuffer; + static jmethodID jAsReadOnlyBuffer; + static jmethodID jAsShortBuffer; + static jmethodID jCompact; + static jmethodID jCompareTo; + static jmethodID jCompareTo1; + static jmethodID jDuplicate; + static jmethodID jEquals; + static jmethodID jGet; + static jmethodID jGet1; + static jmethodID jGet10; + static jmethodID jGet11; + static jmethodID jGetChar; + static jmethodID jGetChar1; + static jmethodID jGetDouble; + static jmethodID jGetDouble1; + static jmethodID jGetFloat; + static jmethodID jGetFloat1; + static jmethodID jGetInt; + static jmethodID jGetInt1; + static jmethodID jGetLong; + static jmethodID jGetLong1; + static jmethodID jGetShort; + static jmethodID jGetShort1; + static jmethodID jHasArray; + static jmethodID jHashCode; + static jmethodID jIsDirect; + static jmethodID jOrder; + static jmethodID jOrder1; + static jmethodID jPut; + static jmethodID jPut1; + static jmethodID jPut12; + static jmethodID jPut13; + static jmethodID jPut14; + static jmethodID jPutChar; + static jmethodID jPutChar1; + static jmethodID jPutDouble; + static jmethodID jPutDouble1; + static jmethodID jPutFloat; + static jmethodID jPutFloat1; + static jmethodID jPutInt; + static jmethodID jPutInt1; + static jmethodID jPutLong; + static jmethodID jPutLong1; + static jmethodID jPutShort; + static jmethodID jPutShort1; + static jmethodID jSlice; + static jmethodID jToString; + static jmethodID jWrap; + static jmethodID jWrap1; + static jfieldID jBigEndian; + static jfieldID jHb; + static jfieldID jIsReadOnly; + static jfieldID jNativeByteOrder; + static jfieldID jOffset; +}; + +class BufferInfo : public AutoGlobalWrappedJavaObject { +public: + static void InitStubs(JNIEnv *jEnv); + static BufferInfo* Wrap(jobject obj); + BufferInfo(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {}; + BufferInfo(); + void Set(int32_t a0, int32_t a1, int64_t a2, int32_t a3); + int32_t getFlags(); + void setFlags(int32_t a0); + int32_t getOffset(); + void setOffset(int32_t a0); + int64_t getPresentationTimeUs(); + void setPresentationTimeUs(int64_t a0); + int32_t getSize(); + void setSize(int32_t a0); +protected: + static jclass mBufferInfoClass; + static jmethodID jBufferInfo; + static jmethodID jSet; + static jfieldID jFlags; + static jfieldID jOffset; + static jfieldID jPresentationTimeUs; + static jfieldID jSize; +}; + +} /* android */ +} /* widget */ +} /* mozilla */ +#endif diff --git a/widget/android/bindings/Makefile.in b/widget/android/bindings/Makefile.in deleted file mode 100644 index 8a069f18f1cc..000000000000 --- a/widget/android/bindings/Makefile.in +++ /dev/null @@ -1,26 +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/. - -ANNOTATION_PROCESSOR_JAR_FILES := $(DEPTH)/build/annotationProcessors/annotationProcessors.jar:$(ANDROID_SDK)/android.jar:$(ANDROID_SDK)/../../tools/lib/lint.jar:$(ANDROID_SDK)/../../tools/lib/lint-checks.jar - -MediaCodec.cpp: $(ANDROID_SDK)/android.jar mediacodec-classes.txt - $(JAVA) -classpath $(ANNOTATION_PROCESSOR_JAR_FILES) org.mozilla.gecko.annotationProcessors.SDKProcessor $(ANDROID_SDK)/android.jar $(srcdir)/mediacodec-classes.txt $(CURDIR) MediaCodec 16 - -MediaCodec.h: MediaCodec.cpp ; - -SurfaceTexture.cpp: $(ANDROID_SDK)/android.jar surfacetexture-classes.txt - $(JAVA) -classpath $(ANNOTATION_PROCESSOR_JAR_FILES) org.mozilla.gecko.annotationProcessors.SDKProcessor $(ANDROID_SDK)/android.jar $(srcdir)/surfacetexture-classes.txt $(CURDIR) SurfaceTexture 16 - -SurfaceTexture.h: SurfaceTexture.cpp ; - -# We'd like these to be defined in a future GENERATED_EXPORTS list. -bindings_exports := \ - MediaCodec.h \ - SurfaceTexture.h \ - $(NULL) - -INSTALL_TARGETS += bindings_exports -bindings_exports_FILES := $(bindings_exports) -bindings_exports_DEST = $(DIST)/include -bindings_exports_TARGET := export diff --git a/widget/android/bindings/mediacodec-classes.txt b/widget/android/bindings/mediacodec-classes.txt deleted file mode 100644 index d8fb3420d3d5..000000000000 --- a/widget/android/bindings/mediacodec-classes.txt +++ /dev/null @@ -1,3 +0,0 @@ -android.media.MediaCodec -android.media.MediaCodec$BufferInfo -android.media.MediaFormat diff --git a/widget/android/bindings/moz.build b/widget/android/bindings/moz.build deleted file mode 100644 index c446a76bac36..000000000000 --- a/widget/android/bindings/moz.build +++ /dev/null @@ -1,24 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -GENERATED_SOURCES += [ - 'MediaCodec.cpp', - 'SurfaceTexture.cpp', -] - -# We'd like to add these to a future GENERATED_EXPORTS list, but for now we mark -# them as generated here and manually install them in Makefile.in. -GENERATED_INCLUDES += [ - 'MediaCodec.h', - 'SurfaceTexture.h', -] - -FAIL_ON_WARNINGS = True -FINAL_LIBRARY = 'xul' - -LOCAL_INCLUDES += [ - '/widget/android', -] diff --git a/widget/android/bindings/surfacetexture-classes.txt b/widget/android/bindings/surfacetexture-classes.txt deleted file mode 100644 index 5c7ca8968860..000000000000 --- a/widget/android/bindings/surfacetexture-classes.txt +++ /dev/null @@ -1,2 +0,0 @@ -android.graphics.SurfaceTexture -android.view.Surface diff --git a/widget/android/moz.build b/widget/android/moz.build index dee4c7e2f41c..78873655b283 100644 --- a/widget/android/moz.build +++ b/widget/android/moz.build @@ -4,10 +4,6 @@ # 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/. -DIRS += [ - 'bindings', -] - XPIDL_SOURCES += [ 'nsIAndroidBridge.idl', ] @@ -19,6 +15,7 @@ EXPORTS += [ 'AndroidJavaWrappers.h', 'AndroidJNIWrapper.h', 'GeneratedJNIWrappers.h', + 'GeneratedSDKWrappers.h', ] SOURCES += [ @@ -30,6 +27,7 @@ SOURCES += [ 'AndroidJNIWrapper.cpp', 'APZCCallbackHandler.cpp', 'GeneratedJNIWrappers.cpp', + 'GeneratedSDKWrappers.cpp', 'GfxInfo.cpp', 'NativeJSContainer.cpp', 'nsAndroidProtocolHandler.cpp',