diff --git a/mozilla/js/src/xpconnect/src/xpcconvert.cpp b/mozilla/js/src/xpconnect/src/xpcconvert.cpp index 5b2b66ffd1b..cdbaa697435 100644 --- a/mozilla/js/src/xpconnect/src/xpcconvert.cpp +++ b/mozilla/js/src/xpconnect/src/xpcconvert.cpp @@ -90,7 +90,7 @@ static uint8 xpc_reflectable_flags[XPC_FLAG_COUNT] = { XPC_MK_FLAG( 1 , 1 , 1 , 0 ), /* T_WCHAR */ XPC_MK_FLAG( 0 , 0 , 0 , 0 ), /* T_VOID */ XPC_MK_FLAG( 0 , 1 , 0 , 1 ), /* T_IID */ - XPC_MK_FLAG( 0 , 0 , 0 , 0 ), /* T_DOMSTRING */ + XPC_MK_FLAG( 0 , 1 , 0 , 0 ), /* T_DOMSTRING */ XPC_MK_FLAG( 0 , 1 , 0 , 1 ), /* T_CHAR_STR */ XPC_MK_FLAG( 0 , 1 , 0 , 1 ), /* T_WCHAR_STR */ XPC_MK_FLAG( 0 , 1 , 0 , 1 ), /* T_INTERFACE */ @@ -347,9 +347,35 @@ XPCConvert::NativeData2JS(JSContext* cx, jsval* d, const void* s, } case nsXPTType::T_DOMSTRING: - // XXX implement DOMSTRING - XPC_LOG_ERROR(("XPCConvert::NativeData2JS : DOMSTRING params not supported")); - return JS_FALSE; + { + const nsAReadableString* p = *((const nsAReadableString**)s); + if(!p) + break; + + PRUint32 length = p->Length(); + + jschar* chars = (jschar *) + JS_malloc(cx, (length + 1) * sizeof(jschar)); + if(!chars) + return JS_FALSE; + + if(length && !CopyUnicodeTo(*p, 0, (PRUnichar*)chars, length)) + { + JS_free(cx, chars); + return JS_FALSE; + } + + chars[length] = 0; + + JSString* str; + if(!(str = JS_NewUCString(cx, chars, length))) + { + JS_free(cx, chars); + return JS_FALSE; + } + *d = STRING_TO_JSVAL(str); + break; + } case nsXPTType::T_CHAR_STR: { @@ -586,9 +612,74 @@ XPCConvert::JSData2Native(JSContext* cx, void* d, jsval s, } case nsXPTType::T_DOMSTRING: - // XXX implement DOMSTRING - XPC_LOG_ERROR(("XPCConvert::JSData2Native : DOMSTRING params not supported")); - return JS_FALSE; + { + static const NS_NAMED_LITERAL_STRING(sEmptyString, ""); + static const NS_NAMED_LITERAL_STRING(sNullString, "null"); + static const NS_NAMED_LITERAL_STRING(sVoidString, "undefined"); + + const PRUnichar* chars; + PRUint32 length; + JSBool isNewString = JS_FALSE; + + if(JSVAL_IS_VOID(s)) + { + chars = sVoidString.get(); + length = sVoidString.Length(); + } + else if(JSVAL_IS_NULL(s)) + { + // XXX We don't yet have a way to represent a null nsAXXXString + // XXX Do we *want* to use "null"? + chars = sNullString.get(); + length = sNullString.Length(); + } + else + { + JSString* str = JS_ValueToString(cx, s); + if(!str) + return JS_FALSE; + + length = (PRUint32) JS_GetStringLength(str); + if(length) + { + chars = (const PRUnichar*) JS_GetStringChars(str); + if(!chars) + return JS_FALSE; + if(STRING_TO_JSVAL(str) != s) + isNewString = JS_TRUE; + } + else + { + chars = sEmptyString.get(); + } + } + + NS_ASSERTION(chars, "I must be really confused"); + + if(useAllocator) + { + nsAReadableString* rs; + + // If the underlying JSString may have been created in the + // JS_ValueToString call, then we need to make a copied string + // to avoid the possibility of the string data being gc'd before + // we are done. + if(isNewString) + rs = new nsString(chars, length); + else + rs = new nsLiteralString(chars, length); + + if(!rs) + return JS_FALSE; + *((nsAReadableString**)d) = rs; + } + else + { + nsAWritableString* ws = *((nsAWritableString**)d); + ws->Assign(chars); + } + return JS_TRUE; + } case nsXPTType::T_CHAR_STR: { diff --git a/mozilla/js/src/xpconnect/src/xpcwrappedjsclass.cpp b/mozilla/js/src/xpconnect/src/xpcwrappedjsclass.cpp index 18a16540ad4..97eeadbec1f 100644 --- a/mozilla/js/src/xpconnect/src/xpcwrappedjsclass.cpp +++ b/mozilla/js/src/xpconnect/src/xpcwrappedjsclass.cpp @@ -1067,7 +1067,7 @@ pre_call_clean_up: for(i = 0; i < paramCount; i++) { const nsXPTParamInfo& param = info->GetParam(i); - if(!param.IsOut()) + if(!param.IsOut() && !param.IsDipper()) continue; const nsXPTType& type = param.GetType(); @@ -1082,7 +1082,10 @@ pre_call_clean_up: JSBool useAllocator = JS_FALSE; nsXPTCMiniVariant* pv; - pv = (nsXPTCMiniVariant*) nativeParams[i].val.p; + if(param.IsDipper()) + pv = (nsXPTCMiniVariant*) &nativeParams[i].val.p; + else + pv = (nsXPTCMiniVariant*) nativeParams[i].val.p; if(param.IsRetval()) val = result; @@ -1100,7 +1103,7 @@ pre_call_clean_up: HANDLE_OUT_CONVERSION_FAILURE; iidIsOwned = JS_TRUE; } - else if(type.IsPointer() && !param.IsShared()) + else if(type.IsPointer() && !param.IsShared() && !param.IsDipper()) useAllocator = JS_TRUE; if(!XPCConvert::JSData2Native(cx, &pv->val, val, type, diff --git a/mozilla/js/src/xpconnect/src/xpcwrappednativeclass.cpp b/mozilla/js/src/xpconnect/src/xpcwrappednativeclass.cpp index c3923819b64..04f424dccd1 100644 --- a/mozilla/js/src/xpconnect/src/xpcwrappednativeclass.cpp +++ b/mozilla/js/src/xpconnect/src/xpcwrappednativeclass.cpp @@ -271,15 +271,6 @@ nsXPCWrappedNativeClass::BuildMemberDescriptors(XPCContext* xpcc) return JS_TRUE; } -/* -void -nsXPCWrappedNativeClass::XPCContextBeingDestroyed() -{ - DestroyMemberDescriptors(); - mXPCContext = nsnull; -} -*/ - void nsXPCWrappedNativeClass::DestroyMemberDescriptors() { @@ -666,7 +657,7 @@ nsXPCWrappedNativeClass::CallWrappedMethod(JSContext* cx, for(i = 0; i < paramCount; i++) { nsXPTCVariant* dp = &dispatchParams[i]; - dp->flags = 0; + dp->ClearFlags(); dp->val.p = nsnull; } @@ -693,7 +684,7 @@ nsXPCWrappedNativeClass::CallWrappedMethod(JSContext* cx, if(type_tag == nsXPTType::T_INTERFACE) { - dp->flags |= nsXPTCVariant::VAL_IS_IFACE; + dp->SetValIsInterface(); } // set 'src' to be the object from which we get the value and @@ -701,7 +692,7 @@ nsXPCWrappedNativeClass::CallWrappedMethod(JSContext* cx, if(param.IsOut()) { - dp->flags |= nsXPTCVariant::PTR_IS_DATA; + dp->SetPtrIsData(); dp->ptr = &dp->val; if(!param.IsRetval() && @@ -720,7 +711,7 @@ nsXPCWrappedNativeClass::CallWrappedMethod(JSContext* cx, !param.IsShared()) { useAllocator = JS_TRUE; - dp->flags |= nsXPTCVariant::VAL_IS_OWNED; + dp->SetValIsAllocated(); } if(!param.IsIn()) @@ -728,14 +719,43 @@ nsXPCWrappedNativeClass::CallWrappedMethod(JSContext* cx, } else { - src = argv[i]; - - if(type.IsPointer() && - type_tag == nsXPTType::T_IID) + if(type.IsPointer()) { - useAllocator = JS_TRUE; - dp->flags |= nsXPTCVariant::VAL_IS_OWNED; + switch(type_tag) + { + case nsXPTType::T_IID: + dp->SetValIsAllocated(); + useAllocator = JS_TRUE; + break; + + case nsXPTType::T_DOMSTRING: + dp->SetValIsDOMString(); + if(param.IsDipper()) + { + // Is an 'out' DOMString. Make a new nsAWritableString + // now and then continue in order to skip the call to + // JSData2Native + if(!(dp->val.p = new nsString())) + { + JS_ReportOutOfMemory(cx); + goto done; + } + continue; + } + // else... + + // Is an 'in' DOMString. Set 'useAllocator' to indicate + // that JSData2Native should allocate a new + // nsAReadableString. + useAllocator = JS_TRUE; + break; + } } + + // Do this *after* the above because in the case where we have a + // "T_DOMSTRING && IsDipper()" then argv might be null since this + // is really an 'out' param masquerading as an 'in' param. + src = argv[i]; } if(type_tag == nsXPTType::T_INTERFACE && @@ -788,7 +808,7 @@ nsXPCWrappedNativeClass::CallWrappedMethod(JSContext* cx, if(isArray) { - dp->flags |= nsXPTCVariant::VAL_IS_ARRAY; + dp->SetValIsArray(); if(NS_FAILED(mInfo->GetTypeForParam(vtblIndex, ¶m, 1, &datum_type))) @@ -802,7 +822,7 @@ nsXPCWrappedNativeClass::CallWrappedMethod(JSContext* cx, if(datum_type.IsInterfacePointer()) { - dp->flags |= nsXPTCVariant::VAL_IS_IFACE; + dp->SetValIsInterface(); } // set 'src' to be the object from which we get the value and @@ -810,7 +830,7 @@ nsXPCWrappedNativeClass::CallWrappedMethod(JSContext* cx, if(param.IsOut()) { - dp->flags |= nsXPTCVariant::PTR_IS_DATA; + dp->SetPtrIsData(); dp->ptr = &dp->val; if(!param.IsRetval() && @@ -828,7 +848,7 @@ nsXPCWrappedNativeClass::CallWrappedMethod(JSContext* cx, (isArray || !param.IsShared())) { useAllocator = JS_TRUE; - dp->flags |= nsXPTCVariant::VAL_IS_OWNED; + dp->SetValIsAllocated(); } if(!param.IsIn()) @@ -842,7 +862,7 @@ nsXPCWrappedNativeClass::CallWrappedMethod(JSContext* cx, datum_type.TagPart() == nsXPTType::T_IID) { useAllocator = JS_TRUE; - dp->flags |= nsXPTCVariant::VAL_IS_OWNED; + dp->SetValIsAllocated(); } } @@ -940,7 +960,7 @@ nsXPCWrappedNativeClass::CallWrappedMethod(JSContext* cx, for(i = 0; i < paramCount; i++) { const nsXPTParamInfo& param = info->GetParam(i); - if(!param.IsOut()) + if(!param.IsOut() && !param.IsDipper()) continue; const nsXPTType& type = param.GetType(); @@ -1054,7 +1074,7 @@ done: if(dp->IsValArray()) { // going to have to cleanup the array and perhaps its contents - if(dp->IsValOwned() || dp->IsValInterface()) + if(dp->IsValAllocated() || dp->IsValInterface()) { // we need to figure out how many elements are present. JSUint32 array_count; @@ -1067,7 +1087,7 @@ done: NS_ASSERTION(0,"failed to get array length, we'll leak here"); continue; } - if(dp->IsValOwned()) + if(dp->IsValAllocated()) { void** a = (void**)p; for(JSUint32 k = 0; k < array_count; k++) @@ -1089,10 +1109,12 @@ done: // always free the array itself nsMemory::Free(p); } - else if(dp->IsValOwned()) + else if(dp->IsValAllocated()) nsMemory::Free(p); else if(dp->IsValInterface()) ((nsISupports*)p)->Release(); + else if(dp->IsValDOMString()) + delete (nsAReadableString*)p; } } diff --git a/mozilla/js/src/xpconnect/tests/TestXPC.cpp b/mozilla/js/src/xpconnect/tests/TestXPC.cpp index beaa8ac6dd9..072954c5842 100644 --- a/mozilla/js/src/xpconnect/tests/TestXPC.cpp +++ b/mozilla/js/src/xpconnect/tests/TestXPC.cpp @@ -52,6 +52,7 @@ #include "nsMemory.h" #include "nsIXPCSecurityManager.h" #include "nsICategoryManager.h" +#include "nsAWritableString.h" #include "jsapi.h" #include "jsgc.h" // for js_ForceGC diff --git a/mozilla/js/src/xpconnect/tests/components/xpctest_echo.cpp b/mozilla/js/src/xpconnect/tests/components/xpctest_echo.cpp index df380834ad3..6175e718be4 100644 --- a/mozilla/js/src/xpconnect/tests/components/xpctest_echo.cpp +++ b/mozilla/js/src/xpconnect/tests/components/xpctest_echo.cpp @@ -102,6 +102,22 @@ NS_IMETHODIMP xpctestEcho::In2OutOneInt(int input, int* output) return NS_OK; } +/* DOMString In2OutOneDOMString (in DOMString input); */ +NS_IMETHODIMP xpctestEcho::In2OutOneDOMString(const nsAReadableString & input, + nsAWritableString & _retval) +{ + _retval.Assign(input); + return NS_OK; +} + +/* DOMString EchoIn2OutOneDOMString (in DOMString input); */ +NS_IMETHODIMP xpctestEcho::EchoIn2OutOneDOMString(const nsAReadableString & input, nsAWritableString & _retval) +{ + if(mReceiver) + return mReceiver->EchoIn2OutOneDOMString(input, _retval); + return NS_OK; +} + NS_IMETHODIMP xpctestEcho::In2OutAddTwoInts(int input1, int input2, int* output1, diff --git a/mozilla/js/src/xpconnect/tests/components/xpctest_private.h b/mozilla/js/src/xpconnect/tests/components/xpctest_private.h index d5b889a384b..78f377c558d 100644 --- a/mozilla/js/src/xpconnect/tests/components/xpctest_private.h +++ b/mozilla/js/src/xpconnect/tests/components/xpctest_private.h @@ -47,6 +47,7 @@ #include "nsIGenericFactory.h" #include "nscore.h" #include "nsCOMPtr.h" +#include "nsAWritableString.h" #include #include "xpctest.h" diff --git a/mozilla/js/src/xpconnect/tests/idl/xpctest.idl b/mozilla/js/src/xpconnect/tests/idl/xpctest.idl index a427a5a4afe..d1505820cc0 100644 --- a/mozilla/js/src/xpconnect/tests/idl/xpctest.idl +++ b/mozilla/js/src/xpconnect/tests/idl/xpctest.idl @@ -66,6 +66,10 @@ interface nsIEcho : nsISupports { out long output1, out long output2); string In2OutOneString(in string input); + + DOMString In2OutOneDOMString(in DOMString input); + DOMString EchoIn2OutOneDOMString(in DOMString input); + void SimpleCallNoEcho(); void SendManyTypes(in octet p1, in short p2, diff --git a/mozilla/js/src/xpconnect/tests/js/old/xpctest_echo.js b/mozilla/js/src/xpconnect/tests/js/old/xpctest_echo.js index bc4e7121d0f..8ae21940398 100644 --- a/mozilla/js/src/xpconnect/tests/js/old/xpctest_echo.js +++ b/mozilla/js/src/xpconnect/tests/js/old/xpctest_echo.js @@ -70,6 +70,12 @@ receiver.SendManyTypes = function() receiver_results[i] = arguments[i]; }; +receiver.EchoIn2OutOneDOMString = function(input) + { + // print("EchoIn2OutOneDOMString called with: "+input); + return input; + }; + echo.SetReceiver(receiver); //////////////////// @@ -217,6 +223,31 @@ for(i = 0; i < 16; i++) { if(all_ok) print("SendInOutManyTypes - passed"); +//////////////////// + +var test_string3 = "And this is yet again some other string 3"; +var test_string4 = "And this is yet again some other string 4"; + +print("In2OutOneDOMString - "+( + echo.In2OutOneDOMString(test_string3) == test_string3 + ? "passed" : "failed")); + +print("EchoIn2OutOneDOMString - "+( + echo.EchoIn2OutOneDOMString(test_string4) == test_string4 + ? "passed" : "failed")); + +print("EchoIn2OutOneDOMString of empty string - "+( + echo.EchoIn2OutOneDOMString("") == "" + ? "passed" : "failed")); + +print("EchoIn2OutOneDOMString of null - "+( + echo.EchoIn2OutOneDOMString(null) == "null" + ? "passed" : "failed")); + +print("EchoIn2OutOneDOMString of undefined - "+( + echo.EchoIn2OutOneDOMString(this.propertyThatDoesNotExist) == "undefined" + ? "passed" : "failed")); + //////////////////// // check exceptions on xpcom error code @@ -373,7 +404,7 @@ foo = bar = iface = clazz = null; print("......................................."); print("simple speed tests..."); -var iterations = 1000; +var iterations = 5000; var receiver2 = new Object(); receiver2.SetReceiver = function() {}; @@ -462,6 +493,8 @@ send_params = null; start_time = null; test_string = null; test_string2 = null; +test_string3 = null; +test_string4 = null; nsNativeEcho = null; gc(); gc(); diff --git a/mozilla/xpcom/reflect/xptcall/public/xptcall.h b/mozilla/xpcom/reflect/xptcall/public/xptcall.h index 34477896f28..94d00bf2d97 100644 --- a/mozilla/xpcom/reflect/xptcall/public/xptcall.h +++ b/mozilla/xpcom/reflect/xptcall/public/xptcall.h @@ -99,15 +99,24 @@ struct nsXPTCVariant : public nsXPTCMiniVariant { // these are bitflags! PTR_IS_DATA = 0x1, // ptr points to 'real' data in val - VAL_IS_OWNED = 0x2, // val.p holds alloc'd ptr that must be freed + VAL_IS_ALLOCD= 0x2, // val.p holds alloc'd ptr that must be freed VAL_IS_IFACE = 0x4, // val.p holds interface ptr that must be released - VAL_IS_ARRAY = 0x8 // val.p holds a pointer to an array needing cleanup + VAL_IS_ARRAY = 0x8, // val.p holds a pointer to an array needing cleanup + VAL_IS_DOMSTR= 0x10 // val.p holds a pointer to domstring needing cleanup }; + void ClearFlags() {flags = 0;} + void SetPtrIsData() {flags |= PTR_IS_DATA;} + void SetValIsAllocated() {flags |= VAL_IS_ALLOCD;} + void SetValIsInterface() {flags |= VAL_IS_IFACE;} + void SetValIsArray() {flags |= VAL_IS_ARRAY;} + void SetValIsDOMString() {flags |= VAL_IS_DOMSTR;} + PRBool IsPtrData() const {return (PRBool) (flags & PTR_IS_DATA);} - PRBool IsValOwned() const {return (PRBool) (flags & VAL_IS_OWNED);} + PRBool IsValAllocated() const {return (PRBool) (flags & VAL_IS_ALLOCD);} PRBool IsValInterface() const {return (PRBool) (flags & VAL_IS_IFACE);} PRBool IsValArray() const {return (PRBool) (flags & VAL_IS_ARRAY);} + PRBool IsValDOMString() const {return (PRBool) (flags & VAL_IS_DOMSTR);} void Init(const nsXPTCMiniVariant& mv, const nsXPTType& t, PRUint8 f) { diff --git a/mozilla/xpcom/typelib/xpidl/xpidl_util.c b/mozilla/xpcom/typelib/xpidl/xpidl_util.c index ece494491db..3144eaf5717 100644 --- a/mozilla/xpcom/typelib/xpidl/xpidl_util.c +++ b/mozilla/xpcom/typelib/xpidl/xpidl_util.c @@ -507,6 +507,31 @@ verify_method_declaration(IDL_tree method_tree) } } + /* + * inout is not allowed with "domstring" types + */ + if (IDL_PARAM_DCL(param).attr == IDL_PARAM_INOUT && + UP_IS_NATIVE(param_type) && + IDL_tree_property_get(param_type, "domstring") != NULL) { + IDL_tree_error(method_tree, + "[domstring] types cannot be used as inout " + "parameters"); + return FALSE; + } + + + /* + * arrays of "domstring" types not allowed + */ + if (IDL_tree_property_get(simple_decl, "array") != NULL && + UP_IS_NATIVE(param_type) && + IDL_tree_property_get(param_type, "domstring") != NULL) { + IDL_tree_error(method_tree, + "[domstring] types cannot be used in array " + "parameters"); + return FALSE; + } + if (!check_param_attribute(method_tree, param, IID_IS) || !check_param_attribute(method_tree, param, LENGTH_IS) || !check_param_attribute(method_tree, param, SIZE_IS))