Make XPCNativeWrapper call the wrapped native's classinfo resolve/get/set

hooks.  Makes native wrappers work in lots of nasty DOM0 corner cases.  Bug
296967, r=mrbkap, sr=jst, a=asa
This commit is contained in:
bzbarsky%mit.edu 2005-07-29 15:11:08 +00:00
Родитель 9526108fcc
Коммит 31c1cac564
9 изменённых файлов: 389 добавлений и 176 удалений

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

@ -637,7 +637,7 @@ calDateTime::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
*vp = OBJECT_TO_JSVAL(obj);
*_retval = PR_TRUE;
return NS_OK;
return NS_SUCCESS_I_DID_SOMETHING;
}
}
@ -675,7 +675,7 @@ calDateTime::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
}
*_retval = PR_TRUE;
return NS_OK;
return NS_SUCCESS_I_DID_SOMETHING;
}
}
*_retval = PR_TRUE;

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

@ -1098,9 +1098,21 @@ jsval nsDOMClassInfo::sTags_id = JSVAL_VOID;
jsval nsDOMClassInfo::sAddEventListener_id= JSVAL_VOID;
const JSClass *nsDOMClassInfo::sObjectClass = nsnull;
const JSClass *nsDOMClassInfo::sXPCNativeWrapperClass = nsnull;
PRBool nsDOMClassInfo::sDoSecurityCheckInAddProperty = PR_TRUE;
const JSClass*
NS_DOMClassInfo_GetXPCNativeWrapperClass()
{
return nsDOMClassInfo::GetXPCNativeWrapperClass();
}
void
NS_DOMClassInfo_SetXPCNativeWrapperClass(JSClass* aClass)
{
nsDOMClassInfo::SetXPCNativeWrapperClass(aClass);
}
static void
PrintWarningOnConsole(JSContext *cx, const char *stringBundleProperty)
@ -3794,7 +3806,7 @@ nsWindowSH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
NS_GET_IID(nsIDOMWindow), vp);
}
return rv;
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
}
if (needsSecurityCheck(cx, wrapper)) {
@ -3820,7 +3832,7 @@ nsWindowSH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
// Yup, *vp is a window object, return early (*vp is already
// the window, so no need to wrap it again).
return NS_OK;
return NS_SUCCESS_I_DID_SOMETHING;
}
}
}
@ -3877,7 +3889,8 @@ nsWindowSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
rv = location->SetHref(nsDependentJSString(val));
NS_ENSURE_SUCCESS(rv, rv);
return WrapNative(cx, obj, location, NS_GET_IID(nsIDOMLocation), vp);
rv = WrapNative(cx, obj, location, NS_GET_IID(nsIDOMLocation), vp);
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
}
return nsEventReceiverSH::SetProperty(wrapper, cx, obj, id, vp, _retval);
@ -5754,6 +5767,10 @@ nsEventReceiverSH::RegisterCompileHandler(nsIXPConnectWrappedNative *wrapper,
return NS_OK;
}
if (ObjectIsNativeWrapper(cx, obj)) {
return NS_ERROR_NOT_AVAILABLE;
}
nsIScriptContext *script_cx = nsJSUtils::GetStaticScriptContext(cx, obj);
NS_ENSURE_TRUE(script_cx, NS_ERROR_UNEXPECTED);
@ -5778,7 +5795,7 @@ nsEventReceiverSH::RegisterCompileHandler(nsIXPConnectWrappedNative *wrapper,
rv = manager->RegisterScriptEventListener(script_cx, receiver, atom);
}
return rv;
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
}
NS_IMETHODIMP
@ -5990,6 +6007,8 @@ nsArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
PRBool is_number = PR_FALSE;
PRInt32 n = GetArrayIndexFromId(cx, id, &is_number);
nsresult rv = NS_OK;
if (is_number) {
if (n < 0) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
@ -5997,17 +6016,19 @@ nsArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
nsCOMPtr<nsISupports> array_item;
nsresult rv = GetItemAt(wrapper->Native(), n, getter_AddRefs(array_item));
rv = GetItemAt(wrapper->Native(), n, getter_AddRefs(array_item));
NS_ENSURE_SUCCESS(rv, rv);
if (array_item) {
rv = WrapNative(cx, ::JS_GetGlobalObject(cx), array_item,
NS_GET_IID(nsISupports), vp);
NS_ENSURE_SUCCESS(rv, rv);
rv = NS_SUCCESS_I_DID_SOMETHING;
}
}
return NS_OK;
return rv;
}
@ -6041,9 +6062,11 @@ nsNamedArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
rv = WrapNative(cx, ::JS_GetGlobalObject(cx), item,
NS_GET_IID(nsISupports), vp);
NS_ENSURE_SUCCESS(rv, rv);
rv = NS_SUCCESS_I_DID_SOMETHING;
}
return NS_OK; // Don't fall through to nsArraySH::GetProperty() here
return rv; // Don't fall through to nsArraySH::GetProperty() here
}
return nsArraySH::GetProperty(wrapper, cx, obj, id, vp, _retval);
@ -6410,7 +6433,8 @@ nsDocumentSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
rv = location->SetHref(nsDependentJSString(val));
NS_ENSURE_SUCCESS(rv, rv);
return WrapNative(cx, obj, location, NS_GET_IID(nsIDOMLocation), vp);
rv = WrapNative(cx, obj, location, NS_GET_IID(nsIDOMLocation), vp);
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
}
}
@ -7074,7 +7098,8 @@ nsHTMLDocumentSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
return fnc ? NS_OK : NS_ERROR_UNEXPECTED;
}
if (id == sAll_id && !sDisableDocumentAllSupport) {
if (id == sAll_id && !sDisableDocumentAllSupport &&
!ObjectIsNativeWrapper(cx, obj)) {
nsCOMPtr<nsIHTMLDocument> doc(do_QueryWrappedNative(wrapper));
if (doc->GetCompatibilityMode() == eCompatibility_NavQuirks) {
@ -7164,11 +7189,14 @@ nsHTMLDocumentSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
NS_ENSURE_SUCCESS(rv, rv);
if (result) {
return WrapNative(cx, ::JS_GetGlobalObject(cx), result,
NS_GET_IID(nsISupports), vp);
rv = WrapNative(cx, ::JS_GetGlobalObject(cx), result,
NS_GET_IID(nsISupports), vp);
if (NS_SUCCEEDED(rv)) {
rv = NS_SUCCESS_I_DID_SOMETHING;
}
}
return NS_OK;
return rv;
}
// HTMLElement helper
@ -7297,8 +7325,9 @@ nsHTMLFormElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
if (result) {
// Wrap result, result can be either an element or a list of
// elements
return WrapNative(cx, ::JS_GetGlobalObject(cx), result,
NS_GET_IID(nsISupports), vp);
nsresult rv = WrapNative(cx, ::JS_GetGlobalObject(cx), result,
NS_GET_IID(nsISupports), vp);
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
}
return NS_OK; // Don't fall through
@ -7311,8 +7340,9 @@ nsHTMLFormElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
form->GetElementAt(n, getter_AddRefs(control));
if (control) {
return WrapNative(cx, ::JS_GetGlobalObject(cx), control,
NS_GET_IID(nsISupports), vp);
nsresult rv = WrapNative(cx, ::JS_GetGlobalObject(cx), control,
NS_GET_IID(nsISupports), vp);
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
}
}
@ -7404,6 +7434,7 @@ nsHTMLSelectElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
{
PRInt32 n = GetArrayIndexFromId(cx, id);
nsresult rv = NS_OK;
if (n >= 0) {
nsCOMPtr<nsIDOMHTMLSelectElement> s(do_QueryWrappedNative(wrapper));
@ -7415,12 +7446,15 @@ nsHTMLSelectElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
options->Item(n, getter_AddRefs(node));
return WrapNative(cx, ::JS_GetGlobalObject(cx), node,
NS_GET_IID(nsIDOMNode), vp);
rv = WrapNative(cx, ::JS_GetGlobalObject(cx), node,
NS_GET_IID(nsIDOMNode), vp);
if (NS_SUCCEEDED(rv)) {
rv = NS_SUCCESS_I_DID_SOMETHING;
}
}
}
return NS_OK;
return rv;
}
// static
@ -7473,7 +7507,8 @@ nsHTMLSelectElementSH::SetProperty(nsIXPConnectWrappedNative *wrapper,
nsCOMPtr<nsIDOMNSHTMLOptionCollection> oc(do_QueryInterface(options));
NS_ENSURE_TRUE(oc, NS_ERROR_UNEXPECTED);
return SetOption(cx, vp, n, oc);
nsresult rv = SetOption(cx, vp, n, oc);
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
}
return nsElementSH::SetProperty(wrapper, cx, obj, id, vp, _retval);
@ -7692,21 +7727,23 @@ nsHTMLExternalObjSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
const jschar *id_chars = nsnull;
size_t id_length = 0;
JSBool found;
JSBool found = PR_FALSE;
if (JSVAL_IS_STRING(id)) {
JSString *id_str = JSVAL_TO_STRING(id);
if (!ObjectIsNativeWrapper(cx, obj)) {
if (JSVAL_IS_STRING(id)) {
JSString *id_str = JSVAL_TO_STRING(id);
id_chars = ::JS_GetStringChars(id_str);
id_length = ::JS_GetStringLength(id_str);
id_chars = ::JS_GetStringChars(id_str);
id_length = ::JS_GetStringLength(id_str);
*_retval = ::JS_HasUCProperty(cx, pi_obj, id_chars, id_length, &found);
} else {
*_retval = JS_HasElement(cx, pi_obj, JSVAL_TO_INT(id), &found);
}
*_retval = ::JS_HasUCProperty(cx, pi_obj, id_chars, id_length, &found);
} else {
*_retval = JS_HasElement(cx, pi_obj, JSVAL_TO_INT(id), &found);
}
if (!*_retval) {
return NS_ERROR_UNEXPECTED;
if (!*_retval) {
return NS_ERROR_UNEXPECTED;
}
}
if (found) {
@ -7716,7 +7753,7 @@ nsHTMLExternalObjSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
*_retval = ::JS_GetElement(cx, pi_obj, JSVAL_TO_INT(id), vp);
}
return *_retval ? NS_OK : NS_ERROR_FAILURE;
return *_retval ? NS_SUCCESS_I_DID_SOMETHING : NS_ERROR_FAILURE;
}
return nsElementSH::GetProperty(wrapper, cx, obj, id, vp, _retval);
@ -7732,21 +7769,23 @@ nsHTMLExternalObjSH::SetProperty(nsIXPConnectWrappedNative *wrapper,
const jschar *id_chars = nsnull;
size_t id_length = 0;
JSBool found;
JSBool found = PR_FALSE;
if (JSVAL_IS_STRING(id)) {
JSString *id_str = JSVAL_TO_STRING(id);
if (!ObjectIsNativeWrapper(cx, obj)) {
if (JSVAL_IS_STRING(id)) {
JSString *id_str = JSVAL_TO_STRING(id);
id_chars = ::JS_GetStringChars(id_str);
id_length = ::JS_GetStringLength(id_str);
id_chars = ::JS_GetStringChars(id_str);
id_length = ::JS_GetStringLength(id_str);
*_retval = ::JS_HasUCProperty(cx, pi_obj, id_chars, id_length, &found);
} else {
*_retval = JS_HasElement(cx, pi_obj, JSVAL_TO_INT(id), &found);
}
*_retval = ::JS_HasUCProperty(cx, pi_obj, id_chars, id_length, &found);
} else {
*_retval = JS_HasElement(cx, pi_obj, JSVAL_TO_INT(id), &found);
}
if (!*_retval) {
return NS_ERROR_UNEXPECTED;
if (!*_retval) {
return NS_ERROR_UNEXPECTED;
}
}
if (found) {
@ -7756,7 +7795,7 @@ nsHTMLExternalObjSH::SetProperty(nsIXPConnectWrappedNative *wrapper,
*_retval = ::JS_SetElement(cx, pi_obj, JSVAL_TO_INT(id), vp);
}
return *_retval ? NS_OK : NS_ERROR_FAILURE;
return *_retval ? NS_SUCCESS_I_DID_SOMETHING : NS_ERROR_FAILURE;
}
return nsElementSH::SetProperty(wrapper, cx, obj, id, vp, _retval);
@ -8050,7 +8089,11 @@ nsHTMLOptionsCollectionSH::SetProperty(nsIXPConnectWrappedNative *wrapper,
nsCOMPtr<nsIDOMNSHTMLOptionCollection> oc(do_QueryWrappedNative(wrapper));
NS_ENSURE_TRUE(oc, NS_ERROR_UNEXPECTED);
return nsHTMLSelectElementSH::SetOption(cx, vp, n, oc);
nsresult rv = nsHTMLSelectElementSH::SetOption(cx, vp, n, oc);
if (NS_SUCCEEDED(rv)) {
rv = NS_SUCCESS_I_DID_SOMETHING;
}
return rv;
}
NS_IMETHODIMP
@ -8280,7 +8323,7 @@ nsStringArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
*vp = STRING_TO_JSVAL(str);
return NS_OK;
return NS_SUCCESS_I_DID_SOMETHING;
}

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

@ -135,6 +135,29 @@ public:
static JSClass sDOMJSClass;
/**
* Get our JSClass pointer for the XPCNativeWrapper class
*/
static const JSClass* GetXPCNativeWrapperClass() {
return sXPCNativeWrapperClass;
}
/**
* Set our JSClass pointer for the XPCNativeWrapper class
*/
static void SetXPCNativeWrapperClass(JSClass* aClass) {
NS_ASSERTION(!sXPCNativeWrapperClass,
"Double set of sXPCNativeWrapperClass");
sXPCNativeWrapperClass = aClass;
}
static PRBool ObjectIsNativeWrapper(JSContext* cx, JSObject* obj)
{
NS_PRECONDITION(sXPCNativeWrapperClass,
"Must know what the XPCNativeWrapper class is!");
return ::JS_GetClass(cx, obj) == sXPCNativeWrapperClass;
}
/**
* Note that the XPConnect wrapper should be preserved. This will only
* preserve aWrapper if its native QIs to nsIDOMNode; otherwise it'll just
@ -306,6 +329,7 @@ protected:
static jsval sAddEventListener_id;
static const JSClass *sObjectClass;
static const JSClass *sXPCNativeWrapperClass;
static PRBool sDoSecurityCheckInAddProperty;
};

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

@ -1511,6 +1511,8 @@ nsJSContext::GetNativeContext()
return mContext;
}
const JSClass* NS_DOMClassInfo_GetXPCNativeWrapperClass();
void NS_DOMClassInfo_SetXPCNativeWrapperClass(JSClass* aClass);
nsresult
nsJSContext::InitContext(nsIScriptGlobalObject *aGlobalObject)
@ -1571,6 +1573,13 @@ nsJSContext::InitContext(nsIScriptGlobalObject *aGlobalObject)
flags,
getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
// Now check whether we need to grab a pointer to the
// XPCNativeWrapper class
if (!NS_DOMClassInfo_GetXPCNativeWrapperClass()) {
rv = FindXPCNativeWrapperClass(holder);
NS_ENSURE_SUCCESS(rv, rv);
}
} else {
// If there's already a global object in mContext we're called
// after ::JS_ClearScope() was called. We'll have to tell XPConnect
@ -1645,6 +1654,51 @@ nsJSContext::InitializeLiveConnectClasses()
return NS_OK;
}
nsresult
nsJSContext::FindXPCNativeWrapperClass(nsIXPConnectJSObjectHolder *aHolder)
{
NS_ASSERTION(!NS_DOMClassInfo_GetXPCNativeWrapperClass(),
"Why was this called?");
JSObject *globalObj;
aHolder->GetJSObject(&globalObj);
NS_ASSERTION(globalObj, "Must have global by now!");
const char* arg = "arg";
NS_NAMED_LITERAL_STRING(body, "return new XPCNativeWrapper(arg);");
// Can't use CompileFunction() here because our principal isn't
// inited yet and a null principal makes it fail.
JSFunction *fun =
::JS_CompileUCFunction(mContext,
globalObj,
"_XPCNativeWrapperCtor",
1, &arg,
(jschar*)body.get(),
body.Length(),
"javascript:return new XPCNativeWrapper(arg);",
1 // lineno
);
NS_ENSURE_TRUE(fun, NS_ERROR_FAILURE);
jsval globalVal = OBJECT_TO_JSVAL(globalObj);
jsval wrapper;
JSBool ok = ::JS_CallFunction(mContext, globalObj, fun,
1, &globalVal, &wrapper);
if (!ok) {
// No need to notify about pending exceptions here; we don't
// expect any other than out of memory, really.
return NS_ERROR_FAILURE;
}
NS_ASSERTION(JSVAL_IS_OBJECT(wrapper), "This should be an object!");
NS_DOMClassInfo_SetXPCNativeWrapperClass(
::JS_GetClass(mContext, JSVAL_TO_OBJECT(wrapper)));
return NS_OK;
}
static JSPropertySpec OptionsProperties[] = {
{"strict", JSOPTION_STRICT, JSPROP_ENUMERATE | JSPROP_PERMANENT},
{"werror", JSOPTION_WERROR, JSPROP_ENUMERATE | JSPROP_PERMANENT},

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

@ -46,7 +46,7 @@
#include "nsIXPCScriptNotify.h"
#include "nsITimer.h"
#include "prtime.h"
class nsIXPConnectJSObjectHolder;
class nsJSContext : public nsIScriptContext,
public nsIXPCScriptNotify,
@ -138,6 +138,8 @@ protected:
nsresult InitClasses();
nsresult InitializeExternalClasses();
nsresult InitializeLiveConnectClasses();
// aHolder should be holding our global object
nsresult FindXPCNativeWrapperClass(nsIXPConnectJSObjectHolder *aHolder);
void FireGCTimer();

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

@ -137,6 +137,7 @@ nsSOAPPropertyBag::GetProperty(nsIXPConnectWrappedNative * wrapper,
JSContext * cx, JSObject * obj,
jsval id, jsval * vp, PRBool * _retval)
{
nsresult rv = NS_OK;
if (JSVAL_IS_STRING(id)) {
JSString *str = JSVAL_TO_STRING(id);
const PRUnichar *name = NS_REINTERPRET_CAST(const PRUnichar *,
@ -144,13 +145,14 @@ nsSOAPPropertyBag::GetProperty(nsIXPConnectWrappedNative * wrapper,
nsCOMPtr<nsIVariant> value;
mProperties.Get(nsDependentString(name), getter_AddRefs(value));
if (!value)
return NS_OK;
return rv;
rv = NS_SUCCESS_I_DID_SOMETHING;
void *mark;
jsval *argv = JS_PushArguments(cx, &mark, "%iv", value.get());
*vp = *argv;
JS_PopArguments(cx, mark);
}
return NS_OK;
return rv;
}
PLDHashOperator PR_CALLBACK

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

@ -41,7 +41,19 @@
#include "nsISupports.idl"
#include "nsIXPConnect.idl"
[uuid(fa2c3b80-0e9d-11d5-9092-0010a4e73d9a)]
%{ C++
#define NS_SUCCESS_I_DID_SOMETHING \
(NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCONNECT,1))
%}
/**
* Note: This is not really an XPCOM interface. For example, callers must
* guarantee that they set the *_retval of the various methods that return a
* boolean to PR_TRUE before making the call. Implementations may skip writing
* to *_retval unless they want to return PR_FALSE.
*/
[uuid(3a592a93-bf40-4ca1-9025-ef05dc2b0cd9)]
interface nsIXPCScriptable : nsISupports
{
/* bitflags used for 'flags' (only 32 bits available!) */
@ -100,10 +112,14 @@ interface nsIXPCScriptable : nsISupports
in JSContextPtr cx, in JSObjectPtr obj, in JSVal id,
in JSValPtr vp);
// The returnCode should be set to NS_SUCCESS_I_DID_SOMETHING if
// this method does something.
PRBool getProperty(in nsIXPConnectWrappedNative wrapper,
in JSContextPtr cx, in JSObjectPtr obj, in JSVal id,
in JSValPtr vp);
// The returnCode should be set to NS_SUCCESS_I_DID_SOMETHING if
// this method does something.
PRBool setProperty(in nsIXPConnectWrappedNative wrapper,
in JSContextPtr cx, in JSObjectPtr obj, in JSVal id,
in JSValPtr vp);

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

@ -39,6 +39,10 @@
#include "xpcprivate.h"
#include "XPCNativeWrapper.h"
#include "jsdbgapi.h"
JS_STATIC_DLL_CALLBACK(JSBool)
XPC_NW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
JS_STATIC_DLL_CALLBACK(JSBool)
XPC_NW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
@ -83,6 +87,13 @@ XPC_NW_Mark(JSContext *cx, JSObject *obj, void *arg);
JS_STATIC_DLL_CALLBACK(JSBool)
XPC_NW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp);
static JSBool
RewrapIfDeepWrapper(JSContext *cx, JSObject *obj, jsval v, jsval *rval);
JS_STATIC_DLL_CALLBACK(JSBool)
XPC_NW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval);
// JS class for XPCNativeWrapper (and this doubles as the constructor
// for XPCNativeWrapper for the moment too...)
@ -93,7 +104,7 @@ JSExtendedClass XPCNativeWrapper::sXPC_NW_JSClass = {
// Our one reserved slot holds a jsint of flag bits
JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(1) |
JSCLASS_IS_EXTENDED,
JS_PropertyStub, XPC_NW_DelProperty,
XPC_NW_AddProperty, XPC_NW_DelProperty,
XPC_NW_GetProperty, XPC_NW_SetProperty,
XPC_NW_Enumerate, (JSResolveOp)XPC_NW_NewResolve,
XPC_NW_Convert, XPC_NW_Finalize,
@ -108,9 +119,16 @@ JSExtendedClass XPCNativeWrapper::sXPC_NW_JSClass = {
#define FLAG_DEEP 0x1
#define FLAG_EXPLICIT 0x2
// FLAG_RESOLVING is used to tag an XPCNativeWrapper when while it's calling
// the newResolve hook on the XPCWrappedNative's scriptable info.
#define FLAG_RESOLVING 0x4
#define HAS_FLAGS(_val, _flags) \
((JSVAL_TO_INT(_val) & (_flags)) != 0)
((PRUint32(JSVAL_TO_INT(_val)) & (_flags)) != 0)
#define NATIVE_HAS_FLAG(_wn, _flag) \
((_wn)->GetScriptableInfo() && \
(_wn)->GetScriptableInfo()->GetFlags()._flag())
// If one of our class hooks is ever called from a non-system script, bypass
// the hook by calling the same hook on our wrapped native, with obj reset to
@ -197,6 +215,45 @@ GetStringByIndex(JSContext *cx, uintN index)
return ID_TO_VALUE(rt->GetStringID(index));
}
static JSBool
WrapFunction(JSContext* cx, JSObject* funobj, jsval *rval)
{
// If funobj is already a wrapped function, just return it.
if (JS_GetFunctionNative(cx,
JS_ValueToFunction(cx, OBJECT_TO_JSVAL(funobj))) ==
XPC_NW_FunctionWrapper) {
*rval = OBJECT_TO_JSVAL(funobj);
return JS_TRUE;
}
// Create a new function that'll call our given function. This new
// function's parent will be the original function and that's how we
// get the right thing to call when this function is called.
JSFunction *funWrapper =
::JS_NewFunction(cx, XPC_NW_FunctionWrapper, 0, 0, funobj,
"XPCNativeWrapper function wrapper");
if (!funWrapper) {
return JS_FALSE;
}
*rval = OBJECT_TO_JSVAL(::JS_GetFunctionObject(funWrapper));
return JS_TRUE;
}
JS_STATIC_DLL_CALLBACK(JSBool)
XPC_NW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
jsval flags;
::JS_GetReservedSlot(cx, obj, 0, &flags);
if (!HAS_FLAGS(flags, FLAG_RESOLVING)) {
return JS_TRUE;
}
// Note: no need to protect *vp from GC here, since it's already in the slot
// on |obj|.
return RewrapIfDeepWrapper(cx, obj, *vp, vp);
}
JS_STATIC_DLL_CALLBACK(JSBool)
XPC_NW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
@ -223,12 +280,29 @@ RewrapIfDeepWrapper(JSContext *cx, JSObject *obj, jsval v, jsval *rval)
{
NS_ASSERTION(XPCNativeWrapper::IsNativeWrapper(cx, obj),
"Unexpected object");
JSBool primitive = JSVAL_IS_PRIMITIVE(v);
JSObject* nativeObj = primitive ? nsnull : JSVAL_TO_OBJECT(v);
// We always want to wrap function objects, no matter whether we're deep.
if (!primitive && JS_ObjectIsFunction(cx, nativeObj)) {
return WrapFunction(cx, nativeObj, rval);
}
jsval flags;
::JS_GetReservedSlot(cx, obj, 0, &flags);
// Re-wrap non-primitive values if this is a deep wrapper, i.e.
// if (HAS_FLAGS(flags, FLAG_DEEP).
if (HAS_FLAGS(flags, FLAG_DEEP) && !JSVAL_IS_PRIMITIVE(v)) {
if (HAS_FLAGS(flags, FLAG_DEEP) && !primitive) {
XPCWrappedNative* wrappedNative =
XPCWrappedNative::GetWrappedNativeOfJSObject(cx, nativeObj);
if (!wrappedNative) {
// Not something we can protect... just make it JSVAL_NULL
*rval = JSVAL_NULL;
return JS_TRUE;
}
if (HAS_FLAGS(flags, FLAG_EXPLICIT)) {
#ifdef DEBUG_XPCNativeWrapper
@ -248,13 +322,6 @@ RewrapIfDeepWrapper(JSContext *cx, JSObject *obj, jsval v, jsval *rval)
// Just using GetNewOrUsed on the return value of
// GetWrappedNativeOfJSObject will give the right thing -- the unique deep
// implicit wrapper associated with wrappedNative.
JSObject *nativeObj = JSVAL_TO_OBJECT(v);
XPCWrappedNative* wrappedNative =
XPCWrappedNative::GetWrappedNativeOfJSObject(cx, nativeObj);
if (!wrappedNative) {
return ThrowException(NS_ERROR_INVALID_ARG, cx);
}
JSObject* wrapperObj = XPCNativeWrapper::GetNewOrUsed(cx, wrappedNative);
if (!wrapperObj) {
return JS_FALSE;
@ -355,24 +422,54 @@ XPC_NW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp,
return JS_TRUE;
}
jsval methodName;
// This will do verification and the method lookup for us.
XPCCallContext ccx(JS_CALLER, cx, nativeObj, nsnull, id);
if (JSVAL_IS_STRING(id)) {
methodName = id;
} else if (JSVAL_IS_INT(id)) {
// Map wrapper[n] to wrapper.item(n) for get. For set, throw an
// error as we don't support that.
if (aIsSet ? NATIVE_HAS_FLAG(wrappedNative, WantSetProperty) :
NATIVE_HAS_FLAG(wrappedNative, WantGetProperty)) {
jsval v = *vp;
// Note that some sets return random DOM objects (setting
// document.location, say), so we want to rewrap for sets too if v != *vp.
JSBool retval = JS_TRUE;
nsresult rv;
if (aIsSet) {
return ThrowException(NS_ERROR_UNEXPECTED, cx);
rv = wrappedNative->GetScriptableCallback()->
SetProperty(wrappedNative, cx, obj, id, &v, &retval);
} else {
rv = wrappedNative->GetScriptableCallback()->
GetProperty(wrappedNative, cx, obj, id, &v, &retval);
}
if (NS_FAILED(rv)) {
return ThrowException(rv, cx);
}
if (!retval) {
return JS_FALSE;
}
methodName = GetStringByIndex(cx, XPCJSRuntime::IDX_ITEM);
} else {
return ThrowException(NS_ERROR_INVALID_ARG, cx);
}
if (rv == NS_SUCCESS_I_DID_SOMETHING) {
// Make sure v doesn't get collected while we're re-wrapping it.
AUTO_MARK_JSVAL(ccx, v);
// This will do verification and the method lookup for us.
XPCCallContext ccx(JS_CALLER, cx, nativeObj, nsnull, methodName);
#ifdef DEBUG_XPCNativeWrapper
JSString* strId = ::JS_ValueToString(cx, id);
if (strId) {
NS_ConvertUTF16toUTF8 propName((PRUnichar*)::JS_GetStringChars(strId),
::JS_GetStringLength(strId));
printf("%s via scriptable hooks for '%s'\n",
aIsSet ? "Set" : "Got", propName.get());
}
#endif
return RewrapIfDeepWrapper(cx, obj, v, vp);
}
}
if (!JSVAL_IS_STRING(id)) {
// Not going to be found here
return JS_TRUE;
}
// Verify that our jsobject really is a wrapped native.
XPCWrappedNative* wrapper = ccx.GetWrapper();
@ -385,45 +482,6 @@ XPC_NW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp,
// interface :)
XPCNativeInterface* iface = ccx.GetInterface();
if (!iface) {
// No interface, no IDL property. Check whet her we're getting an indexed
// property such as frames[0]. Handle that as a special case here, now
// that we know there's no XPConnected .item() method.
if (methodName != id) {
jsid index_id;
JSObject *pobj;
JSProperty *prop;
// Look up the property for the id being indexed in nativeObj.
if (!::JS_ValueToId(cx, id, &index_id) ||
!OBJ_LOOKUP_PROPERTY(cx, nativeObj, index_id, &pobj, &prop)) {
return JS_FALSE;
}
if (prop) {
JSBool safe = JS_FALSE;
if (OBJ_IS_NATIVE(pobj)) {
// At this point we know we have a native JS object (one that
// has a JSScope for its map, containing refs to the runtime's
// JSScopeProperty tree nodes. Compare that property's getter
// to the class default getter to decide whether this element
// is safe to get -- i.e., it is not overridden, possibly by a
// user-defined getter.
JSScopeProperty *sprop = (JSScopeProperty *) prop;
JSClass *nativeObjClass = JS_GET_CLASS(cx, nativeObj);
safe = (sprop->getter == nativeObjClass->getProperty);
}
OBJ_DROP_PROPERTY(cx, pobj, prop);
if (safe) {
return ::JS_GetElement(cx, nativeObj, JSVAL_TO_INT(id), vp);
}
}
}
return JS_TRUE;
}
@ -456,11 +514,9 @@ XPC_NW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp,
return JS_TRUE;
}
if (!member->IsAttribute() && methodName == id) {
if (!member->IsAttribute()) {
// Getting the value of a method. Just return and let the value
// from XPC_NW_NewResolve() be used. Note that if methodName != id
// then we fully expect that member is not an attribute and we need
// to keep going and handle this case below.
// from XPC_NW_NewResolve() be used.
return JS_TRUE;
}
@ -479,24 +535,7 @@ XPC_NW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp,
jsval *argv = nsnull;
uintN argc = 0;
if (methodName != id) {
// wrapper[n] to wrapper.item(n) mapping case.
if (member->IsAttribute()) {
// Uh oh, somehow wrapper.item is an attribute, not a function.
// Throw an error since we don't know how to deal with this case.
return ThrowException(NS_ERROR_UNEXPECTED, cx);
}
#ifdef DEBUG_XPCNativeWrapper
printf("Mapping wrapper[%d] to wrapper.item(%d)\n", JSVAL_TO_INT(id),
JSVAL_TO_INT(id));
#endif
argv = &id;
argc = 1;
} else if (aIsSet) {
if (aIsSet) {
if (member->IsReadOnlyAttribute()) {
// Trying to set a property for which there is no setter!
return ThrowException(NS_ERROR_NOT_AVAILABLE, cx);
@ -516,8 +555,7 @@ XPC_NW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp,
#endif
}
// Call the getter (or method if an id access was mapped to
// .item(n)).
// Call the getter
jsval v;
if (!::JS_CallFunctionValue(cx, wrapper->GetFlatJSObject(),
OBJECT_TO_JSVAL(funobj), argc, argv, &v)) {
@ -575,8 +613,10 @@ JS_STATIC_DLL_CALLBACK(JSBool)
XPC_NW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
JSObject **objp)
{
// No need to preserve on sets of wrappedJSObject or toString, since
// callers couldn't get at those values anyway.
// No need to preserve on sets of wrappedJSObject or toString, since callers
// couldn't get at those values anyway. Also, we always deal with
// wrappedJSObject and toString before looking at our scriptable hooks, so no
// need to mess with our flags yet.
if (id == GetStringByIndex(cx, XPCJSRuntime::IDX_WRAPPED_JSOBJECT) ||
id == GetStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) {
return JS_TRUE;
@ -632,35 +672,74 @@ XPC_NW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
return JS_TRUE;
}
if (JSVAL_IS_INT(id)) {
// An index is being resolved. Define the property and deal with
// the value in the get/set property hooks.
// Note that we don't have to worry about preserving here, since
// numeric ids can't be assigned to.
if (!::JS_DefineElement(cx, obj, JSVAL_TO_INT(id), JSVAL_VOID, nsnull,
nsnull, 0)) {
return JS_FALSE;
}
*objp = obj;
return JS_TRUE;
}
if (!JSVAL_IS_STRING(id)) {
// A non-int and non-string id is being resolved. Won't be found
// here, return early.
return MaybePreserveWrapper(cx, wrappedNative, flags);
}
JSObject *nativeObj = wrappedNative->GetFlatJSObject();
// This will do verification and the method lookup for us.
XPCCallContext ccx(JS_CALLER, cx, nativeObj, nsnull, id);
// For "constructor" we don't want to call into the resolve hooks on the
// wrapped native, since that would give the wrong constructor.
if (NATIVE_HAS_FLAG(wrappedNative, WantNewResolve) &&
id != GetStringByIndex(cx, XPCJSRuntime::IDX_CONSTRUCTOR)) {
// Mark ourselves as resolving so our AddProperty hook can do the
// right thing here.
jsval oldFlags;
::JS_GetReservedSlot(cx, obj, 0, &oldFlags);
if (!::JS_SetReservedSlot(cx, obj, 0,
INT_TO_JSVAL(JSVAL_TO_INT(oldFlags) |
FLAG_RESOLVING))) {
return JS_FALSE;
}
XPCWrappedNative* oldResolvingWrapper;
JSBool allowPropMods =
NATIVE_HAS_FLAG(wrappedNative, AllowPropModsDuringResolve);
if (allowPropMods) {
oldResolvingWrapper = ccx.SetResolvingWrapper(wrappedNative);
}
JSBool retval = JS_TRUE;
JSObject* newObj = nsnull;
nsresult rv = wrappedNative->GetScriptableInfo()->
GetCallback()->NewResolve(wrappedNative, cx, obj, id, flags,
&newObj, &retval);
if (allowPropMods) {
ccx.SetResolvingWrapper(oldResolvingWrapper);
}
if (!::JS_SetReservedSlot(cx, obj, 0, oldFlags)) {
return JS_FALSE;
}
if (NS_FAILED(rv)) {
return ThrowException(rv, cx);
}
if (newObj) {
#ifdef DEBUG_XPCNativeWrapper
JSString* strId = ::JS_ValueToString(cx, id);
if (strId) {
NS_ConvertUTF16toUTF8 propName((PRUnichar*)::JS_GetStringChars(strId),
::JS_GetStringLength(strId));
printf("Resolved via scriptable hooks for '%s'\n", propName.get());
}
#endif
// Note that we don't need to preserve the wrapper here, since this is
// not an "expando" property if the scriptable newResolve hook found it.
*objp = newObj;
return retval;
}
}
if (!JSVAL_IS_STRING(id)) {
// A non-string id is being resolved. Won't be found here, return
// early.
return MaybePreserveWrapper(cx, wrappedNative, flags);
}
// Verify that our jsobject really is a wrapped native.
XPCWrappedNative* wrapper = ccx.GetWrapper();
if (wrapper != wrappedNative || !wrapper->IsValid()) {
@ -727,18 +806,9 @@ XPC_NW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
::JS_GetStringBytes(JSVAL_TO_STRING(id)));
#endif
// Create a new function that'll call the method we got from the
// member. This new function's parent will be the method to call from
// the function, and that's how we get the method when this function
// is called.
JSFunction *funWrapper =
::JS_NewFunction(cx, XPC_NW_FunctionWrapper, 0, 0, funobj,
"Components.lookupMethod function wrapper");
if (!funWrapper) {
if (!WrapFunction(cx, funobj, &v)) {
return JS_FALSE;
}
v = OBJECT_TO_JSVAL(::JS_GetFunctionObject(funWrapper));
}
if (!::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str),

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

@ -2438,13 +2438,15 @@ nsXPCComponents::GetProperty(nsIXPConnectWrappedNative *wrapper,
doResult = JS_TRUE;
}
nsresult rv = NS_OK;
if(doResult)
{
if(!JS_NewNumberValue(cx, (jsdouble) res, vp))
return NS_ERROR_OUT_OF_MEMORY;
rv = NS_SUCCESS_I_DID_SOMETHING;
}
return NS_OK;
return rv;
}
/* PRBool setProperty (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in JSVal id, in JSValPtr vp); */
@ -2468,7 +2470,7 @@ nsXPCComponents::SetProperty(nsIXPConnectWrappedNative *wrapper,
{
xpcc->SetPendingResult(rv);
xpcc->SetLastResult(rv);
return NS_OK;
return NS_SUCCESS_I_DID_SOMETHING;
}
return NS_ERROR_FAILURE;
}