Bug 917958 part 1. Stop using JSObject* to represent WebIDL callback functions in workers. r=smaug

This commit is contained in:
Boris Zbarsky 2013-09-20 01:07:03 -04:00
parent 14d8b1d3f9
commit 7370c94e13
7 changed files with 89 additions and 72 deletions

View File

@ -3502,28 +3502,13 @@ for (uint32_t i = 0; i < length; ++i) {
assert not isEnforceRange and not isClamp
assert not type.treatNonCallableAsNull() or type.nullable()
if descriptorProvider.workers:
if isMember:
raise NoSuchDescriptorError("Can't handle member callbacks in "
"workers; need to sort out rooting"
"issues")
if isOptional:
# We have a specialization of Optional that will use a
# Rooted for the storage here.
declType = CGGeneric("JS::Handle<JSObject*>")
else:
declType = CGGeneric("JS::Rooted<JSObject*>")
conversion = " ${declName} = &${val}.toObject();\n"
declArgs = "cx"
name = type.unroll().identifier.name
if type.nullable():
declType = CGGeneric("nsRefPtr<%s>" % name);
else:
name = type.unroll().identifier.name
if type.nullable():
declType = CGGeneric("nsRefPtr<%s>" % name);
else:
declType = CGGeneric("OwningNonNull<%s>" % name)
conversion = (
" ${declName} = new %s(&${val}.toObject());\n" % name)
declArgs = None
declType = CGGeneric("OwningNonNull<%s>" % name)
conversion = (
" ${declName} = new %s(&${val}.toObject());\n" % name)
if allowTreatNonCallableAsNull and type.treatNonCallableAsNull():
haveCallable = "JS_ObjectIsCallable(cx, &${val}.toObject())"
@ -3549,8 +3534,7 @@ for (uint32_t i = 0; i < length; ++i) {
"${declName} = nullptr",
failureCode)
return JSToNativeConversionInfo(template, declType=declType,
dealWithOptional=isOptional,
declArgs=declArgs)
dealWithOptional=isOptional)
if type.isAny():
assert not isEnforceRange and not isClamp
@ -4204,14 +4188,6 @@ if (!returnArray) {
return conversion, False
if type.isCallback() or type.isCallbackInterface():
# See comments in WrapNewBindingObject explaining why we need
# to wrap here.
# NB: setValue(..., True) calls JS_WrapValue(), so is fallible
if descriptorProvider.workers:
return (setValue("JS::ObjectOrNullValue(%s)" % result,
"objectOrNull"),
False)
wrapCode = setValue(
"JS::ObjectValue(*GetCallbackFromCallbackObject(%(result)s))",
"object")
@ -4366,8 +4342,7 @@ def infallibleForMember(member, type, descriptorProvider):
def leafTypeNeedsCx(type, descriptorProvider, retVal):
return (type.isAny() or type.isObject() or
(retVal and type.isSpiderMonkeyInterface()) or
(descriptorProvider.workers and type.isCallback()))
(retVal and type.isSpiderMonkeyInterface()))
def leafTypeNeedsScopeObject(type, descriptorProvider, retVal):
return (retVal and type.isSpiderMonkeyInterface())
@ -4458,8 +4433,6 @@ def getRetvalDeclarationForType(returnType, descriptorProvider,
return result, False, None, None
if returnType.isCallback():
name = returnType.unroll().identifier.name
if descriptorProvider.workers:
return CGGeneric("JSObject*"), False, None, None
return CGGeneric("nsRefPtr<%s>" % name), False, None, None
if returnType.isAny():
return CGGeneric("JS::Value"), False, None, None

View File

@ -5,11 +5,13 @@
#include "EventTarget.h"
#include "mozilla/dom/EventListenerBinding.h"
#include "mozilla/dom/EventHandlerBinding.h"
USING_WORKERS_NAMESPACE
using mozilla::ErrorResult;
using mozilla::dom::EventListener;
using mozilla::dom::Nullable;
using mozilla::dom::EventHandlerNonNull;
void
EventTarget::_trace(JSTracer* aTrc)
@ -25,7 +27,7 @@ EventTarget::_finalize(JSFreeOp* aFop)
DOMBindingBase::_finalize(aFop);
}
JSObject*
already_AddRefed<EventHandlerNonNull>
EventTarget::GetEventListener(const nsAString& aType, ErrorResult& aRv) const
{
JSContext* cx = GetJSContext();
@ -34,15 +36,22 @@ EventTarget::GetEventListener(const nsAString& aType, ErrorResult& aRv) const
JS_NewUCStringCopyN(cx, aType.BeginReading(), aType.Length()));
if (!type || !(type = JS_InternJSString(cx, type))) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return NULL;
return nullptr;
}
return mListenerManager.GetEventListener(INTERNED_STRING_TO_JSID(cx, type));
JS::RootedObject listener(
cx, mListenerManager.GetEventListener(INTERNED_STRING_TO_JSID(cx, type)));
if (!listener) {
return nullptr;
}
nsRefPtr<EventHandlerNonNull> handler = new EventHandlerNonNull(listener);
return handler.forget();
}
void
EventTarget::SetEventListener(const nsAString& aType,
JS::Handle<JSObject*> aListener,
EventHandlerNonNull* aListener,
ErrorResult& aRv)
{
JSContext* cx = GetJSContext();
@ -54,8 +63,12 @@ EventTarget::SetEventListener(const nsAString& aType,
return;
}
JS::RootedObject listener(cx);
if (aListener) {
listener = aListener->Callable();
}
mListenerManager.SetEventListener(cx, INTERNED_STRING_TO_JSID(cx, type),
aListener, aRv);
listener, aRv);
}
void

View File

@ -17,6 +17,7 @@
namespace mozilla {
namespace dom {
class EventListener;
class EventHandlerNonNull;
} // namespace mozilla
} // namespace dom
@ -56,11 +57,11 @@ public:
return mListenerManager.DispatchEvent(GetJSContext(), *this, aEvent, aRv);
}
JSObject*
already_AddRefed<EventHandlerNonNull>
GetEventListener(const nsAString& aType, ErrorResult& aRv) const;
void
SetEventListener(const nsAString& aType, JS::Handle<JSObject*> aListener,
SetEventListener(const nsAString& aType, EventHandlerNonNull* aListener,
ErrorResult& aRv);
bool
@ -69,13 +70,14 @@ public:
return mListenerManager.HasListeners();
}
void SetEventHandler(JSContext*, const nsAString& aType, JSObject* aHandler,
void SetEventHandler(const nsAString& aType, EventHandlerNonNull* aHandler,
ErrorResult& rv)
{
rv.Throw(NS_ERROR_NOT_IMPLEMENTED);
}
JSObject* GetEventHandler(JSContext*, const nsAString& aType)
EventHandlerNonNull*
GetEventHandler(const nsAString& aType)
{
return nullptr;
}

View File

@ -7,6 +7,7 @@
#include "mozilla/dom/DOMJSClass.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/EventHandlerBinding.h"
#include "jsapi.h"
#include "EventTarget.h"
@ -179,14 +180,19 @@ private:
MOZ_ASSERT(worker);
ErrorResult rv;
JS::Rooted<JSObject*> listener(aCx, worker->GetEventListener(Substring(aNameStr, 2), rv));
nsRefPtr<EventHandlerNonNull> handler =
worker->GetEventListener(Substring(aNameStr, 2), rv);
if (rv.Failed()) {
JS_ReportError(aCx, "Failed to get listener!");
return false;
}
aArgs.rval().setObjectOrNull(listener);
if (!handler) {
aArgs.rval().setNull();
} else {
aArgs.rval().setObject(*handler->Callable());
}
return true;
}
@ -230,8 +236,14 @@ private:
return false;
}
nsRefPtr<EventHandlerNonNull> handler;
if (listener && JS_ObjectIsCallable(aCx, listener)) {
handler = new EventHandlerNonNull(listener);
} else {
handler = nullptr;
}
ErrorResult rv;
worker->SetEventListener(Substring(aNameStr, 2), listener, rv);
worker->SetEventListener(Substring(aNameStr, 2), handler, rv);
if (rv.Failed()) {
JS_ReportError(aCx, "Failed to set listener!");

View File

@ -11,6 +11,7 @@
#include "mozilla/Util.h"
#include "mozilla/dom/DOMJSClass.h"
#include "mozilla/dom/EventBinding.h"
#include "mozilla/dom/EventHandlerBinding.h"
#include "mozilla/dom/EventTargetBinding.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/DOMExceptionBinding.h"
@ -163,8 +164,7 @@ private:
MOZ_ASSERT(scope);
ErrorResult rv;
JSObject* listener =
nsRefPtr<EventHandlerNonNull> handler =
scope->GetEventListener(NS_ConvertASCIItoUTF16(name + 2), rv);
if (rv.Failed()) {
@ -172,7 +172,11 @@ private:
return false;
}
aArgs.rval().setObjectOrNull(listener);
if (!handler) {
aArgs.rval().setNull();
} else {
aArgs.rval().setObject(*handler->Callable());
}
return true;
}
@ -191,15 +195,21 @@ private:
GetInstancePrivate(aCx, &aArgs.thisv().toObject(), name);
MOZ_ASSERT(scope);
if (aArgs.length() == 0 || !aArgs[0].isObject()) {
if (aArgs.length() == 0 || !aArgs[0].isObjectOrNull()) {
JS_ReportError(aCx, "Not an event listener!");
return false;
}
ErrorResult rv;
JS::Rooted<JSObject*> listenerObj(aCx, &aArgs[0].toObject());
JS::Rooted<JSObject*> listenerObj(aCx, aArgs[0].toObjectOrNull());
nsRefPtr<EventHandlerNonNull> handler;
if (listenerObj && JS_ObjectIsCallable(aCx, listenerObj)) {
handler = new EventHandlerNonNull(listenerObj);
} else {
handler = nullptr;
}
scope->SetEventListener(NS_ConvertASCIItoUTF16(name + 2),
listenerObj, rv);
handler, rv);
if (rv.Failed()) {
JS_ReportError(aCx, "Failed to set event listener!");
return false;
@ -319,8 +329,7 @@ private:
MOZ_ASSERT(scope);
ErrorResult rv;
JSObject* adaptor =
nsRefPtr<EventHandlerNonNull> adaptor =
scope->GetEventListener(NS_ConvertASCIItoUTF16(name + 2), rv);
if (rv.Failed()) {
@ -333,7 +342,8 @@ private:
return true;
}
aArgs.rval().set(js::GetFunctionNativeReserved(adaptor, SLOT_wrappedFunction));
aArgs.rval().set(js::GetFunctionNativeReserved(adaptor->Callable(),
SLOT_wrappedFunction));
MOZ_ASSERT(aArgs.rval().isObject());
return true;
}
@ -375,8 +385,8 @@ private:
js::SetFunctionNativeReserved(listener, SLOT_wrappedFunction, aArgs[0]);
ErrorResult rv;
scope->SetEventListener(NS_ConvertASCIItoUTF16(name + 2), listener, rv);
nsRefPtr<EventHandlerNonNull> handler = new EventHandlerNonNull(listener);
scope->SetEventListener(NS_ConvertASCIItoUTF16(name + 2), handler, rv);
if (rv.Failed()) {
JS_ReportError(aCx, "Failed to set event listener!");
@ -787,8 +797,7 @@ private:
MOZ_ASSERT(scope);
ErrorResult rv;
JSObject* listener =
nsRefPtr<EventHandlerNonNull> handler =
scope->GetEventListener(NS_ConvertASCIItoUTF16(name + 2), rv);
if (rv.Failed()) {
@ -796,7 +805,11 @@ private:
return false;
}
aArgs.rval().setObjectOrNull(listener);
if (!handler) {
aArgs.rval().setNull();
} else {
aArgs.rval().setObject(*handler->Callable());
}
return true;
}
@ -815,16 +828,22 @@ private:
GetInstancePrivate(aCx, &aArgs.thisv().toObject(), name);
MOZ_ASSERT(scope);
if (aArgs.length() == 0 || !aArgs[0].isObject()) {
if (aArgs.length() == 0 || !aArgs[0].isObjectOrNull()) {
JS_ReportError(aCx, "Not an event listener!");
return false;
}
ErrorResult rv;
JS::Rooted<JSObject*> listenerObj(aCx, &aArgs[0].toObject());
JS::Rooted<JSObject*> listenerObj(aCx, aArgs[0].toObjectOrNull());
nsRefPtr<EventHandlerNonNull> handler;
if (listenerObj && JS_ObjectIsCallable(aCx, listenerObj)) {
handler = new EventHandlerNonNull(listenerObj);
} else {
handler = nullptr;
}
scope->SetEventListener(NS_ConvertASCIItoUTF16(name + 2),
listenerObj, rv);
handler, rv);
if (rv.Failed()) {
JS_ReportError(aCx, "Failed to set event listener!");

View File

@ -99,15 +99,14 @@ public:
Notify(JSContext* aCx, Status aStatus) MOZ_OVERRIDE;
#define IMPL_GETTER_AND_SETTER(_type) \
JSObject* \
GetOn##_type(JSContext* /* unused */, ErrorResult& aRv) \
already_AddRefed<EventHandlerNonNull> \
GetOn##_type(ErrorResult& aRv) \
{ \
return GetEventListener(NS_LITERAL_STRING(#_type), aRv); \
} \
\
void \
SetOn##_type(JSContext* /* unused */, JS::Handle<JSObject*> aListener, \
ErrorResult& aRv) \
SetOn##_type(EventHandlerNonNull* aListener, ErrorResult& aRv) \
{ \
SetEventListener(NS_LITERAL_STRING(#_type), aListener, aRv); \
}

View File

@ -28,15 +28,14 @@ public:
_finalize(JSFreeOp* aFop) MOZ_OVERRIDE;
#define IMPL_GETTER_AND_SETTER(_type) \
JSObject* \
GetOn##_type(JSContext* /* unused */, ErrorResult& aRv) \
already_AddRefed<EventHandlerNonNull> \
GetOn##_type(ErrorResult& aRv) \
{ \
return GetEventListener(NS_LITERAL_STRING(#_type), aRv); \
} \
\
void \
SetOn##_type(JSContext* /* unused */, JS::Handle<JSObject*> aListener, \
ErrorResult& aRv) \
SetOn##_type(EventHandlerNonNull* aListener, ErrorResult& aRv) \
{ \
SetEventListener(NS_LITERAL_STRING(#_type), aListener, aRv); \
}