1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: vtablefactory.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_bridges.hxx"
39 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
41 #include "guardedarray.hxx"
43 #include "bridges/cpp_uno/shared/vtables.hxx"
45 #include "osl/thread.h"
46 #include "osl/security.hxx"
47 #include "osl/file.hxx"
48 #include "osl/diagnose.h"
49 #include "osl/mutex.hxx"
50 #include "rtl/alloc.h"
51 #include "rtl/ustring.hxx"
52 #include "sal/types.h"
53 #include "typelib/typedescription.hxx"
64 #define WIN32_LEAN_AND_MEAN
66 #pragma warning(push,1) // disable warnings within system headers
77 #error Unsupported platform
80 using bridges::cpp_uno::shared::VtableFactory
;
84 extern "C" void * SAL_CALL
allocExec(rtl_arena_type
*, sal_Size
* size
) {
87 #if defined FREEBSD || defined NETBSD
88 pagesize
= getpagesize();
90 pagesize
= sysconf(_SC_PAGESIZE
);
95 pagesize
= info
.dwPageSize
;
96 #elif defined(SAL_OS2)
98 DosQuerySysInfo(QSV_PAGE_SIZE
, QSV_PAGE_SIZE
, &ulPageSize
, sizeof(ULONG
));
99 pagesize
= (sal_Size
)ulPageSize
;
101 #error Unsupported platform
103 sal_Size n
= (*size
+ (pagesize
- 1)) & ~(pagesize
- 1);
107 0, n
, PROT_READ
| PROT_WRITE
, MAP_PRIVATE
| MAP_ANON
, -1,
109 if (p
== MAP_FAILED
) {
112 else if (mprotect (static_cast<char*>(p
), n
, PROT_READ
| PROT_WRITE
| PROT_EXEC
) == -1)
114 munmap (static_cast<char*>(p
), n
);
117 #elif defined SAL_W32
118 p
= VirtualAlloc(0, n
, MEM_COMMIT
, PAGE_EXECUTE_READWRITE
);
119 #elif defined(SAL_OS2)
121 DosAllocMem( &p
, n
, PAG_COMMIT
| PAG_READ
| PAG_WRITE
| OBJ_ANY
);
129 extern "C" void SAL_CALL
freeExec(
130 rtl_arena_type
*, void * address
, sal_Size size
)
133 munmap(static_cast< char * >(address
), size
);
134 #elif defined SAL_W32
135 (void) size
; // unused
136 VirtualFree(address
, 0, MEM_RELEASE
);
137 #elif defined(SAL_OS2)
138 (void) DosFreeMem( address
);
144 class VtableFactory::GuardedBlocks
: public std::vector
< Block
> {
146 GuardedBlocks(VtableFactory
const & factory
):
147 m_factory(factory
), m_guarded(true) {}
151 void unguard() { m_guarded
= false; }
154 GuardedBlocks(GuardedBlocks
&); // not implemented
155 void operator =(GuardedBlocks
); // not implemented
157 VtableFactory
const & m_factory
;
161 VtableFactory::GuardedBlocks::~GuardedBlocks() {
163 for (iterator
i(begin()); i
!= end(); ++i
) {
164 m_factory
.freeBlock(*i
);
169 class VtableFactory::BaseOffset
{
171 BaseOffset(typelib_InterfaceTypeDescription
* type
) { calculate(type
, 0); }
173 sal_Int32
getFunctionOffset(rtl::OUString
const & name
) const
174 { return m_map
.find(name
)->second
; }
178 typelib_InterfaceTypeDescription
* type
, sal_Int32 offset
);
180 typedef std::hash_map
< rtl::OUString
, sal_Int32
, rtl::OUStringHash
> Map
;
185 sal_Int32
VtableFactory::BaseOffset::calculate(
186 typelib_InterfaceTypeDescription
* type
, sal_Int32 offset
)
188 rtl::OUString
name(type
->aBase
.pTypeName
);
189 if (m_map
.find(name
) == m_map
.end()) {
190 for (sal_Int32 i
= 0; i
< type
->nBaseTypes
; ++i
) {
191 offset
= calculate(type
->ppBaseTypes
[i
], offset
);
193 m_map
.insert(Map::value_type(name
, offset
));
194 typelib_typedescription_complete(
195 reinterpret_cast< typelib_TypeDescription
** >(&type
));
196 offset
+= bridges::cpp_uno::shared::getLocalFunctions(type
);
201 VtableFactory::VtableFactory(): m_arena(
203 "bridges::cpp_uno::shared::VtableFactory",
204 sizeof (void *), // to satisfy alignment requirements
205 0, reinterpret_cast< rtl_arena_type
* >(-1), allocExec
, freeExec
, 0))
208 throw std::bad_alloc();
212 VtableFactory::~VtableFactory() {
214 osl::MutexGuard
guard(m_mutex
);
215 for (Map::iterator
i(m_map
.begin()); i
!= m_map
.end(); ++i
) {
216 for (sal_Int32 j
= 0; j
< i
->second
.count
; ++j
) {
217 freeBlock(i
->second
.blocks
[j
]);
219 delete[] i
->second
.blocks
;
222 rtl_arena_destroy(m_arena
);
225 VtableFactory::Vtables
VtableFactory::getVtables(
226 typelib_InterfaceTypeDescription
* type
)
228 rtl::OUString
name(type
->aBase
.pTypeName
);
229 osl::MutexGuard
guard(m_mutex
);
230 Map::iterator
i(m_map
.find(name
));
231 if (i
== m_map
.end()) {
232 GuardedBlocks
blocks(*this);
233 createVtables(blocks
, BaseOffset(type
), type
, true);
235 OSL_ASSERT(blocks
.size() <= SAL_MAX_INT32
);
236 vtables
.count
= static_cast< sal_Int32
>(blocks
.size());
237 bridges::cpp_uno::shared::GuardedArray
< Block
> guardedBlocks(
238 new Block
[vtables
.count
]);
239 vtables
.blocks
= guardedBlocks
.get();
240 for (sal_Int32 j
= 0; j
< vtables
.count
; ++j
) {
241 vtables
.blocks
[j
] = blocks
[j
];
243 i
= m_map
.insert(Map::value_type(name
, vtables
)).first
;
244 guardedBlocks
.release();
250 #ifdef USE_DOUBLE_MMAP
251 bool VtableFactory::createBlock(Block
&block
, sal_Int32 slotCount
) const
253 sal_Size size
= getBlockSize(slotCount
);
254 sal_Size pagesize
= sysconf(_SC_PAGESIZE
);
255 block
.size
= (size
+ (pagesize
- 1)) & ~(pagesize
- 1);
256 block
.start
= block
.exec
= NULL
;
259 osl::Security aSecurity
;
260 rtl::OUString strDirectory
;
261 rtl::OUString strURLDirectory
;
262 if (aSecurity
.getHomeDir(strURLDirectory
))
263 osl::File::getSystemPathFromFileURL(strURLDirectory
, strDirectory
);
265 for (int i
= strDirectory
.getLength() == 0 ? 1 : 0; i
< 2; ++i
)
267 if (!strDirectory
.getLength())
268 strDirectory
= rtl::OUString::createFromAscii("/tmp");
270 strDirectory
+= rtl::OUString::createFromAscii("/.execoooXXXXXX");
271 rtl::OString aTmpName
= rtl::OUStringToOString(strDirectory
, osl_getThreadTextEncoding());
272 char *tmpfname
= new char[aTmpName
.getLength()+1];
273 strncpy(tmpfname
, aTmpName
.getStr(), aTmpName
.getLength()+1);
274 if ((block
.fd
= mkstemp(tmpfname
)) == -1)
275 perror("creation of executable memory area failed");
283 ftruncate(block
.fd
, block
.size
);
284 block
.start
= mmap(NULL
, block
.size
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, block
.fd
, 0);
285 if (block
.start
== MAP_FAILED
) {
288 block
.exec
= mmap(NULL
, block
.size
, PROT_READ
| PROT_EXEC
, MAP_SHARED
, block
.fd
, 0);
289 if (block
.exec
== MAP_FAILED
) {
294 if (block
.start
&& block
.exec
&& block
.fd
!= -1)
299 strDirectory
= rtl::OUString();
301 if (!block
.start
|| !block
.exec
|| block
.fd
== -1)
303 //Fall back to non-doublemmaped allocation
305 block
.start
= block
.exec
= rtl_arena_alloc(m_arena
, &block
.size
);
307 return (block
.start
!= 0 && block
.exec
!= 0);
310 void VtableFactory::freeBlock(Block
const & block
) const {
311 //if the double-map failed we were allocated on the arena
312 if (block
.fd
== -1 && block
.start
== block
.exec
&& block
.start
!= NULL
)
313 rtl_arena_free(m_arena
, block
.start
, block
.size
);
316 if (block
.start
) munmap(block
.start
, block
.size
);
317 if (block
.exec
) munmap(block
.exec
, block
.size
);
318 if (block
.fd
!= -1) close(block
.fd
);
322 bool VtableFactory::createBlock(Block
&block
, sal_Int32 slotCount
) const
324 block
.size
= getBlockSize(slotCount
);
325 block
.start
= rtl_arena_alloc(m_arena
, &block
.size
);
326 return block
.start
!= 0;
329 void VtableFactory::freeBlock(Block
const & block
) const {
330 rtl_arena_free(m_arena
, block
.start
, block
.size
);
334 void VtableFactory::createVtables(
335 GuardedBlocks
& blocks
, BaseOffset
const & baseOffset
,
336 typelib_InterfaceTypeDescription
* type
, bool includePrimary
) const
338 if (includePrimary
) {
340 = bridges::cpp_uno::shared::getPrimaryFunctions(type
);
342 if (!createBlock(block
, slotCount
)) {
343 throw std::bad_alloc();
346 Slot
* slots
= initializeBlock(block
.start
, slotCount
);
347 unsigned char * codeBegin
=
348 reinterpret_cast< unsigned char * >(slots
);
349 unsigned char * code
= codeBegin
;
350 sal_Int32 vtableOffset
= blocks
.size() * sizeof (Slot
*);
351 for (typelib_InterfaceTypeDescription
const * type2
= type
;
352 type2
!= 0; type2
= type2
->pBaseTypeDescription
)
354 code
= addLocalFunctions(
356 #ifdef USE_DOUBLE_MMAP
357 sal_IntPtr(block
.exec
) - sal_IntPtr(block
.start
),
360 baseOffset
.getFunctionOffset(type2
->aBase
.pTypeName
),
361 bridges::cpp_uno::shared::getLocalFunctions(type2
),
364 flushCode(codeBegin
, code
);
365 #ifdef USE_DOUBLE_MMAP
366 //Finished generating block, swap writable pointer with executable
368 ::std::swap(block
.start
, block
.exec
);
370 blocks
.push_back(block
);
376 for (sal_Int32 i
= 0; i
< type
->nBaseTypes
; ++i
) {
377 createVtables(blocks
, baseOffset
, type
->ppBaseTypes
[i
], i
!= 0);