Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "sal/config.h"
21 :
22 : #include <cassert>
23 :
24 : #include "cppu/macros.hxx"
25 : #include "sal/types.h"
26 : #include "typelib/typeclass.h"
27 : #include "typelib/typedescription.h"
28 :
29 : #include "callvirtualmethod.hxx"
30 : #include "share.hxx"
31 :
32 : // The call instruction within the asm block of callVirtualMethod may throw
33 : // exceptions. At least GCC 4.7.0 with -O0 would create (unnecessary)
34 : // .gcc_exception_table call-site table entries around all other calls in this
35 : // function that can throw, leading to std::terminate if the asm call throws an
36 : // exception and the unwinding C++ personality routine finds the unexpected hole
37 : // in the .gcc_exception_table. Therefore, make sure this function explicitly
38 : // only calls nothrow-functions (so GCC 4.7.0 with -O0 happens to not create a
39 : // .gcc_exception_table section at all for this function). For some reason,
40 : // this also needs to be in a source file of its own.
41 : //
42 : // Also, this file should be compiled with -fnon-call-exceptions, and ideally
43 : // there would be a way to tell the compiler that the asm block contains calls
44 : // to functions that can potentially throw; see the mail thread starting at
45 : // <http://gcc.gnu.org/ml/gcc/2012-03/msg00454.html> "C++: Letting compiler know
46 : // asm block can call function that can throw?"
47 :
48 436 : void CPPU_CURRENT_NAMESPACE::callVirtualMethod(
49 : void * pAdjustedThisPtr, sal_Int32 nVtableIndex, void * pRegisterReturn,
50 : typelib_TypeDescription * pReturnTypeDescr, bool bSimpleReturn,
51 : sal_Int32 * pStackLongs, sal_Int32 nStackLongs)
52 : {
53 : // parameter list is mixed list of * and values
54 : // reference parameters are pointers
55 :
56 : assert(pStackLongs && pAdjustedThisPtr);
57 : assert(sizeof (void *) == 4 && sizeof (sal_Int32) == 4);
58 : // unexpected size of int
59 : assert(nStackLongs && pStackLongs); // no stack
60 :
61 : #if defined __clang__ || __GNUC__ == 4 && __GNUC_MINOR__ <= 6
62 : if (! pAdjustedThisPtr) CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something
63 : #endif
64 :
65 436 : volatile long edx = 0, eax = 0; // for register returns
66 : void * stackptr;
67 : asm volatile (
68 : "mov %%esp, %6\n\t"
69 : // preserve potential 128bit stack alignment
70 : "and $0xfffffff0, %%esp\n\t"
71 : "mov %0, %%eax\n\t"
72 : "lea -4(,%%eax,4), %%eax\n\t"
73 : "and $0xf, %%eax\n\t"
74 : "sub $0xc, %%eax\n\t"
75 : "add %%eax, %%esp\n\t"
76 : // copy values
77 : "mov %0, %%eax\n\t"
78 : "mov %%eax, %%edx\n\t"
79 : "dec %%edx\n\t"
80 : "shl $2, %%edx\n\t"
81 : "add %1, %%edx\n"
82 : "Lcopy:\n\t"
83 : "pushl 0(%%edx)\n\t"
84 : "sub $4, %%edx\n\t"
85 : "dec %%eax\n\t"
86 : "jne Lcopy\n\t"
87 : // do the actual call
88 : "mov %2, %%edx\n\t"
89 : "mov 0(%%edx), %%edx\n\t"
90 : "mov %3, %%eax\n\t"
91 : "shl $2, %%eax\n\t"
92 : "add %%eax, %%edx\n\t"
93 : "mov 0(%%edx), %%edx\n\t"
94 : "call *%%edx\n\t"
95 : // save return registers
96 : "mov %%eax, %4\n\t"
97 : "mov %%edx, %5\n\t"
98 : // cleanup stack
99 : "mov %6, %%esp\n\t"
100 : :
101 : : "m"(nStackLongs), "m"(pStackLongs), "m"(pAdjustedThisPtr),
102 : "m"(nVtableIndex), "m"(eax), "m"(edx), "m"(stackptr)
103 436 : : "eax", "ecx", "edx" );
104 353 : switch( pReturnTypeDescr->eTypeClass )
105 : {
106 : case typelib_TypeClass_VOID:
107 139 : break;
108 : case typelib_TypeClass_HYPER:
109 : case typelib_TypeClass_UNSIGNED_HYPER:
110 2 : ((long*)pRegisterReturn)[1] = edx;
111 : case typelib_TypeClass_LONG:
112 : case typelib_TypeClass_UNSIGNED_LONG:
113 : case typelib_TypeClass_CHAR:
114 : case typelib_TypeClass_ENUM:
115 39 : ((long*)pRegisterReturn)[0] = eax;
116 39 : break;
117 : case typelib_TypeClass_SHORT:
118 : case typelib_TypeClass_UNSIGNED_SHORT:
119 2 : *(unsigned short*)pRegisterReturn = eax;
120 2 : break;
121 : case typelib_TypeClass_BOOLEAN:
122 : case typelib_TypeClass_BYTE:
123 11 : *(unsigned char*)pRegisterReturn = eax;
124 11 : break;
125 : case typelib_TypeClass_FLOAT:
126 1 : asm ( "fstps %0" : : "m"(*(char *)pRegisterReturn) );
127 1 : break;
128 : case typelib_TypeClass_DOUBLE:
129 34 : asm ( "fstpl %0\n\t" : : "m"(*(char *)pRegisterReturn) );
130 34 : break;
131 : default:
132 : {
133 : #if defined (FREEBSD) || defined(NETBSD) || defined(OPENBSD) || defined(MACOSX) || \
134 : defined(DRAGONFLY)
135 : sal_Int32 const nRetSize = pReturnTypeDescr->nSize;
136 : if (bSimpleReturn && nRetSize <= 8 && nRetSize > 0)
137 : {
138 : if (nRetSize > 4)
139 : static_cast<long *>(pRegisterReturn)[1] = edx;
140 : static_cast<long *>(pRegisterReturn)[0] = eax;
141 : }
142 : #else
143 : (void)bSimpleReturn;
144 : #endif
145 127 : break;
146 : }
147 : }
148 353 : }
149 :
150 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|