Update ooo320-m1
[ooovba.git] / bridges / source / cpp_uno / shared / vtablefactory.cxx
blob2bf3fef1bb06b17c432b3f670be5963abb4ddc86
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: vtablefactory.cxx,v $
10 * $Revision: 1.11 $
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"
34 #if defined OS2
35 #define INCL_DOS
36 #define INCL_DOSMISC
37 #endif
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"
55 #include <hash_map>
56 #include <new>
57 #include <vector>
59 #if defined SAL_UNX
60 #include <unistd.h>
61 #include <string.h>
62 #include <sys/mman.h>
63 #elif defined SAL_W32
64 #define WIN32_LEAN_AND_MEAN
65 #ifdef _MSC_VER
66 #pragma warning(push,1) // disable warnings within system headers
67 #endif
68 #include <windows.h>
69 #ifdef _MSC_VER
70 #pragma warning(pop)
71 #endif
72 #elif defined SAL_OS2
73 #define INCL_DOS
74 #define INCL_DOSMISC
75 #include <os2.h>
76 #else
77 #error Unsupported platform
78 #endif
80 using bridges::cpp_uno::shared::VtableFactory;
82 namespace {
84 extern "C" void * SAL_CALL allocExec(rtl_arena_type *, sal_Size * size) {
85 sal_Size pagesize;
86 #if defined SAL_UNX
87 #if defined FREEBSD || defined NETBSD
88 pagesize = getpagesize();
89 #else
90 pagesize = sysconf(_SC_PAGESIZE);
91 #endif
92 #elif defined SAL_W32
93 SYSTEM_INFO info;
94 GetSystemInfo(&info);
95 pagesize = info.dwPageSize;
96 #elif defined(SAL_OS2)
97 ULONG ulPageSize;
98 DosQuerySysInfo(QSV_PAGE_SIZE, QSV_PAGE_SIZE, &ulPageSize, sizeof(ULONG));
99 pagesize = (sal_Size)ulPageSize;
100 #else
101 #error Unsupported platform
102 #endif
103 sal_Size n = (*size + (pagesize - 1)) & ~(pagesize - 1);
104 void * p;
105 #if defined SAL_UNX
106 p = mmap(
107 0, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1,
109 if (p == MAP_FAILED) {
110 p = 0;
112 else if (mprotect (static_cast<char*>(p), n, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
114 munmap (static_cast<char*>(p), n);
115 p = 0;
117 #elif defined SAL_W32
118 p = VirtualAlloc(0, n, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
119 #elif defined(SAL_OS2)
120 p = 0;
121 DosAllocMem( &p, n, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_ANY);
122 #endif
123 if (p != 0) {
124 *size = n;
126 return p;
129 extern "C" void SAL_CALL freeExec(
130 rtl_arena_type *, void * address, sal_Size size)
132 #if defined SAL_UNX
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);
139 #endif
144 class VtableFactory::GuardedBlocks: public std::vector< Block > {
145 public:
146 GuardedBlocks(VtableFactory const & factory):
147 m_factory(factory), m_guarded(true) {}
149 ~GuardedBlocks();
151 void unguard() { m_guarded = false; }
153 private:
154 GuardedBlocks(GuardedBlocks &); // not implemented
155 void operator =(GuardedBlocks); // not implemented
157 VtableFactory const & m_factory;
158 bool m_guarded;
161 VtableFactory::GuardedBlocks::~GuardedBlocks() {
162 if (m_guarded) {
163 for (iterator i(begin()); i != end(); ++i) {
164 m_factory.freeBlock(*i);
169 class VtableFactory::BaseOffset {
170 public:
171 BaseOffset(typelib_InterfaceTypeDescription * type) { calculate(type, 0); }
173 sal_Int32 getFunctionOffset(rtl::OUString const & name) const
174 { return m_map.find(name)->second; }
176 private:
177 sal_Int32 calculate(
178 typelib_InterfaceTypeDescription * type, sal_Int32 offset);
180 typedef std::hash_map< rtl::OUString, sal_Int32, rtl::OUStringHash > Map;
182 Map m_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);
198 return offset;
201 VtableFactory::VtableFactory(): m_arena(
202 rtl_arena_create(
203 "bridges::cpp_uno::shared::VtableFactory",
204 sizeof (void *), // to satisfy alignment requirements
205 0, reinterpret_cast< rtl_arena_type * >(-1), allocExec, freeExec, 0))
207 if (m_arena == 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);
234 Vtables vtables;
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();
245 blocks.unguard();
247 return i->second;
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;
257 block.fd = -1;
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");
276 if (block.fd == -1)
278 delete[] tmpfname;
279 break;
281 unlink(tmpfname);
282 delete[] tmpfname;
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) {
286 block.start = 0;
288 block.exec = mmap(NULL, block.size, PROT_READ | PROT_EXEC, MAP_SHARED, block.fd, 0);
289 if (block.exec == MAP_FAILED) {
290 block.exec = 0;
293 //All good
294 if (block.start && block.exec && block.fd != -1)
295 break;
297 freeBlock(block);
299 strDirectory = rtl::OUString();
301 if (!block.start || !block.exec || block.fd == -1)
303 //Fall back to non-doublemmaped allocation
304 block.fd = -1;
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);
314 else
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);
321 #else
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);
332 #endif
334 void VtableFactory::createVtables(
335 GuardedBlocks & blocks, BaseOffset const & baseOffset,
336 typelib_InterfaceTypeDescription * type, bool includePrimary) const
338 if (includePrimary) {
339 sal_Int32 slotCount
340 = bridges::cpp_uno::shared::getPrimaryFunctions(type);
341 Block block;
342 if (!createBlock(block, slotCount)) {
343 throw std::bad_alloc();
345 try {
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(
355 &slots, code,
356 #ifdef USE_DOUBLE_MMAP
357 sal_IntPtr(block.exec) - sal_IntPtr(block.start),
358 #endif
359 type2,
360 baseOffset.getFunctionOffset(type2->aBase.pTypeName),
361 bridges::cpp_uno::shared::getLocalFunctions(type2),
362 vtableOffset);
364 flushCode(codeBegin, code);
365 #ifdef USE_DOUBLE_MMAP
366 //Finished generating block, swap writable pointer with executable
367 //pointer
368 ::std::swap(block.start, block.exec);
369 #endif
370 blocks.push_back(block);
371 } catch (...) {
372 freeBlock(block);
373 throw;
376 for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) {
377 createVtables(blocks, baseOffset, type->ppBaseTypes[i], i != 0);