1
0
Fork 0
libreoffice/bridges/source/cpp_uno/msvc_win32_intel/cpp2uno.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

228 lines
6.2 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* 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/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <sal/config.h>
#include <typeinfo>
#include <malloc.h>
#include <com/sun/star/uno/genfunc.hxx>
#include <sal/log.hxx>
#include <uno/data.h>
#include <typelib/typedescription.hxx>
#include "bridge.hxx"
#include "cppinterfaceproxy.hxx"
#include "types.hxx"
#include "vtablefactory.hxx"
#include <msvc/x86.hxx>
#include <msvc/cpp2uno.hxx>
using namespace ::com::sun::star;
namespace
{
/**
* is called on incoming vtable calls
* (called by asm snippets)
*/
static __declspec(naked) void __cdecl cpp_vtable_call()
{
__asm
{
sub esp, 8 // space for immediate return type
push esp
push edx // vtable offset
push eax // function index
mov eax, esp
add eax, 20
push eax // original stack ptr
call cpp_mediate
add esp, 16
cmp eax, typelib_TypeClass_FLOAT
je Lfloat
cmp eax, typelib_TypeClass_DOUBLE
je Ldouble
cmp eax, typelib_TypeClass_HYPER
je Lhyper
cmp eax, typelib_TypeClass_UNSIGNED_HYPER
je Lhyper
// rest is eax
pop eax
add esp, 4
ret
Lhyper:
pop eax
pop edx
ret
Lfloat:
fld dword ptr [esp]
add esp, 8
ret
Ldouble:
fld qword ptr [esp]
add esp, 8
ret
}
}
int const codeSnippetSize = 16;
unsigned char * codeSnippet(
unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset)
{
unsigned char * p = code;
static_assert(sizeof (sal_Int32) == 4, "boo");
// mov eax, functionIndex:
*p++ = 0xB8;
*reinterpret_cast< sal_Int32 * >(p) = functionIndex;
p += sizeof (sal_Int32);
// mov edx, vtableOffset:
*p++ = 0xBA;
*reinterpret_cast< sal_Int32 * >(p) = vtableOffset;
p += sizeof (sal_Int32);
// jmp rel32 cpp_vtable_call:
*p++ = 0xE9;
*reinterpret_cast< sal_Int32 * >(p)
= ((unsigned char *) cpp_vtable_call) - p - sizeof (sal_Int32);
p += sizeof (sal_Int32);
assert(p - code <= codeSnippetSize);
return code + codeSnippetSize;
}
}
struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
bridges::cpp_uno::shared::VtableFactory::Slot *
bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
{
return static_cast< Slot * >(block) + 1;
}
std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
sal_Int32 slotCount)
{
return (slotCount + 1) * sizeof (Slot) + slotCount * codeSnippetSize;
}
namespace {
// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast
// on such proxy objects not crash:
struct ProxyRtti {};
// The following vtable RTTI data is based on how the code at
// <https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/MicrosoftCXXABI.cpp> computes
// such data:
struct RttiClassHierarchyDescriptor;
#pragma warning (push)
#pragma warning (disable: 4324) // "structure was padded due to alignment specifier"
struct alignas(16) RttiBaseClassDescriptor {
sal_uInt32 n0 = reinterpret_cast<sal_uInt32>(&typeid(ProxyRtti));
sal_uInt32 n1 = 0;
sal_uInt32 n2 = 0;
sal_uInt32 n3 = 0xFFFFFFFF;
sal_uInt32 n4 = 0;
sal_uInt32 n5 = 0x40;
sal_uInt32 n6;
RttiBaseClassDescriptor(RttiClassHierarchyDescriptor const * chd):
n6(reinterpret_cast<sal_uInt32>(chd)) {}
};
struct alignas(4) RttiBaseClassArray {
sal_uInt32 n0;
sal_uInt32 n1 = 0;
RttiBaseClassArray(RttiBaseClassDescriptor const * bcd): n0(reinterpret_cast<sal_uInt32>(bcd))
{}
};
struct alignas(4) RttiClassHierarchyDescriptor {
sal_uInt32 n0 = 0;
sal_uInt32 n1 = 0;
sal_uInt32 n2 = 1;
sal_uInt32 n3;
RttiClassHierarchyDescriptor(RttiBaseClassArray const * bca):
n3(reinterpret_cast<sal_uInt32>(bca)) {}
};
struct alignas(16) RttiCompleteObjectLocator {
sal_uInt32 n0 = 0;
sal_uInt32 n1 = 0;
sal_uInt32 n2 = 0;
sal_uInt32 n3 = reinterpret_cast<sal_uInt32>(&typeid(ProxyRtti));
sal_uInt32 n4;
RttiCompleteObjectLocator(RttiClassHierarchyDescriptor const * chd):
n4(reinterpret_cast<sal_uInt32>(chd)) {}
};
struct Rtti {
RttiBaseClassDescriptor bcd;
RttiBaseClassArray bca;
RttiClassHierarchyDescriptor chd;
RttiCompleteObjectLocator col;
Rtti(): bcd(&chd), bca(&bcd), chd(&bca), col(&chd) {}
};
#pragma warning (pop)
}
bridges::cpp_uno::shared::VtableFactory::Slot *
bridges::cpp_uno::shared::VtableFactory::initializeBlock(
void * block, sal_Int32 slotCount, sal_Int32,
typelib_InterfaceTypeDescription *)
{
static Rtti rtti;
Slot * slots = mapBlockToVtable(block);
slots[-1].fn = &rtti.col;
return slots + slotCount;
}
unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
Slot ** slots, unsigned char * code,
typelib_InterfaceTypeDescription const *, sal_Int32 functionOffset,
sal_Int32 functionCount, sal_Int32 vtableOffset)
{
(*slots) -= functionCount;
Slot * s = *slots;
for (sal_Int32 i = 0; i < functionCount; ++i) {
(s++)->fn = code;
code = codeSnippet(code, functionOffset++, vtableOffset);
}
return code;
}
void bridges::cpp_uno::shared::VtableFactory::flushCode(
unsigned char const *,
unsigned char const *)
{
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */