/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/. */ #include "nsXPCOMGlue.h" #include "nspr.h" #include "nsDebug.h" #include "nsIServiceManager.h" #include "nsXPCOMPrivate.h" #include "nsCOMPtr.h" #include #include #include "mozilla/FileUtils.h" #include "mozilla/Sprintf.h" using namespace mozilla; #define XPCOM_DEPENDENT_LIBS_LIST "dependentlibs.list" static XPCOMFunctions xpcomFunctions; static bool do_preload = false; #if defined(XP_WIN) #define READ_TEXTMODE L"rt" #else #define READ_TEXTMODE "r" #endif #if defined(XP_WIN) #include #include typedef HINSTANCE LibHandleType; static LibHandleType GetLibHandle(pathstr_t aDependentLib) { LibHandleType libHandle = LoadLibraryExW(aDependentLib, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH); #ifdef DEBUG if (!libHandle) { DWORD err = GetLastError(); LPWSTR lpMsgBuf; FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, nullptr ); wprintf(L"Error loading %ls: %s\n", aDependentLib, lpMsgBuf); LocalFree(lpMsgBuf); } #endif return libHandle; } static NSFuncPtr GetSymbol(LibHandleType aLibHandle, const char* aSymbol) { return (NSFuncPtr)GetProcAddress(aLibHandle, aSymbol); } static void CloseLibHandle(LibHandleType aLibHandle) { FreeLibrary(aLibHandle); } #else #include #if defined(MOZ_LINKER) && !defined(ANDROID) extern "C" { NS_HIDDEN __typeof(dlopen) __wrap_dlopen; NS_HIDDEN __typeof(dlsym) __wrap_dlsym; NS_HIDDEN __typeof(dlclose) __wrap_dlclose; } #define dlopen __wrap_dlopen #define dlsym __wrap_dlsym #define dlclose __wrap_dlclose #endif typedef void* LibHandleType; static LibHandleType GetLibHandle(pathstr_t aDependentLib) { LibHandleType libHandle = dlopen(aDependentLib, RTLD_GLOBAL | RTLD_LAZY #ifdef XP_MACOSX | RTLD_FIRST #endif ); if (!libHandle) { fprintf(stderr, "XPCOMGlueLoad error for file %s:\n%s\n", aDependentLib, dlerror()); } return libHandle; } static NSFuncPtr GetSymbol(LibHandleType aLibHandle, const char* aSymbol) { return (NSFuncPtr)dlsym(aLibHandle, aSymbol); } static void CloseLibHandle(LibHandleType aLibHandle) { dlclose(aLibHandle); } #endif struct DependentLib { LibHandleType libHandle; DependentLib* next; }; static DependentLib* sTop; static void AppendDependentLib(LibHandleType aLibHandle) { DependentLib* d = new DependentLib; if (!d) { return; } d->next = sTop; d->libHandle = aLibHandle; sTop = d; } static bool ReadDependentCB(pathstr_t aDependentLib, bool aDoPreload) { if (aDoPreload) { ReadAheadLib(aDependentLib); } LibHandleType libHandle = GetLibHandle(aDependentLib); if (libHandle) { AppendDependentLib(libHandle); } return libHandle; } #ifdef XP_WIN static bool ReadDependentCB(const char* aDependentLib, bool do_preload) { wchar_t wideDependentLib[MAX_PATH]; MultiByteToWideChar(CP_UTF8, 0, aDependentLib, -1, wideDependentLib, MAX_PATH); return ReadDependentCB(wideDependentLib, do_preload); } inline FILE* TS_tfopen(const char* path, const wchar_t* mode) { wchar_t wPath[MAX_PATH]; MultiByteToWideChar(CP_UTF8, 0, path, -1, wPath, MAX_PATH); return _wfopen(wPath, mode); } #else inline FILE* TS_tfopen(const char* aPath, const char* aMode) { return fopen(aPath, aMode); } #endif /* RAII wrapper for FILE descriptors */ struct ScopedCloseFileTraits { typedef FILE* type; static type empty() { return nullptr; } static void release(type aFile) { if (aFile) { fclose(aFile); } } }; typedef Scoped ScopedCloseFile; static void XPCOMGlueUnload() { while (sTop) { CloseLibHandle(sTop->libHandle); DependentLib* temp = sTop; sTop = sTop->next; delete temp; } } #if defined(XP_WIN) // like strpbrk but finds the *last* char, not the first static const char* ns_strrpbrk(const char* string, const char* strCharSet) { const char* found = nullptr; for (; *string; ++string) { for (const char* search = strCharSet; *search; ++search) { if (*search == *string) { found = string; // Since we're looking for the last char, we save "found" // until we're at the end of the string. } } } return found; } #endif static GetFrozenFunctionsFunc XPCOMGlueLoad(const char* aXPCOMFile) { char xpcomDir[MAXPATHLEN]; #ifdef XP_WIN const char* lastSlash = ns_strrpbrk(aXPCOMFile, "/\\"); #elif XP_MACOSX // On OSX, the dependentlibs.list file lives under Contents/Resources. // However, the actual libraries listed in dependentlibs.list live under // Contents/MacOS. We want to read the list from Contents/Resources, then // load the libraries from Contents/MacOS. const char *tempSlash = strrchr(aXPCOMFile, '/'); size_t tempLen = size_t(tempSlash - aXPCOMFile); if (tempLen > MAXPATHLEN) { return nullptr; } char tempBuffer[MAXPATHLEN]; memcpy(tempBuffer, aXPCOMFile, tempLen); tempBuffer[tempLen] = '\0'; const char *slash = strrchr(tempBuffer, '/'); tempLen = size_t(slash - tempBuffer); const char *lastSlash = aXPCOMFile + tempLen; #else const char* lastSlash = strrchr(aXPCOMFile, '/'); #endif char* cursor; if (lastSlash) { size_t len = size_t(lastSlash - aXPCOMFile); if (len > MAXPATHLEN - sizeof(XPCOM_FILE_PATH_SEPARATOR #ifdef XP_MACOSX "Resources" XPCOM_FILE_PATH_SEPARATOR #endif XPCOM_DEPENDENT_LIBS_LIST)) { return nullptr; } memcpy(xpcomDir, aXPCOMFile, len); strcpy(xpcomDir + len, XPCOM_FILE_PATH_SEPARATOR #ifdef XP_MACOSX "Resources" XPCOM_FILE_PATH_SEPARATOR #endif XPCOM_DEPENDENT_LIBS_LIST); cursor = xpcomDir + len + 1; } else { strcpy(xpcomDir, XPCOM_DEPENDENT_LIBS_LIST); cursor = xpcomDir; } if (getenv("MOZ_RUN_GTEST")) { strcat(xpcomDir, ".gtest"); } ScopedCloseFile flist; flist = TS_tfopen(xpcomDir, READ_TEXTMODE); if (!flist) { return nullptr; } #ifdef XP_MACOSX tempLen = size_t(cursor - xpcomDir); if (tempLen > MAXPATHLEN - sizeof("MacOS" XPCOM_FILE_PATH_SEPARATOR) - 1) { return nullptr; } strcpy(cursor, "MacOS" XPCOM_FILE_PATH_SEPARATOR); cursor += strlen(cursor); #endif *cursor = '\0'; char buffer[MAXPATHLEN]; while (fgets(buffer, sizeof(buffer), flist)) { int l = strlen(buffer); // ignore empty lines and comments if (l == 0 || *buffer == '#') { continue; } // cut the trailing newline, if present if (buffer[l - 1] == '\n') { buffer[l - 1] = '\0'; } if (l + size_t(cursor - xpcomDir) > MAXPATHLEN) { return nullptr; } strcpy(cursor, buffer); if (!ReadDependentCB(xpcomDir, do_preload)) { XPCOMGlueUnload(); return nullptr; } } GetFrozenFunctionsFunc sym = (GetFrozenFunctionsFunc)GetSymbol(sTop->libHandle, "NS_GetFrozenFunctions"); if (!sym) { // No symbol found. XPCOMGlueUnload(); return nullptr; } return sym; } nsresult XPCOMGlueLoadXULFunctions(const nsDynamicFunctionLoad* aSymbols) { // We don't null-check sXULLibHandle because this might work even // if it is null (same as RTLD_DEFAULT) nsresult rv = NS_OK; while (aSymbols->functionName) { char buffer[512]; SprintfLiteral(buffer, "%s", aSymbols->functionName); *aSymbols->function = (NSFuncPtr)GetSymbol(sTop->libHandle, buffer); if (!*aSymbols->function) { rv = NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; } ++aSymbols; } return rv; } void XPCOMGlueEnablePreload() { do_preload = true; } #if defined(MOZ_WIDGET_GTK) && (defined(MOZ_MEMORY) || defined(__FreeBSD__) || defined(__NetBSD__)) #define MOZ_GSLICE_INIT #endif #ifdef MOZ_GSLICE_INIT #include class GSliceInit { public: GSliceInit() { mHadGSlice = bool(getenv("G_SLICE")); if (!mHadGSlice) { // Disable the slice allocator, since jemalloc already uses similar layout // algorithms, and using a sub-allocator tends to increase fragmentation. // This must be done before g_thread_init() is called. // glib >= 2.36 initializes g_slice as a side effect of its various static // initializers, so this needs to happen before glib is loaded, which is // this is hooked in XPCOMGlueStartup before libxul is loaded. This // relies on the main executable not depending on glib. setenv("G_SLICE", "always-malloc", 1); } } ~GSliceInit() { #if MOZ_WIDGET_GTK == 2 if (sTop) { auto XRE_GlibInit = (void (*)(void)) GetSymbol(sTop->libHandle, "XRE_GlibInit"); // Initialize glib enough for G_SLICE to have an effect before it is unset. // unset. XRE_GlibInit(); } #endif if (!mHadGSlice) { unsetenv("G_SLICE"); } } private: bool mHadGSlice; }; #endif nsresult XPCOMGlueStartup(const char* aXPCOMFile) { #ifdef MOZ_GSLICE_INIT GSliceInit gSliceInit; #endif xpcomFunctions.version = XPCOM_GLUE_VERSION; xpcomFunctions.size = sizeof(XPCOMFunctions); if (!aXPCOMFile) { aXPCOMFile = XPCOM_DLL; } GetFrozenFunctionsFunc func = XPCOMGlueLoad(aXPCOMFile); if (!func) { return NS_ERROR_NOT_AVAILABLE; } nsresult rv = (*func)(&xpcomFunctions, nullptr); if (NS_FAILED(rv)) { XPCOMGlueUnload(); return rv; } return NS_OK; } XPCOM_API(nsresult) NS_InitXPCOM2(nsIServiceManager** aResult, nsIFile* aBinDirectory, nsIDirectoryServiceProvider* aAppFileLocationProvider) { if (!xpcomFunctions.init) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.init(aResult, aBinDirectory, aAppFileLocationProvider); } XPCOM_API(nsresult) NS_ShutdownXPCOM(nsIServiceManager* aServMgr) { if (!xpcomFunctions.shutdown) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.shutdown(aServMgr); } XPCOM_API(nsresult) NS_GetServiceManager(nsIServiceManager** aResult) { if (!xpcomFunctions.getServiceManager) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.getServiceManager(aResult); } XPCOM_API(nsresult) NS_GetComponentManager(nsIComponentManager** aResult) { if (!xpcomFunctions.getComponentManager) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.getComponentManager(aResult); } XPCOM_API(nsresult) NS_GetComponentRegistrar(nsIComponentRegistrar** aResult) { if (!xpcomFunctions.getComponentRegistrar) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.getComponentRegistrar(aResult); } XPCOM_API(nsresult) NS_GetMemoryManager(nsIMemory** aResult) { if (!xpcomFunctions.getMemoryManager) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.getMemoryManager(aResult); } XPCOM_API(nsresult) NS_NewLocalFile(const nsAString& aPath, bool aFollowLinks, nsIFile** aResult) { if (!xpcomFunctions.newLocalFile) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.newLocalFile(aPath, aFollowLinks, aResult); } XPCOM_API(nsresult) NS_NewNativeLocalFile(const nsACString& aPath, bool aFollowLinks, nsIFile** aResult) { if (!xpcomFunctions.newNativeLocalFile) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.newNativeLocalFile(aPath, aFollowLinks, aResult); } XPCOM_API(nsresult) NS_GetDebug(nsIDebug2** aResult) { if (!xpcomFunctions.getDebug) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.getDebug(aResult); } XPCOM_API(nsresult) NS_StringContainerInit(nsStringContainer& aStr) { if (!xpcomFunctions.stringContainerInit) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.stringContainerInit(aStr); } XPCOM_API(nsresult) NS_StringContainerInit2(nsStringContainer& aStr, const char16_t* aData, uint32_t aDataLength, uint32_t aFlags) { if (!xpcomFunctions.stringContainerInit2) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.stringContainerInit2(aStr, aData, aDataLength, aFlags); } XPCOM_API(void) NS_StringContainerFinish(nsStringContainer& aStr) { if (xpcomFunctions.stringContainerFinish) { xpcomFunctions.stringContainerFinish(aStr); } } XPCOM_API(uint32_t) NS_StringGetData(const nsAString& aStr, const char16_t** aBuf, bool* aTerm) { if (!xpcomFunctions.stringGetData) { *aBuf = nullptr; return 0; } return xpcomFunctions.stringGetData(aStr, aBuf, aTerm); } XPCOM_API(uint32_t) NS_StringGetMutableData(nsAString& aStr, uint32_t aLen, char16_t** aBuf) { if (!xpcomFunctions.stringGetMutableData) { *aBuf = nullptr; return 0; } return xpcomFunctions.stringGetMutableData(aStr, aLen, aBuf); } XPCOM_API(char16_t*) NS_StringCloneData(const nsAString& aStr) { if (!xpcomFunctions.stringCloneData) { return nullptr; } return xpcomFunctions.stringCloneData(aStr); } XPCOM_API(nsresult) NS_StringSetData(nsAString& aStr, const char16_t* aBuf, uint32_t aCount) { if (!xpcomFunctions.stringSetData) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.stringSetData(aStr, aBuf, aCount); } XPCOM_API(nsresult) NS_StringSetDataRange(nsAString& aStr, uint32_t aCutStart, uint32_t aCutLength, const char16_t* aBuf, uint32_t aCount) { if (!xpcomFunctions.stringSetDataRange) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.stringSetDataRange(aStr, aCutStart, aCutLength, aBuf, aCount); } XPCOM_API(nsresult) NS_StringCopy(nsAString& aDest, const nsAString& aSrc) { if (!xpcomFunctions.stringCopy) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.stringCopy(aDest, aSrc); } XPCOM_API(void) NS_StringSetIsVoid(nsAString& aStr, const bool aIsVoid) { if (xpcomFunctions.stringSetIsVoid) { xpcomFunctions.stringSetIsVoid(aStr, aIsVoid); } } XPCOM_API(bool) NS_StringGetIsVoid(const nsAString& aStr) { if (!xpcomFunctions.stringGetIsVoid) { return false; } return xpcomFunctions.stringGetIsVoid(aStr); } XPCOM_API(nsresult) NS_CStringContainerInit(nsCStringContainer& aStr) { if (!xpcomFunctions.cstringContainerInit) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.cstringContainerInit(aStr); } XPCOM_API(nsresult) NS_CStringContainerInit2(nsCStringContainer& aStr, const char* aData, uint32_t aDataLength, uint32_t aFlags) { if (!xpcomFunctions.cstringContainerInit2) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.cstringContainerInit2(aStr, aData, aDataLength, aFlags); } XPCOM_API(void) NS_CStringContainerFinish(nsCStringContainer& aStr) { if (xpcomFunctions.cstringContainerFinish) { xpcomFunctions.cstringContainerFinish(aStr); } } XPCOM_API(uint32_t) NS_CStringGetData(const nsACString& aStr, const char** aBuf, bool* aTerm) { if (!xpcomFunctions.cstringGetData) { *aBuf = nullptr; return 0; } return xpcomFunctions.cstringGetData(aStr, aBuf, aTerm); } XPCOM_API(uint32_t) NS_CStringGetMutableData(nsACString& aStr, uint32_t aLen, char** aBuf) { if (!xpcomFunctions.cstringGetMutableData) { *aBuf = nullptr; return 0; } return xpcomFunctions.cstringGetMutableData(aStr, aLen, aBuf); } XPCOM_API(char*) NS_CStringCloneData(const nsACString& aStr) { if (!xpcomFunctions.cstringCloneData) { return nullptr; } return xpcomFunctions.cstringCloneData(aStr); } XPCOM_API(nsresult) NS_CStringSetData(nsACString& aStr, const char* aBuf, uint32_t aCount) { if (!xpcomFunctions.cstringSetData) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.cstringSetData(aStr, aBuf, aCount); } XPCOM_API(nsresult) NS_CStringSetDataRange(nsACString& aStr, uint32_t aCutStart, uint32_t aCutLength, const char* aBuf, uint32_t aCount) { if (!xpcomFunctions.cstringSetDataRange) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.cstringSetDataRange(aStr, aCutStart, aCutLength, aBuf, aCount); } XPCOM_API(nsresult) NS_CStringCopy(nsACString& aDest, const nsACString& aSrc) { if (!xpcomFunctions.cstringCopy) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.cstringCopy(aDest, aSrc); } XPCOM_API(void) NS_CStringSetIsVoid(nsACString& aStr, const bool aIsVoid) { if (xpcomFunctions.cstringSetIsVoid) { xpcomFunctions.cstringSetIsVoid(aStr, aIsVoid); } } XPCOM_API(bool) NS_CStringGetIsVoid(const nsACString& aStr) { if (!xpcomFunctions.cstringGetIsVoid) { return false; } return xpcomFunctions.cstringGetIsVoid(aStr); } XPCOM_API(nsresult) NS_CStringToUTF16(const nsACString& aSrc, nsCStringEncoding aSrcEncoding, nsAString& aDest) { if (!xpcomFunctions.cstringToUTF16) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.cstringToUTF16(aSrc, aSrcEncoding, aDest); } XPCOM_API(nsresult) NS_UTF16ToCString(const nsAString& aSrc, nsCStringEncoding aDestEncoding, nsACString& aDest) { if (!xpcomFunctions.utf16ToCString) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.utf16ToCString(aSrc, aDestEncoding, aDest); } XPCOM_API(void*) NS_Alloc(size_t aSize) { if (!xpcomFunctions.allocFunc) { return nullptr; } return xpcomFunctions.allocFunc(aSize); } XPCOM_API(void*) NS_Realloc(void* aPtr, size_t aSize) { if (!xpcomFunctions.reallocFunc) { return nullptr; } return xpcomFunctions.reallocFunc(aPtr, aSize); } XPCOM_API(void) NS_Free(void* aPtr) { if (xpcomFunctions.freeFunc) { xpcomFunctions.freeFunc(aPtr); } } XPCOM_API(void) NS_DebugBreak(uint32_t aSeverity, const char* aStr, const char* aExpr, const char* aFile, int32_t aLine) { if (xpcomFunctions.debugBreakFunc) { xpcomFunctions.debugBreakFunc(aSeverity, aStr, aExpr, aFile, aLine); } } XPCOM_API(void) NS_LogInit() { if (xpcomFunctions.logInitFunc) { xpcomFunctions.logInitFunc(); } } XPCOM_API(void) NS_LogTerm() { if (xpcomFunctions.logTermFunc) { xpcomFunctions.logTermFunc(); } } XPCOM_API(void) NS_LogAddRef(void* aPtr, nsrefcnt aNewRefCnt, const char* aTypeName, uint32_t aInstanceSize) { if (xpcomFunctions.logAddRefFunc) xpcomFunctions.logAddRefFunc(aPtr, aNewRefCnt, aTypeName, aInstanceSize); } XPCOM_API(void) NS_LogRelease(void* aPtr, nsrefcnt aNewRefCnt, const char* aTypeName) { if (xpcomFunctions.logReleaseFunc) { xpcomFunctions.logReleaseFunc(aPtr, aNewRefCnt, aTypeName); } } XPCOM_API(void) NS_LogCtor(void* aPtr, const char* aTypeName, uint32_t aInstanceSize) { if (xpcomFunctions.logCtorFunc) { xpcomFunctions.logCtorFunc(aPtr, aTypeName, aInstanceSize); } } XPCOM_API(void) NS_LogDtor(void* aPtr, const char* aTypeName, uint32_t aInstanceSize) { if (xpcomFunctions.logDtorFunc) { xpcomFunctions.logDtorFunc(aPtr, aTypeName, aInstanceSize); } } XPCOM_API(void) NS_LogCOMPtrAddRef(void* aCOMPtr, nsISupports* aObject) { if (xpcomFunctions.logCOMPtrAddRefFunc) { xpcomFunctions.logCOMPtrAddRefFunc(aCOMPtr, aObject); } } XPCOM_API(void) NS_LogCOMPtrRelease(void* aCOMPtr, nsISupports* aObject) { if (xpcomFunctions.logCOMPtrReleaseFunc) { xpcomFunctions.logCOMPtrReleaseFunc(aCOMPtr, aObject); } } XPCOM_API(nsresult) NS_GetXPTCallStub(REFNSIID aIID, nsIXPTCProxy* aOuter, nsISomeInterface** aStub) { if (!xpcomFunctions.getXPTCallStubFunc) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.getXPTCallStubFunc(aIID, aOuter, aStub); } XPCOM_API(void) NS_DestroyXPTCallStub(nsISomeInterface* aStub) { if (xpcomFunctions.destroyXPTCallStubFunc) { xpcomFunctions.destroyXPTCallStubFunc(aStub); } } XPCOM_API(nsresult) NS_InvokeByIndex(nsISupports* aThat, uint32_t aMethodIndex, uint32_t aParamCount, nsXPTCVariant* aParams) { if (!xpcomFunctions.invokeByIndexFunc) { return NS_ERROR_NOT_INITIALIZED; } return xpcomFunctions.invokeByIndexFunc(aThat, aMethodIndex, aParamCount, aParams); } XPCOM_API(bool) NS_CycleCollectorSuspect(nsISupports* aObj) { if (!xpcomFunctions.cycleSuspectFunc) { return false; } return xpcomFunctions.cycleSuspectFunc(aObj); } XPCOM_API(bool) NS_CycleCollectorForget(nsISupports* aObj) { if (!xpcomFunctions.cycleForgetFunc) { return false; } return xpcomFunctions.cycleForgetFunc(aObj); } XPCOM_API(nsPurpleBufferEntry*) NS_CycleCollectorSuspect2(void* aObj, nsCycleCollectionParticipant* aCp) { if (!xpcomFunctions.cycleSuspect2Func) { return nullptr; } return xpcomFunctions.cycleSuspect2Func(aObj, aCp); } XPCOM_API(void) NS_CycleCollectorSuspect3(void* aObj, nsCycleCollectionParticipant* aCp, nsCycleCollectingAutoRefCnt* aRefCnt, bool* aShouldDelete) { if (xpcomFunctions.cycleSuspect3Func) { xpcomFunctions.cycleSuspect3Func(aObj, aCp, aRefCnt, aShouldDelete); } } XPCOM_API(bool) NS_CycleCollectorForget2(nsPurpleBufferEntry* aEntry) { if (!xpcomFunctions.cycleForget2Func) { return false; } return xpcomFunctions.cycleForget2Func(aEntry); }