diff options
Diffstat (limited to 'sources/shiboken2')
39 files changed, 4025 insertions, 941 deletions
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp index ce582d21a..d76c788ec 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -2647,7 +2647,7 @@ bool AbstractMetaBuilderPrivate::isQObject(const FileModelItem &dom, const QStri classItem = ns->findClass(names.at(names.size() - 1)); } - if (classItem == nullptr) + if (!classItem) return false; if (classItem->extendsClass(QLatin1String("QObject"))) diff --git a/sources/shiboken2/CMakeLists.txt b/sources/shiboken2/CMakeLists.txt index 60ab7878f..5720ff554 100644 --- a/sources/shiboken2/CMakeLists.txt +++ b/sources/shiboken2/CMakeLists.txt @@ -335,18 +335,6 @@ if (SANITIZE_ADDRESS AND NOT MSVC) set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_STANDARD_LIBRARIES} -fsanitize=address") endif() -add_subdirectory(ApiExtractor) - -set(generator_plugin_DIR ${LIB_INSTALL_DIR}/generatorrunner${generator_SUFFIX}) - -# uninstall target -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" - IMMEDIATE @ONLY) -add_custom_target(uninstall "${CMAKE_COMMAND}" - -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") - - # Detect if the python libs were compiled in debug mode # On Linux distros there is no standard way to check that. execute_process( @@ -390,13 +378,30 @@ execute_process( OUTPUT_VARIABLE PYTHON_WITH_COUNT_ALLOCS OUTPUT_STRIP_TRAILING_WHITESPACE) +# On Windows, PYTHON_LIBRARIES can be a list. Example: +# optimized;C:/Python36/libs/python36.lib;debug;C:/Python36/libs/python36_d.lib +# On other platforms, this result is not used at all. +execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c "if True: + for lib in '${PYTHON_LIBRARIES}'.split(';'): + if '/' in lib: + prefix, py = lib.rsplit('/', 1) + if py.startswith('python3'): + print(prefix + '/python3.lib') + break + " + OUTPUT_VARIABLE PYTHON_LIMITED_LIBRARIES + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(SHIBOKEN_BUILD_TYPE "Release") -# We do not want to link against the python shared / static library on Linux And macOS. +# We do not want to link against the python shared / static library on Linux and macOS. # The dynamic linker will pick up the python symbols at runtime automatically. # On Windows we do need to link against the python.lib import library. set(SBK_PYTHON_LIBRARIES "") +option(FORCE_LIMITED_API "Enable the limited API." "no") +set(PYTHON_LIMITED_API 0) if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(NOT PYTHON_DEBUG_LIBRARIES) message(WARNING "Python debug shared library not found; assuming python was built with shared library support disabled.") @@ -420,11 +425,32 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(SBK_PYTHON_LIBRARIES ${PYTHON_DEBUG_LIBRARIES}) endif() set(SHIBOKEN_BUILD_TYPE "Debug") -else() +endif() +if(FORCE_LIMITED_API STREQUAL "yes") + if (${PYTHON_VERSION_MAJOR} EQUAL 3 AND ${PYTHON_VERSION_MINOR} GREATER 4) + # GREATER_EQUAL is available only from cmake 3.7 on. We mean python 3.5 . + add_definitions("-DPy_LIMITED_API=0x03050000") + set(PYTHON_LIMITED_API 1) + endif() if(WIN32) set(SBK_PYTHON_LIBRARIES ${PYTHON_LIBRARIES}) + if (${PYTHON_VERSION_MAJOR} EQUAL 3 AND ${PYTHON_VERSION_MINOR} GREATER 4) + # PYSIDE-560: XXX maybe add an option to setup.py as override + set(SBK_PYTHON_LIBRARIES ${PYTHON_LIMITED_LIBRARIES}) + endif() + endif() + if (CMAKE_BUILD_TYPE STREQUAL "Release") + add_definitions("-DNDEBUG") endif() - add_definitions("-DNDEBUG") +endif() + +if (PYTHON_LIMITED_API) + if (WIN32 AND NOT EXISTS "${PYTHON_LIMITED_LIBRARIES}") + message(FATAL_ERROR "The Limited API was enabled, but ${PYTHON_LIMITED_LIBRARIES} was not found!") + endif() + message(STATUS "******************************************************") + message(STATUS "** Limited API enabled ${PYTHON_LIMITED_LIBRARIES}") + message(STATUS "******************************************************") endif() if(APPLE) @@ -437,6 +463,17 @@ else() set(SBK_PYTHON_INCLUDE_DIR ${PYTHON_INCLUDE_DIRS}) endif() +add_subdirectory(ApiExtractor) + +set(generator_plugin_DIR ${LIB_INSTALL_DIR}/generatorrunner${generator_SUFFIX}) + +# uninstall target +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) +add_custom_target(uninstall "${CMAKE_COMMAND}" + -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") + add_subdirectory(libshiboken) add_subdirectory(doc) diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index d7c04d3c9..bd654f17c 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -214,6 +214,8 @@ static QString chopType(QString s) { if (s.endsWith(QLatin1String("_Type"))) s.chop(5); + else if (s.endsWith(QLatin1String("_TypeF()"))) + s.chop(8); return s; } @@ -665,7 +667,7 @@ QString CppGenerator::getVirtualFunctionReturnTypeName(const AbstractMetaFunctio if (func->type()->isPrimitive()) return QLatin1Char('"') + func->type()->name() + QLatin1Char('"'); - return QString::fromLatin1("Shiboken::SbkType< %1 >()->tp_name").arg(func->type()->typeEntry()->qualifiedCppName()); + return QString::fromLatin1("PepType(Shiboken::SbkType< %1 >())->tp_name").arg(func->type()->typeEntry()->qualifiedCppName()); } void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFunction* func) @@ -892,7 +894,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun s << INDENT << "Shiboken::warning(PyExc_RuntimeWarning, 2, "\ "\"Invalid return value in function %s, expected %s, got %s.\", \""; s << func->ownerClass()->name() << '.' << funcName << "\", " << getVirtualFunctionReturnTypeName(func); - s << ", " PYTHON_RETURN_VAR "->ob_type->tp_name);" << endl; + s << ", PepType(Py_TYPE(" PYTHON_RETURN_VAR "))->tp_name);" << endl; s << INDENT << "return " << defaultReturnExpr << ';' << endl; } s << INDENT << '}' << endl; @@ -912,7 +914,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun s << INDENT << "Shiboken::warning(PyExc_RuntimeWarning, 2, "\ "\"Invalid return value in function %s, expected %s, got %s.\", \""; s << func->ownerClass()->name() << '.' << funcName << "\", " << getVirtualFunctionReturnTypeName(func); - s << ", " PYTHON_RETURN_VAR "->ob_type->tp_name);" << endl; + s << ", PepType(Py_TYPE(" PYTHON_RETURN_VAR "))->tp_name);" << endl; s << INDENT << "return " << defaultReturnExpr << ';' << endl; } s << INDENT << '}' << endl; @@ -1144,11 +1146,11 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla QString targetTypeName = metaClass->name() + QLatin1String("_PTR"); QString code; QTextStream c(&code); - c << INDENT << "Shiboken::Conversions::pythonToCppPointer(&" << cpythonType << ", pyIn, cppOut);"; + c << INDENT << "Shiboken::Conversions::pythonToCppPointer(" << cpythonType << ", pyIn, cppOut);"; writePythonToCppFunction(s, code, sourceTypeName, targetTypeName); // "Is convertible" function for the Python object to C++ pointer conversion. - QString pyTypeCheck = QStringLiteral("PyObject_TypeCheck(pyIn, (PyTypeObject*)&%1)").arg(cpythonType); + QString pyTypeCheck = QStringLiteral("PyObject_TypeCheck(pyIn, (PyTypeObject*)%1)").arg(cpythonType); writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, pyTypeCheck, QString(), true); s << endl; @@ -1157,7 +1159,7 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla code.clear(); if (usePySideExtensions() && metaClass->isQObject()) { - c << INDENT << "return PySide::getWrapperForQObject((" << typeName << "*)cppIn, &" << cpythonType << ");" << endl; + c << INDENT << "return PySide::getWrapperForQObject((" << typeName << "*)cppIn, " << cpythonType << ");" << endl; } else { c << INDENT << "PyObject* pyOut = (PyObject*)Shiboken::BindingManager::instance().retrieveWrapper(cppIn);" << endl; c << INDENT << "if (pyOut) {" << endl; @@ -1168,7 +1170,7 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla } c << INDENT << '}' << endl; c << INDENT << "const char* typeName = typeid(*((" << typeName << "*)cppIn)).name();" << endl; - c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType; + c << INDENT << "return Shiboken::Object::newObject(" << cpythonType; c << ", const_cast<void*>(cppIn), false, false, typeName);"; } std::swap(targetTypeName, sourceTypeName); @@ -1197,7 +1199,7 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla else computedWrapperName = wrapperName(classContext.preciseType()); - c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType << ", new ::" << computedWrapperName; + c << INDENT << "return Shiboken::Object::newObject(" << cpythonType << ", new ::" << computedWrapperName; c << "(*((" << typeName << "*)cppIn)), true, true);"; writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName); s << endl; @@ -1329,7 +1331,7 @@ void CppGenerator::writeConverterRegister(QTextStream &s, const AbstractMetaClas if (metaClass->isNamespace()) return; s << INDENT << "// Register Converter" << endl; - s << INDENT << "SbkConverter* converter = Shiboken::Conversions::createConverter(&"; + s << INDENT << "SbkConverter* converter = Shiboken::Conversions::createConverter("; s << cpythonTypeName(metaClass) << ',' << endl; { Indentation indent(INDENT); @@ -2324,7 +2326,7 @@ void CppGenerator::writePythonToCppTypeConversion(QTextStream& s, if (!defaultValue.isEmpty()) s << '{' << endl << INDENT; - s << "if (Shiboken::Conversions::isImplicitConversion(reinterpret_cast<const SbkObjectType *>(" + s << "if (Shiboken::Conversions::isImplicitConversion(reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(type) << "), " << pythonToCppFunc << "))" << endl; { Indentation indent(INDENT); @@ -2838,7 +2840,7 @@ void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s, if (toNative->sourceType()) inType = cpythonTypeNameExt(toNative->sourceType()); else - inType = QString::fromLatin1("(&%1_Type)").arg(toNative->sourceTypeName()); + inType = QString::fromLatin1("(%1_TypeF())").arg(toNative->sourceTypeName()); code.replace(QLatin1String("%INTYPE"), inType); code.replace(QLatin1String("%OUTTYPE"), targetType->qualifiedCppName()); code.replace(QLatin1String("%in"), QLatin1String("pyIn")); @@ -3698,24 +3700,20 @@ void CppGenerator::writeClassDefinition(QTextStream &s, } if (!metaClass->baseClass()) - baseClassName = QLatin1String("reinterpret_cast<PyTypeObject*>(&SbkObject_Type)"); + baseClassName = QLatin1String("reinterpret_cast<PyTypeObject*>(SbkObject_TypeF())"); bool onlyPrivCtor = !metaClass->hasNonPrivateConstructor(); const AbstractMetaClass *qCoreApp = AbstractMetaClass::findClass(classes(), QLatin1String("QCoreApplication")); const bool isQApp = qCoreApp != Q_NULLPTR && metaClass->inheritsFrom(qCoreApp); + tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES"); if (metaClass->isNamespace() || metaClass->hasPrivateDestructor()) { - tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES"); tp_dealloc = metaClass->hasPrivateDestructor() ? - QLatin1String("SbkDeallocWrapperWithPrivateDtor") : QLatin1String("0"); + QLatin1String("SbkDeallocWrapperWithPrivateDtor") : + QLatin1String("SbkDummyDealloc /* PYSIDE-595: Prevent replacement of \"0\" with subtype_dealloc. */"); tp_init = QLatin1String("0"); } else { - if (onlyPrivCtor) - tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES"); - else - tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES"); - QString deallocClassName; if (shouldGenerateCppWrapper(metaClass)) deallocClassName = wrapperName(metaClass); @@ -3741,7 +3739,21 @@ void CppGenerator::writeClassDefinition(QTextStream &s, } if (metaClass->hasPrivateDestructor() || onlyPrivCtor) { - tp_new = QLatin1String("0"); + // tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES"); + // This is not generally possible, because PySide does not care about + // privacy the same way. This worked before the heap types were used, + // because inheritance is not really checked for static types. + // Instead, we check this at runtime, see SbkObjectTypeTpNew. + if (metaClass->fullName().startsWith(QLatin1String("PySide2.Qt"))) { + // PYSIDE-595: No idea how to do non-inheritance correctly. + // Since that is only relevant in shiboken, I used a shortcut for + // PySide. + tp_new = QLatin1String("SbkObjectTpNew"); + } + else { + tp_new = QLatin1String("SbkDummyNew /* PYSIDE-595: Prevent replacement " + "of \"0\" with base->tp_new. */"); + } tp_flags.append(QLatin1String("|Py_TPFLAGS_HAVE_GC")); } else if (isQApp) { @@ -3782,6 +3794,9 @@ void CppGenerator::writeClassDefinition(QTextStream &s, s << endl; } + s << "// Class Definition -----------------------------------------------" << endl; + s << "extern \"C\" {" << endl; + if (!metaClass->typeEntry()->hashFunction().isEmpty()) tp_hash = QLatin1Char('&') + cpythonBaseName(metaClass) + QLatin1String("_HashFunc"); @@ -3789,83 +3804,65 @@ void CppGenerator::writeClassDefinition(QTextStream &s, if (callOp && !callOp->isModifiedRemoved()) tp_call = QLatin1Char('&') + cpythonFunctionName(callOp); - s << "// Class Definition -----------------------------------------------" << endl; - s << "extern \"C\" {" << endl; - - if (supportsNumberProtocol(metaClass)) { - s << "static PyNumberMethods " << className + QLatin1String("_TypeAsNumber") << ";" << endl; - s << endl; - } - - if (supportsSequenceProtocol(metaClass)) { - s << "static PySequenceMethods " << className + QLatin1String("_TypeAsSequence") << ";" << endl; - s << endl; - } - - if (supportsMappingProtocol(metaClass)) { - s << "static PyMappingMethods " << className + QLatin1String("_TypeAsMapping") << ";" << endl; - s << endl; - } - - s << "static SbkObjectType " << className + QLatin1String("_Type") << " = { { {" << endl; - s << INDENT << "PyVarObject_HEAD_INIT(&SbkObjectType_Type, 0)" << endl; QString computedClassTargetFullName; if (!classContext.forSmartPointer()) computedClassTargetFullName = getClassTargetFullName(metaClass); else computedClassTargetFullName = getClassTargetFullName(classContext.preciseType()); - s << INDENT << "/*tp_name*/ \"" << computedClassTargetFullName << "\"," << endl; - s << INDENT << "/*tp_basicsize*/ sizeof(SbkObject)," << endl; - s << INDENT << "/*tp_itemsize*/ 0," << endl; - s << INDENT << "/*tp_dealloc*/ " << tp_dealloc << ',' << endl; - s << INDENT << "/*tp_print*/ 0," << endl; - s << INDENT << "/*tp_getattr*/ 0," << endl; - s << INDENT << "/*tp_setattr*/ 0," << endl; - s << INDENT << "/*tp_compare*/ 0," << endl; - s << INDENT << "/*tp_repr*/ " << m_tpFuncs[QLatin1String("__repr__")] << "," << endl; - s << INDENT << "/*tp_as_number*/ 0," << endl; - s << INDENT << "/*tp_as_sequence*/ 0," << endl; - s << INDENT << "/*tp_as_mapping*/ 0," << endl; - s << INDENT << "/*tp_hash*/ " << tp_hash << ',' << endl; - s << INDENT << "/*tp_call*/ " << tp_call << ',' << endl; - s << INDENT << "/*tp_str*/ " << m_tpFuncs[QLatin1String("__str__")] << ',' << endl; - s << INDENT << "/*tp_getattro*/ " << tp_getattro << ',' << endl; - s << INDENT << "/*tp_setattro*/ " << tp_setattro << ',' << endl; - s << INDENT << "/*tp_as_buffer*/ 0," << endl; - s << INDENT << "/*tp_flags*/ " << tp_flags << ',' << endl; - s << INDENT << "/*tp_doc*/ 0," << endl; - s << INDENT << "/*tp_traverse*/ " << className << "_traverse," << endl; - s << INDENT << "/*tp_clear*/ " << className << "_clear," << endl; - s << INDENT << "/*tp_richcompare*/ " << tp_richcompare << ',' << endl; - s << INDENT << "/*tp_weaklistoffset*/ 0," << endl; - s << INDENT << "/*tp_iter*/ " << m_tpFuncs[QLatin1String("__iter__")] << ',' << endl; - s << INDENT << "/*tp_iternext*/ " << m_tpFuncs[QLatin1String("__next__")] << ',' << endl; - s << INDENT << "/*tp_methods*/ " << className << "_methods," << endl; - s << INDENT << "/*tp_members*/ 0," << endl; - s << INDENT << "/*tp_getset*/ " << tp_getset << ',' << endl; - s << INDENT << "/*tp_base*/ " << baseClassName << ',' << endl; - s << INDENT << "/*tp_dict*/ 0," << endl; - s << INDENT << "/*tp_descr_get*/ 0," << endl; - s << INDENT << "/*tp_descr_set*/ 0," << endl; - s << INDENT << "/*tp_dictoffset*/ 0," << endl; - s << INDENT << "/*tp_init*/ " << tp_init << ',' << endl; - s << INDENT << "/*tp_alloc*/ 0," << endl; - s << INDENT << "/*tp_new*/ " << tp_new << ',' << endl; - s << INDENT << "/*tp_free*/ 0," << endl; - s << INDENT << "/*tp_is_gc*/ 0," << endl; - s << INDENT << "/*tp_bases*/ 0," << endl; - s << INDENT << "/*tp_mro*/ 0," << endl; - s << INDENT << "/*tp_cache*/ 0," << endl; - s << INDENT << "/*tp_subclasses*/ 0," << endl; - s << INDENT << "/*tp_weaklist*/ 0" << endl; - s << "}, }," << endl; - s << INDENT << "/*priv_data*/ 0" << endl; - s << "};" << endl; QString suffix; if (isObjectType(metaClass)) suffix = QLatin1String("*"); - s << "} //extern" << endl; + const QString typePtr = QLatin1String("_") + className + + QLatin1String("_Type"); + s << "static SbkObjectType *" << typePtr << " = nullptr;" << endl; + s << "static SbkObjectType *" << className << "_TypeF(void)" << endl; + s << "{" << endl; + s << INDENT << "return " << typePtr << ";" << endl; + s << "}" << endl; + s << endl; + s << "static PyType_Slot " << className << "_slots[] = {" << endl; + s << INDENT << "{Py_tp_base, (void *)0}, // inserted by introduceWrapperType" << endl; + s << INDENT << "{Py_tp_dealloc, (void *)" << tp_dealloc << "}," << endl; + s << INDENT << "{Py_tp_repr, (void *)" << m_tpFuncs[QLatin1String("__repr__")] << "}," << endl; + s << INDENT << "{Py_tp_hash, (void *)" << tp_hash << "}," << endl; + s << INDENT << "{Py_tp_call, (void *)" << tp_call << "}," << endl; + s << INDENT << "{Py_tp_str, (void *)" << m_tpFuncs[QLatin1String("__str__")] << "}," << endl; + s << INDENT << "{Py_tp_getattro, (void *)" << tp_getattro << "}," << endl; + s << INDENT << "{Py_tp_setattro, (void *)" << tp_setattro << "}," << endl; + s << INDENT << "{Py_tp_traverse, (void *)" << className << "_traverse}," << endl; + s << INDENT << "{Py_tp_clear, (void *)" << className << "_clear}," << endl; + s << INDENT << "{Py_tp_richcompare, (void *)" << tp_richcompare << "}," << endl; + s << INDENT << "{Py_tp_iter, (void *)" << m_tpFuncs[QLatin1String("__iter__")] << "}," << endl; + s << INDENT << "{Py_tp_iternext, (void *)" << m_tpFuncs[QLatin1String("__next__")] << "}," << endl; + s << INDENT << "{Py_tp_methods, (void *)" << className << "_methods}," << endl; + s << INDENT << "{Py_tp_getset, (void *)" << tp_getset << "}," << endl; + s << INDENT << "{Py_tp_init, (void *)" << tp_init << "}," << endl; + s << INDENT << "{Py_tp_new, (void *)" << tp_new << "}," << endl; + if (supportsSequenceProtocol(metaClass)) { + s << INDENT << "// type supports sequence protocol" << endl; + writeTypeAsSequenceDefinition(s, metaClass); + } + if (supportsMappingProtocol(metaClass)) { + s << INDENT << "// type supports mapping protocol" << endl; + writeTypeAsMappingDefinition(s, metaClass); + } + if (supportsNumberProtocol(metaClass)) { + // This one must come last. See the function itself. + s << INDENT << "// type supports number protocol" << endl; + writeTypeAsNumberDefinition(s, metaClass); + } + s << INDENT << "{0, 0}" << endl; + s << "};" << endl; + s << "static PyType_Spec " << className << "_spec = {" << endl; + s << INDENT << "\"" << computedClassTargetFullName << "\"," << endl; + s << INDENT << "sizeof(SbkObject)," << endl; + s << INDENT << "0," << endl; + s << INDENT << tp_flags << "," << endl; + s << INDENT << className << "_slots" << endl; + s << "};" << endl; + s << endl; + s << "} //extern \"C\"" << endl; } void CppGenerator::writeMappingMethods(QTextStream &s, @@ -3943,14 +3940,13 @@ void CppGenerator::writeTypeAsSequenceDefinition(QTextStream& s, const AbstractM funcs[QLatin1String("__setitem__")] = baseName + QLatin1String("__setitem__"); } - s << INDENT << "memset(&" << baseName << "_TypeAsSequence, 0, sizeof(PySequenceMethods));" << endl; for (QHash<QString, QString>::const_iterator it = m_sqFuncs.cbegin(), end = m_sqFuncs.cend(); it != end; ++it) { const QString& sqName = it.key(); if (funcs[sqName].isEmpty()) continue; if (it.value() == QLatin1String("sq_slice")) s << "#ifndef IS_PY3K" << endl; - s << INDENT << baseName << "_TypeAsSequence." << it.value() << " = " << funcs[sqName] << ';' << endl; + s << INDENT << "{Py_" << it.value() << ", (void *)" << funcs[sqName] << "}," << endl; if (it.value() == QLatin1String("sq_slice")) s << "#endif" << endl; } @@ -3976,12 +3972,11 @@ void CppGenerator::writeTypeAsMappingDefinition(QTextStream& s, const AbstractMe } QString baseName = cpythonBaseName(metaClass); - s << INDENT << "memset(&" << baseName << "_TypeAsMapping, 0, sizeof(PyMappingMethods));" << endl; for (auto it = m_mpFuncs.cbegin(), end = m_mpFuncs.cend(); it != end; ++it) { const QString &mpName = it.key(); if (funcs[mpName].isEmpty()) continue; - s << INDENT << baseName << "_TypeAsMapping." << it.value() << " = " << funcs[mpName] << ';' << endl; + s << INDENT << "{Py_" << it.value() << ", (void *)" << funcs[mpName] << "}," << endl; } } @@ -4029,7 +4024,6 @@ void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMet nb[QLatin1String("bool")] = hasBoolCast(metaClass) ? baseName + QLatin1String("___nb_bool") : QString(); - s << INDENT << "memset(&" << baseName << "_TypeAsNumber, 0, sizeof(PyNumberMethods));" << endl; for (QHash<QString, QString>::const_iterator it = m_nbFuncs.cbegin(), end = m_nbFuncs.cend(); it != end; ++it) { const QString &nbName = it.key(); if (nb[nbName].isEmpty()) @@ -4038,21 +4032,29 @@ void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMet // bool is special because the field name differs on Python 2 and 3 (nb_nonzero vs nb_bool) // so a shiboken macro is used. if (nbName == QLatin1String("bool")) { - s << INDENT << "SBK_NB_BOOL(" << baseName << "_TypeAsNumber) = " << nb[nbName] << ';' << endl; + s << "#ifdef IS_PY3K" << endl; + s << INDENT << "{Py_nb_bool, (void *)" << nb[nbName] << "}," << endl; + s << "#else" << endl; + s << INDENT << "{Py_nb_nonzero, (void *)" << nb[nbName] << "}," << endl; + s << "#endif" << endl; } else { bool excludeFromPy3K = nbName == QLatin1String("__div__") || nbName == QLatin1String("__idiv__"); - if (excludeFromPy3K) { - s << "#ifdef IS_PY3K" << endl; - s << INDENT << "SBK_UNUSED(&" << nb[nbName] << ");" << endl; - s << "#else" << endl; - } - s << INDENT << baseName << "_TypeAsNumber." << it.value() << " = " << nb[nbName] << ';' << endl; - if (excludeFromPy3K) - s << "#endif" << endl; + if (!excludeFromPy3K) + s << INDENT << "{Py_" << it.value() << ", (void *)" << nb[nbName] << "}," << endl; } } - if (!nb[QLatin1String("__div__")].isEmpty()) - s << INDENT << baseName << "_TypeAsNumber.nb_true_divide = " << nb[QLatin1String("__div__")] << ';' << endl; + if (!nb[QLatin1String("__div__")].isEmpty()) { + s << INDENT << "{Py_nb_true_divide, (void *)" << nb[QLatin1String("__div__")] << "}," << endl; + s << "#ifndef IS_PY3K" << endl; + s << INDENT << "{Py_nb_divide, (void *)" << nb[QLatin1String("__div__")] << "}," << endl; + s << "#endif" << endl; + } + if (!nb[QLatin1String("__idiv__")].isEmpty()) { + s << INDENT << "// This function is unused in Python 3. We reference it here." << endl; + s << INDENT << "{0, (void *)" << nb[QLatin1String("__idiv__")] << "}," << endl; + s << INDENT << "// This list is ending at the first 0 entry." << endl; + s << INDENT << "// Therefore, we need to put the unused functions at the very end." << endl; + } } void CppGenerator::writeTpTraverseFunction(QTextStream& s, const AbstractMetaClass* metaClass) @@ -4061,7 +4063,7 @@ void CppGenerator::writeTpTraverseFunction(QTextStream& s, const AbstractMetaCla s << "static int "; s << baseName << "_traverse(PyObject* " PYTHON_SELF_VAR ", visitproc visit, void* arg)" << endl; s << '{' << endl; - s << INDENT << "return reinterpret_cast<PyTypeObject*>(&SbkObject_Type)->tp_traverse(" PYTHON_SELF_VAR ", visit, arg);" << endl; + s << INDENT << "return PepType(reinterpret_cast<PyTypeObject*>(SbkObject_TypeF()))->tp_traverse(" PYTHON_SELF_VAR ", visit, arg);" << endl; s << '}' << endl; } @@ -4071,7 +4073,7 @@ void CppGenerator::writeTpClearFunction(QTextStream& s, const AbstractMetaClass* s << "static int "; s << baseName << "_clear(PyObject* " PYTHON_SELF_VAR ")" << endl; s << '{' << endl; - s << INDENT << "return reinterpret_cast<PyTypeObject*>(&SbkObject_Type)->tp_clear(" PYTHON_SELF_VAR ");" << endl; + s << INDENT << "return PepType(reinterpret_cast<PyTypeObject*>(SbkObject_TypeF()))->tp_clear(" PYTHON_SELF_VAR ");" << endl; s << '}' << endl; } @@ -4147,7 +4149,7 @@ void CppGenerator::writeGetterFunction(QTextStream &s, { Indentation indent(INDENT); s << INDENT << "pyOut = reinterpret_cast<PyObject *>(Shiboken::Object::findColocatedChild(" - << "reinterpret_cast<SbkObject *>(self), reinterpret_cast<const SbkObjectType *>(" + << "reinterpret_cast<SbkObject *>(self), reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(fieldType) << ")));\n"; s << INDENT << "if (pyOut) {Py_IncRef(pyOut); return pyOut;}\n"; @@ -4474,7 +4476,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu const EnumTypeEntry *enumTypeEntry = cppEnum->typeEntry(); QString enclosingObjectVariable; if (enclosingClass) - enclosingObjectVariable = QLatin1Char('&') + cpythonTypeName(enclosingClass); + enclosingObjectVariable = cpythonTypeName(enclosingClass); else if (hasUpperEnclosingClass) enclosingObjectVariable = QLatin1String("enclosingClass"); else @@ -4488,8 +4490,8 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu if (!cppEnum->isAnonymous()) { FlagsTypeEntry* flags = enumTypeEntry->flags(); if (flags) { - s << INDENT << cpythonTypeNameExt(flags) << " = PySide::QFlags::create(\"" << flags->flagsName() << "\", &" - << cpythonEnumName(cppEnum) << "_as_number);" << endl; + s << INDENT << cpythonTypeNameExt(flags) << " = PySide::QFlags::create(\"" << flags->flagsName() << "\", " + << cpythonEnumName(cppEnum) << "_number_slots);" << endl; } enumVarTypeObj = cpythonTypeNameExt(enumTypeEntry); @@ -4539,8 +4541,8 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu { Indentation indent(INDENT); s << INDENT << "PyObject* anonEnumItem = PyInt_FromLong(" << enumValueText << ");" << endl; - s << INDENT << "if (PyDict_SetItemString(reinterpret_cast<SbkObjectType *>(" << enclosingObjectVariable - << ")->super.ht_type.tp_dict, \"" << enumValue->name() << "\", anonEnumItem) < 0)" << endl; + s << INDENT << "if (PyDict_SetItemString(PepType(reinterpret_cast<SbkObjectType *>(" << enclosingObjectVariable + << "))->tp_dict, \"" << enumValue->name() << "\", anonEnumItem) < 0)" << endl; { Indentation indent(INDENT); s << INDENT << "return " << m_currentErrorCode << ';' << endl; @@ -4609,7 +4611,7 @@ void CppGenerator::writeSignalInitialization(QTextStream& s, const AbstractMetaC } } - s << INDENT << "PySide::Signal::registerSignals(&" << cpythonTypeName(metaClass) << ", &::" + s << INDENT << "PySide::Signal::registerSignals(" << cpythonTypeName(metaClass) << ", &::" << metaClass->qualifiedCppName() << "::staticMetaObject);" << endl; } @@ -4659,57 +4661,22 @@ void CppGenerator::writeFlagsNumberMethodsDefinition(QTextStream& s, const Abstr { QString cpythonName = cpythonEnumName(cppEnum); - s << "static PyNumberMethods " << cpythonName << "_as_number = {" << endl; - s << INDENT << "/*nb_add*/ 0," << endl; - s << INDENT << "/*nb_subtract*/ 0," << endl; - s << INDENT << "/*nb_multiply*/ 0," << endl; - s << INDENT << "#ifndef IS_PY3K" << endl; - s << INDENT << "/* nb_divide */ 0," << endl; - s << INDENT << "#endif" << endl; - s << INDENT << "/*nb_remainder*/ 0," << endl; - s << INDENT << "/*nb_divmod*/ 0," << endl; - s << INDENT << "/*nb_power*/ 0," << endl; - s << INDENT << "/*nb_negative*/ 0," << endl; - s << INDENT << "/*nb_positive*/ 0," << endl; - s << INDENT << "/*nb_absolute*/ 0," << endl; - s << INDENT << "/*nb_nonzero*/ " << cpythonName << "__nonzero," << endl; - s << INDENT << "/*nb_invert*/ (unaryfunc)" << cpythonName << "___invert__," << endl; - s << INDENT << "/*nb_lshift*/ 0," << endl; - s << INDENT << "/*nb_rshift*/ 0," << endl; - s << INDENT << "/*nb_and*/ (binaryfunc)" << cpythonName << "___and__," << endl; - s << INDENT << "/*nb_xor*/ (binaryfunc)" << cpythonName << "___xor__," << endl; - s << INDENT << "/*nb_or*/ (binaryfunc)" << cpythonName << "___or__," << endl; - s << INDENT << "#ifndef IS_PY3K" << endl; - s << INDENT << "/* nb_coerce */ 0," << endl; - s << INDENT << "#endif" << endl; - s << INDENT << "/*nb_int*/ " << cpythonName << "_long," << endl; - s << INDENT << "#ifdef IS_PY3K" << endl; - s << INDENT << "/*nb_reserved*/ 0," << endl; - s << INDENT << "/*nb_float*/ 0," << endl; - s << INDENT << "#else" << endl; - s << INDENT << "/*nb_long*/ " << cpythonName << "_long," << endl; - s << INDENT << "/*nb_float*/ 0," << endl; - s << INDENT << "/*nb_oct*/ 0," << endl; - s << INDENT << "/*nb_hex*/ 0," << endl; - s << INDENT << "#endif" << endl; - s << INDENT << "/*nb_inplace_add*/ 0," << endl; - s << INDENT << "/*nb_inplace_subtract*/ 0," << endl; - s << INDENT << "/*nb_inplace_multiply*/ 0," << endl; - s << INDENT << "#ifndef IS_PY3K" << endl; - s << INDENT << "/*nb_inplace_divide*/ 0," << endl; - s << INDENT << "#endif" << endl; - s << INDENT << "/*nb_inplace_remainder*/ 0," << endl; - s << INDENT << "/*nb_inplace_power*/ 0," << endl; - s << INDENT << "/*nb_inplace_lshift*/ 0," << endl; - s << INDENT << "/*nb_inplace_rshift*/ 0," << endl; - s << INDENT << "/*nb_inplace_and*/ 0," << endl; - s << INDENT << "/*nb_inplace_xor*/ 0," << endl; - s << INDENT << "/*nb_inplace_or*/ 0," << endl; - s << INDENT << "/*nb_floor_divide*/ 0," << endl; - s << INDENT << "/*nb_true_divide*/ 0," << endl; - s << INDENT << "/*nb_inplace_floor_divide*/ 0," << endl; - s << INDENT << "/*nb_inplace_true_divide*/ 0," << endl; - s << INDENT << "/*nb_index*/ 0" << endl; + s << "static PyType_Slot " << cpythonName << "_number_slots[] = {" << endl; + s << "#ifdef IS_PY3K" << endl; + s << INDENT << "{Py_nb_bool, (void *)" << cpythonName << "__nonzero}," << endl; + s << "#else" << endl; + s << INDENT << "{Py_nb_nonzero, (void *)" << cpythonName << "__nonzero}," << endl; + s << INDENT << "{Py_nb_long, (void *)" << cpythonName << "_long}," << endl; + s << "#endif" << endl; + s << INDENT << "{Py_nb_invert, (void *)" << cpythonName << "___invert__}," << endl; + s << INDENT << "{Py_nb_and, (void *)" << cpythonName << "___and__}," << endl; + s << INDENT << "{Py_nb_xor, (void *)" << cpythonName << "___xor__}," << endl; + s << INDENT << "{Py_nb_or, (void *)" << cpythonName << "___or__}," << endl; + s << INDENT << "{Py_nb_int, (void *)" << cpythonName << "_long}," << endl; + s << "#ifndef IS_PY3K" << endl; + s << INDENT << "{Py_nb_long, (void *)" << cpythonName << "_long}," << endl; + s << "#endif" << endl; + s << INDENT << "{0, 0} // sentinel" << endl; s << "};" << endl << endl; } @@ -4803,37 +4770,8 @@ void CppGenerator::writeClassRegister(QTextStream &s, s << "(PyObject* " << enclosingObjectVariable << ")" << endl; s << '{' << endl; - if (supportsNumberProtocol(metaClass)) { - s << INDENT << "// type has number operators" << endl; - writeTypeAsNumberDefinition(s, metaClass); - s << INDENT << pyTypeName << ".super.ht_type.tp_as_number = &" << pyTypeName << "AsNumber;" << endl; - s << endl; - } - - if (supportsSequenceProtocol(metaClass)) { - s << INDENT << "// type supports sequence protocol" << endl; - writeTypeAsSequenceDefinition(s, metaClass); - s << INDENT << pyTypeName << ".super.ht_type.tp_as_sequence = &" << pyTypeName << "AsSequence;" << endl; - s << endl; - } - - if (supportsMappingProtocol(metaClass)) { - s << INDENT << "// type supports mapping protocol" << endl; - writeTypeAsMappingDefinition(s, metaClass); - s << INDENT << pyTypeName << ".super.ht_type.tp_as_mapping = &" << pyTypeName << "AsMapping;" << endl; - s << endl; - } - - if (!classContext.forSmartPointer()) - s << INDENT << cpythonTypeNameExt(classTypeEntry) << endl; - else - s << INDENT << cpythonTypeNameExt(classContext.preciseType()) << endl; - - s << INDENT << " = reinterpret_cast<PyTypeObject*>(&" << pyTypeName << ");" << endl; - s << endl; - // Multiple inheritance - QString pyTypeBasesVariable = pyTypeName + QLatin1String("_bases"); + QString pyTypeBasesVariable = chopType(pyTypeName) + QLatin1String("_Type_bases"); const AbstractMetaClassList baseClasses = getBaseClasses(metaClass); if (metaClass->baseClassNames().size() > 1) { s << INDENT << "PyObject* " << pyTypeBasesVariable << " = PyTuple_Pack(" << baseClasses.size() << ',' << endl; @@ -4848,28 +4786,42 @@ void CppGenerator::writeClassRegister(QTextStream &s, } // Create type and insert it in the module or enclosing class. - s << INDENT << "if (!Shiboken::ObjectType::introduceWrapperType(" << enclosingObjectVariable; - QString typeName; - if (!classContext.forSmartPointer()) - typeName = metaClass->name(); - else - typeName = classContext.preciseType()->cppSignature(); - - s << ", \"" << typeName << "\", \""; + const QString typePtr = QLatin1String("_") + chopType(pyTypeName) + + QLatin1String("_Type"); - // Original name - if (!classContext.forSmartPointer()) - s << metaClass->qualifiedCppName() << (isObjectType(classTypeEntry) ? "*" : ""); - else - s << classContext.preciseType()->cppSignature(); - - s << "\"," << endl; + s << INDENT << typePtr << " = Shiboken::ObjectType::introduceWrapperType(" << endl; { Indentation indent(INDENT); - s << INDENT << "&" << pyTypeName << "," << endl; - s << INDENT << initFunctionName << "_SignaturesString"; + // 1:enclosingObject + s << INDENT << enclosingObjectVariable << "," << endl; + QString typeName; + if (!classContext.forSmartPointer()) + typeName = metaClass->name(); + else + typeName = classContext.preciseType()->cppSignature(); + + // 2:typeName + s << INDENT << "\"" << typeName << "\"," << endl; + + // 3:originalName + s << INDENT << "\""; + if (!classContext.forSmartPointer()) { + s << metaClass->qualifiedCppName(); + if (isObjectType(classTypeEntry)) + s << '*'; + } else { + s << classContext.preciseType()->cppSignature(); + } + + s << "\"," << endl; + // 4:typeSpec + s << INDENT << '&' << chopType(pyTypeName) << "_spec," << endl; - // Set destructor function + // 5:signaturesString + s << INDENT << initFunctionName << "_SignaturesString," << endl; + + // 6:cppObjDtor + s << INDENT; if (!metaClass->isNamespace() && !metaClass->hasPrivateDestructor()) { QString dtorClassName = metaClass->qualifiedCppName(); if ((avoidProtectedHack() && metaClass->hasProtectedDestructor()) || classTypeEntry->isValue()) @@ -4877,28 +4829,37 @@ void CppGenerator::writeClassRegister(QTextStream &s, if (classContext.forSmartPointer()) dtorClassName = wrapperName(classContext.preciseType()); - s << ", &Shiboken::callCppDestructor< ::" << dtorClassName << " >"; - } else if (metaClass->baseClass() || hasEnclosingClass) { - s << ", 0"; + s << "&Shiboken::callCppDestructor< ::" << dtorClassName << " >," << endl; + } else { + s << "0," << endl; } - // Base type + // 7:baseType if (metaClass->baseClass()) { - s << ", reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(metaClass->baseClass()->typeEntry()) << ')'; - // The other base types - if (metaClass->baseClassNames().size() > 1) - s << ", " << pyTypeBasesVariable; - else if (hasEnclosingClass) - s << ", 0"; - } else if (hasEnclosingClass) { - s << ", 0, 0"; - } - if (hasEnclosingClass) - s << ", true"; - s << ")) {" << endl; - s << INDENT << "return;" << endl; + s << INDENT << "reinterpret_cast<SbkObjectType *>(" + << cpythonTypeNameExt(metaClass->baseClass()->typeEntry()) << ")," << endl; + } else { + s << INDENT << "0," << endl; + } + + // 8:baseTypes + if (metaClass->baseClassNames().size() > 1) + s << INDENT << pyTypeBasesVariable << ',' << endl; + else + s << INDENT << "0," << endl; + + // 9:isInnerClass + s << INDENT << (hasEnclosingClass ? "true" : "false") << endl; } - s << INDENT << '}' << endl << endl; + s << INDENT << ");" << endl; + s << INDENT << endl; + + if (!classContext.forSmartPointer()) + s << INDENT << cpythonTypeNameExt(classTypeEntry) << endl; + else + s << INDENT << cpythonTypeNameExt(classContext.preciseType()) << endl; + s << INDENT << " = reinterpret_cast<PyTypeObject*>(" << pyTypeName << ");" << endl; + s << endl; // Register conversions for the type. writeConverterRegister(s, metaClass, classContext); @@ -4920,15 +4881,15 @@ void CppGenerator::writeClassRegister(QTextStream &s, s << "Shiboken::ObjectType::getMultipleIheritanceFunction(reinterpret_cast<SbkObjectType*>("; s << cpythonTypeNameExt(miClass->typeEntry()) << "));" << endl; } - s << INDENT << "Shiboken::ObjectType::setMultipleIheritanceFunction(&"; + s << INDENT << "Shiboken::ObjectType::setMultipleInheritanceFunction("; s << cpythonTypeName(metaClass) << ", func);" << endl; - s << INDENT << "Shiboken::ObjectType::setCastFunction(&" << cpythonTypeName(metaClass); + s << INDENT << "Shiboken::ObjectType::setCastFunction(" << cpythonTypeName(metaClass); s << ", &" << cpythonSpecialCastFunctionName(metaClass) << ");" << endl; } // Set typediscovery struct or fill the struct of another one if (metaClass->isPolymorphic() && metaClass->baseClass()) { - s << INDENT << "Shiboken::ObjectType::setTypeDiscoveryFunctionV2(&" << cpythonTypeName(metaClass); + s << INDENT << "Shiboken::ObjectType::setTypeDiscoveryFunctionV2(" << cpythonTypeName(metaClass); s << ", &" << cpythonBaseName(metaClass) << "_typeDiscovery);" << endl << endl; } @@ -4948,7 +4909,7 @@ void CppGenerator::writeClassRegister(QTextStream &s, for (const AbstractMetaField *field : fields) { if (!field->isStatic()) continue; - s << INDENT << QLatin1String("PyDict_SetItemString(") + cpythonTypeName(metaClass) + QLatin1String(".super.ht_type.tp_dict, \""); + s << INDENT << QLatin1String("PyDict_SetItemString(PepType(") + cpythonTypeName(metaClass) + QLatin1String(")->tp_dict, \""); s << field->name() << "\", "; writeToPythonConversion(s, field->type(), metaClass, metaClass->qualifiedCppName() + QLatin1String("::") + field->name()); s << ");" << endl; @@ -4969,8 +4930,8 @@ void CppGenerator::writeClassRegister(QTextStream &s, } if (usePySideExtensions() && metaClass->isQObject()) { - s << INDENT << "Shiboken::ObjectType::setSubTypeInitHook(&" << pyTypeName << ", &PySide::initQObjectSubType);" << endl; - s << INDENT << "PySide::initDynamicMetaObject(&" << pyTypeName << ", &::" << metaClass->qualifiedCppName() + s << INDENT << "Shiboken::ObjectType::setSubTypeInitHook(" << pyTypeName << ", &PySide::initQObjectSubType);" << endl; + s << INDENT << "PySide::initDynamicMetaObject(" << pyTypeName << ", &::" << metaClass->qualifiedCppName() << "::staticMetaObject, sizeof(::" << metaClass->qualifiedCppName() << "));" << endl; } @@ -5163,7 +5124,7 @@ void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &conte s << INDENT << "if (Shiboken::Object::isUserType(" PYTHON_SELF_VAR ")) {" << endl; { Indentation indent(INDENT); - s << INDENT << "PyObject* meth = PyDict_GetItem(" PYTHON_SELF_VAR "->ob_type->tp_dict, name);" << endl; + s << INDENT << "PyObject* meth = PyDict_GetItem(PepType(Py_TYPE(" PYTHON_SELF_VAR "))->tp_dict, name);" << endl; s << INDENT << "if (meth)" << endl; { Indentation indent(INDENT); @@ -5228,7 +5189,7 @@ void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &conte s << INDENT << "PyTypeObject *tp = Py_TYPE(self);" << endl; s << INDENT << "PyErr_Format(PyExc_AttributeError," << endl; s << INDENT << " \"'%.50s' object has no attribute '%.400s'\"," << endl; - s << INDENT << " tp->tp_name, PyBytes_AS_STRING(name));" << endl; + s << INDENT << " PepType(tp)->tp_name, PyBytes_AS_STRING(name));" << endl; s << INDENT << "return NULL;" << endl; } s << INDENT << "} else {" << endl; @@ -5308,7 +5269,7 @@ bool CppGenerator::finishGeneration() QString defineStr = QLatin1String("init_") + cls->qualifiedCppName().replace(QLatin1String("::"), QLatin1String("_")); if (cls->enclosingClass() && (cls->enclosingClass()->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass)) - defineStr += QLatin1Char('(') + cpythonTypeNameExt(cls->enclosingClass()->typeEntry()) + QLatin1String("->tp_dict);"); + defineStr += QLatin1String("(PepType(") + cpythonTypeNameExt(cls->enclosingClass()->typeEntry()) + QLatin1String(")->tp_dict);"); else defineStr += QLatin1String("(module);"); s_classPythonDefines << INDENT << defineStr << endl; @@ -5854,10 +5815,12 @@ QString CppGenerator::writeReprFunction(QTextStream &s, GeneratorContext &contex s << INDENT << "if (idx >= 0)" << endl; { Indentation indent(INDENT); - s << INDENT << "str.replace(0, idx, Py_TYPE(self)->tp_name);" << endl; + s << INDENT << "str.replace(0, idx, PepType((Py_TYPE(self)))->tp_name);" << endl; } - s << INDENT << "PyObject* mod = PyDict_GetItemString(Py_TYPE(self)->tp_dict, \"__module__\");" << endl; - s << INDENT << "if (mod)" << endl; + s << INDENT << "PyObject* mod = PyDict_GetItemString(PepType(Py_TYPE(self))->tp_dict, \"__module__\");" << endl; + // PYSIDE-595: The introduction of heap types has the side effect that the module name + // is always prepended to the type name. Therefore the strchr check: + s << INDENT << "if (mod && !strchr(str, '.'))" << endl; { Indentation indent(INDENT); s << INDENT << "return Shiboken::String::fromFormat(\"<%s.%s at %p>\", Shiboken::String::toCString(mod), str.constData(), self);" << endl; diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp index 6165ef009..976b34141 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp @@ -804,7 +804,7 @@ QString ShibokenGenerator::cpythonTypeName(const AbstractMetaClass* metaClass) QString ShibokenGenerator::cpythonTypeName(const TypeEntry* type) { - return cpythonBaseName(type) + QLatin1String("_Type"); + return cpythonBaseName(type) + QLatin1String("_TypeF()"); } QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntry* type) @@ -838,7 +838,7 @@ QString ShibokenGenerator::converterObject(const TypeEntry* type) if (isCppPrimitive(type)) return QString::fromLatin1("Shiboken::Conversions::PrimitiveTypeConverter<%1>()").arg(type->qualifiedCppName()); if (isWrapperType(type) || type->isEnum() || type->isFlags()) - return QString::fromLatin1("SBK_CONVERTER(%1)").arg(cpythonTypeNameExt(type)); + return QString::fromLatin1("*PepType_SGTP(%1)->converter").arg(cpythonTypeNameExt(type)); if (type->isArray()) { qDebug() << "Warning: no idea how to handle the Qt5 type " << type->qualifiedCppName(); @@ -1164,7 +1164,7 @@ QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType* metaType if (isPointerToWrapperType(type)) { typeCheck += QString::fromLatin1("checkSequenceTypes(%1, ").arg(cpythonTypeNameExt(type)); } else if (isWrapperType(type)) { - typeCheck += QLatin1String("convertibleSequenceTypes(reinterpret_cast<const SbkObjectType *>("); + typeCheck += QLatin1String("convertibleSequenceTypes(reinterpret_cast<SbkObjectType *>("); typeCheck += cpythonTypeNameExt(type); typeCheck += QLatin1String("), "); } else { @@ -1287,7 +1287,7 @@ QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaType* result += QLatin1String("isPythonToCppReferenceConvertible"); else result += QLatin1String("isPythonToCppValueConvertible"); - result += QLatin1String("(reinterpret_cast<const SbkObjectType *>(") + result += QLatin1String("(reinterpret_cast<SbkObjectType *>(") + cpythonTypeNameExt(metaType) + QLatin1String("), "); return result; } @@ -1341,7 +1341,7 @@ QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaT else conversion = QLatin1String("pointer"); QString result = QLatin1String("Shiboken::Conversions::") + conversion - + QLatin1String("ToPython(reinterpret_cast<const SbkObjectType *>(") + + QLatin1String("ToPython(reinterpret_cast<SbkObjectType *>(") + cpythonTypeNameExt(type) + QLatin1String("), "); if (conversion != QLatin1String("pointer")) result += QLatin1Char('&'); @@ -1362,7 +1362,7 @@ QString ShibokenGenerator::cpythonToPythonConversionFunction(const TypeEntry* ty if (isWrapperType(type)) { const QString conversion = type->isValue() ? QLatin1String("copy") : QLatin1String("pointer"); QString result = QLatin1String("Shiboken::Conversions::") + conversion - + QLatin1String("ToPython(reinterpret_cast<const SbkObjectType *>(") + cpythonTypeNameExt(type) + + QLatin1String("ToPython(reinterpret_cast<SbkObjectType *>(") + cpythonTypeNameExt(type) + QLatin1String("), "); if (conversion != QLatin1String("pointer")) result += QLatin1Char('&'); @@ -1625,7 +1625,7 @@ void ShibokenGenerator::processCodeSnip(QString& code, const AbstractMetaClass* // Replace template variable by the Python Type object // for the class context in which the variable is used. code.replace(QLatin1String("%PYTHONTYPEOBJECT"), - cpythonTypeName(context) + QLatin1String(".super.ht_type")); + cpythonTypeName(context) + QLatin1String("->type")); code.replace(QLatin1String("%TYPE"), wrapperName(context)); code.replace(QLatin1String("%CPPTYPE"), context->name()); } @@ -1856,7 +1856,7 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s, // class implementing the method in which the code snip is written if (func->isStatic()) { code.replace(QLatin1String("%PYTHONTYPEOBJECT"), - cpythonTypeName(func->implementingClass()) + QLatin1String(".super.ht_type")); + cpythonTypeName(func->implementingClass()) + QLatin1String("->type")); } else { code.replace(QLatin1String("%PYTHONTYPEOBJECT."), pySelf + QLatin1String("->ob_type->")); code.replace(QLatin1String("%PYTHONTYPEOBJECT"), pySelf + QLatin1String("->ob_type")); diff --git a/sources/shiboken2/libshiboken/CMakeLists.txt b/sources/shiboken2/libshiboken/CMakeLists.txt index e87cf07fd..b5ba78e15 100644 --- a/sources/shiboken2/libshiboken/CMakeLists.txt +++ b/sources/shiboken2/libshiboken/CMakeLists.txt @@ -48,7 +48,10 @@ threadstatesaver.cpp shibokenbuffer.cpp signature.cpp qapp_macro.cpp +pep384impl.cpp voidptr.cpp +typespec.cpp +bufferprocs27.cpp ) get_numpy_location() @@ -89,9 +92,12 @@ install(FILES threadstatesaver.h shibokenbuffer.h sbkpython.h + pep384impl.h signature.h qapp_macro.h voidptr.h + typespec.h + bufferprocs27.h "${CMAKE_CURRENT_BINARY_DIR}/sbkversion.h" DESTINATION include/shiboken2${shiboken2_SUFFIX}) install(TARGETS libshiboken EXPORT shiboken2 diff --git a/sources/shiboken2/libshiboken/autodecref.h b/sources/shiboken2/libshiboken/autodecref.h index 1f3f41eab..7b6aa47da 100644 --- a/sources/shiboken2/libshiboken/autodecref.h +++ b/sources/shiboken2/libshiboken/autodecref.h @@ -79,7 +79,9 @@ public: /// Returns the pointer of the Python object being held. inline PyObject* object() { return m_pyObj; } inline operator PyObject*() { return m_pyObj; } +#ifndef Py_LIMITED_API inline operator PyTupleObject*() { return reinterpret_cast<PyTupleObject*>(m_pyObj); } +#endif inline operator bool() const { return m_pyObj != 0; } inline PyObject* operator->() { return m_pyObj; } diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp index 21f6933d2..0e2712ec8 100644 --- a/sources/shiboken2/libshiboken/basewrapper.cpp +++ b/sources/shiboken2/libshiboken/basewrapper.cpp @@ -66,55 +66,34 @@ extern "C" static void SbkObjectTypeDealloc(PyObject* pyObj); static PyObject* SbkObjectTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds); -PyTypeObject SbkObjectType_Type = { - PyVarObject_HEAD_INIT(0, 0) - /*tp_name*/ "Shiboken.ObjectType", - /*tp_basicsize*/ sizeof(SbkObjectType), - /*tp_itemsize*/ 0, - /*tp_dealloc*/ SbkObjectTypeDealloc, - /*tp_print*/ 0, - /*tp_getattr*/ 0, - /*tp_setattr*/ 0, - /*tp_compare*/ 0, - /*tp_repr*/ 0, - /*tp_as_number*/ 0, - /*tp_as_sequence*/ 0, - /*tp_as_mapping*/ 0, - /*tp_hash*/ 0, - /*tp_call*/ 0, - /*tp_str*/ 0, - /*tp_getattro*/ 0, - /*tp_setattro*/ PyObject_GenericSetAttr, - /*tp_as_buffer*/ 0, - /*tp_flags*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, - /*tp_doc*/ 0, - /*tp_traverse*/ 0, - /*tp_clear*/ 0, - /*tp_richcompare*/ 0, - /*tp_weaklistoffset*/ 0, - /*tp_iter*/ 0, - /*tp_iternext*/ 0, - /*tp_methods*/ 0, - /*tp_members*/ 0, - /*tp_getset*/ 0, - /*tp_base*/ &PyType_Type, - /*tp_dict*/ 0, - /*tp_descr_get*/ 0, - /*tp_descr_set*/ 0, - /*tp_dictoffset*/ 0, - /*tp_init*/ 0, - /*tp_alloc*/ PyType_GenericAlloc, - /*tp_new*/ SbkObjectTypeTpNew, - /*tp_free*/ PyObject_GC_Del, - /*tp_is_gc*/ 0, - /*tp_bases*/ 0, - /*tp_mro*/ 0, - /*tp_cache*/ 0, - /*tp_subclasses*/ 0, - /*tp_weaklist*/ 0, - /*tp_del*/ 0, - /*tp_version_tag*/ 0 +static PyType_Slot SbkObjectType_Type_slots[] = { + {Py_tp_dealloc, (void *)SbkObjectTypeDealloc}, + {Py_tp_setattro, (void *)PyObject_GenericSetAttr}, + {Py_tp_base, (void *)&PyType_Type}, + {Py_tp_alloc, (void *)PyType_GenericAlloc}, + {Py_tp_new, (void *)SbkObjectTypeTpNew}, + {Py_tp_free, (void *)PyObject_GC_Del}, + {0, 0} }; +static PyType_Spec SbkObjectType_Type_spec = { + "Shiboken.ObjectType", + 0, // basicsize (inserted later) + sizeof(PyMemberDef), + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + SbkObjectType_Type_slots, +}; + + +PyTypeObject *SbkObjectType_TypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) { + SbkObjectType_Type_spec.basicsize = + PepHeapType_SIZE + sizeof(SbkObjectTypePrivate); + type = reinterpret_cast<PyTypeObject *>(PyType_FromSpec(&SbkObjectType_Type_spec)); + } + return type; +} static PyObject *SbkObjectGetDict(PyObject* pObj, void *) { @@ -176,57 +155,36 @@ static int SbkObject_clear(PyObject* self) return 0; } -SbkObjectType SbkObject_Type = { { { - PyVarObject_HEAD_INIT(&SbkObjectType_Type, 0) - /*tp_name*/ "Shiboken.Object", - /*tp_basicsize*/ sizeof(SbkObject), - /*tp_itemsize*/ 0, - /*tp_dealloc*/ SbkDeallocWrapperWithPrivateDtor, - /*tp_print*/ 0, - /*tp_getattr*/ 0, - /*tp_setattr*/ 0, - /*tp_compare*/ 0, - /*tp_repr*/ 0, - /*tp_as_number*/ 0, - /*tp_as_sequence*/ 0, - /*tp_as_mapping*/ 0, - /*tp_hash*/ 0, - /*tp_call*/ 0, - /*tp_str*/ 0, - /*tp_getattro*/ 0, - /*tp_setattro*/ 0, - /*tp_as_buffer*/ 0, - /*tp_flags*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, - /*tp_doc*/ 0, - /*tp_traverse*/ SbkObject_traverse, - /*tp_clear*/ SbkObject_clear, - /*tp_richcompare*/ 0, - /*tp_weaklistoffset*/ offsetof(SbkObject, weakreflist), - /*tp_iter*/ 0, - /*tp_iternext*/ 0, - /*tp_methods*/ 0, - /*tp_members*/ 0, - /*tp_getset*/ SbkObjectGetSetList, - /*tp_base*/ 0, - /*tp_dict*/ 0, - /*tp_descr_get*/ 0, - /*tp_descr_set*/ 0, - /*tp_dictoffset*/ offsetof(SbkObject, ob_dict), - /*tp_init*/ 0, - /*tp_alloc*/ 0, - /*tp_new*/ 0, - /*tp_free*/ 0, - /*tp_is_gc*/ 0, - /*tp_bases*/ 0, - /*tp_mro*/ 0, - /*tp_cache*/ 0, - /*tp_subclasses*/ 0, - /*tp_weaklist*/ 0, - /*tp_del*/ 0, - /*tp_version_tag*/ 0 -}, }, - /*priv_data*/ 0 +static PyType_Slot SbkObject_Type_slots[] = { + {Py_tp_dealloc, (void *)SbkDeallocWrapperWithPrivateDtor}, + {Py_tp_traverse, (void *)SbkObject_traverse}, + {Py_tp_clear, (void *)SbkObject_clear}, + // unsupported: {Py_tp_weaklistoffset, (void *)offsetof(SbkObject, weakreflist)}, + {Py_tp_getset, (void *)SbkObjectGetSetList}, + // unsupported: {Py_tp_dictoffset, (void *)offsetof(SbkObject, ob_dict)}, + {0, 0} }; +static PyType_Spec SbkObject_Type_spec = { + "Shiboken.Object", + sizeof(SbkObject), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, + SbkObject_Type_slots, +}; + + +SbkObjectType *SbkObject_TypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) { + type = reinterpret_cast<PyTypeObject *>(PyType_FromSpec(&SbkObject_Type_spec)); + Py_TYPE(type) = SbkObjectType_TypeF(); + Py_INCREF(Py_TYPE(type)); + PepType(type)->tp_weaklistoffset = offsetof(SbkObject, weakreflist); + PepType(type)->tp_dictoffset = offsetof(SbkObject, ob_dict); + } + return reinterpret_cast<SbkObjectType *>(type); +} static void SbkDeallocWrapperCommon(PyObject* pyObj, bool canDelete) @@ -237,8 +195,8 @@ static void SbkDeallocWrapperCommon(PyObject* pyObj, bool canDelete) // Need to decref the type if this is the dealloc func; if type // is subclassed, that dealloc func will decref (see subtype_dealloc // in typeobject.c in the python sources) - bool needTypeDecref = (pyType->tp_dealloc == SbkDeallocWrapper - || pyType->tp_dealloc == SbkDeallocWrapperWithPrivateDtor); + bool needTypeDecref = (PyType_GetSlot(pyType, Py_tp_dealloc) == SbkDeallocWrapper + || PyType_GetSlot(pyType, Py_tp_dealloc) == SbkDeallocWrapperWithPrivateDtor); // Ensure that the GC is no longer tracking this object to avoid a // possible reentrancy problem. Since there are multiple steps involved @@ -257,10 +215,10 @@ static void SbkDeallocWrapperCommon(PyObject* pyObj, bool canDelete) // If I have ownership and is valid delete C++ pointer if (canDelete && sbkObj->d->hasOwnership && sbkObj->d->validCppObject) { - SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(pyType); - if (sbkType->d->is_multicpp) { + SbkObjectTypePrivate *sotp = PepType_SOTP(pyType); + if (sotp->is_multicpp) { Shiboken::DeallocVisitor visitor(sbkObj); - Shiboken::walkThroughClassHierarchy(pyObj->ob_type, &visitor); + Shiboken::walkThroughClassHierarchy(Py_TYPE(pyObj), &visitor); } else { void* cptr = sbkObj->d->cptr[0]; Shiboken::Object::deallocData(sbkObj, true); @@ -268,7 +226,7 @@ static void SbkDeallocWrapperCommon(PyObject* pyObj, bool canDelete) Shiboken::ThreadStateSaver threadSaver; if (Py_IsInitialized()) threadSaver.save(); - sbkType->d->cpp_dtor(cptr); + sotp->cpp_dtor(cptr); } } else { Shiboken::Object::deallocData(sbkObj, true); @@ -297,91 +255,103 @@ void SbkDeallocWrapperWithPrivateDtor(PyObject* self) void SbkObjectTypeDealloc(PyObject* pyObj) { - SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(pyObj); + SbkObjectTypePrivate *sotp = PepType_SOTP(pyObj); + PyTypeObject *type = reinterpret_cast<PyTypeObject*>(pyObj); PyObject_GC_UnTrack(pyObj); Py_TRASHCAN_SAFE_BEGIN(pyObj); - if (sbkType->d) { - if(sbkType->d->user_data && sbkType->d->d_func) { - sbkType->d->d_func(sbkType->d->user_data); - sbkType->d->user_data = 0; + if (sotp) { + if (sotp->user_data && sotp->d_func) { + sotp->d_func(sotp->user_data); + sotp->user_data = nullptr; } - free(sbkType->d->original_name); - sbkType->d->original_name = 0; - if (!Shiboken::ObjectType::isUserType(reinterpret_cast<PyTypeObject*>(sbkType))) - Shiboken::Conversions::deleteConverter(sbkType->d->converter); - delete sbkType->d; - sbkType->d = 0; + free(sotp->original_name); + sotp->original_name = nullptr; + if (!Shiboken::ObjectType::isUserType(type)) + Shiboken::Conversions::deleteConverter(sotp->converter); + delete sotp; + sotp = nullptr; } Py_TRASHCAN_SAFE_END(pyObj); } PyObject* SbkObjectTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds) { -#ifndef IS_PY3K // Check if all bases are new style before calling type.tp_new // Was causing gc assert errors in test_bug704.py when // this check happened after creating the type object. // Argument parsing take from type.tp_new code. + + // PYSIDE-595: Also check if all bases allow inheritance. + // Before we changed to heap types, it was sufficient to remove the + // Py_TPFLAGS_BASETYPE flag. That does not work, because PySide does + // not respect this flag itself! PyObject* name; PyObject* pyBases; PyObject* dict; static const char* kwlist[] = { "name", "bases", "dict", 0}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "SO!O!:sbktype", (char**)kwlist, + if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO!O!:sbktype", (char**)kwlist, &name, &PyTuple_Type, &pyBases, &PyDict_Type, &dict)) return NULL; - for(int i=0, i_max=PyTuple_GET_SIZE(pyBases); i < i_max; i++) { + for (int i=0, i_max=PyTuple_GET_SIZE(pyBases); i < i_max; i++) { PyObject* baseType = PyTuple_GET_ITEM(pyBases, i); +#ifndef IS_PY3K if (PyClass_Check(baseType)) { - PyErr_Format(PyExc_TypeError, "Invalid base class used in type %s. PySide only support multiple inheritance from python new style class.", metatype->tp_name); + PyErr_Format(PyExc_TypeError, "Invalid base class used in type %s. " + "PySide only support multiple inheritance from python new style class.", PepType(metatype)->tp_name); return 0; } - } #endif + if (PepType(reinterpret_cast<PyTypeObject*>(baseType))->tp_new == SbkDummyNew) { + // PYSIDE-595: A base class does not allow inheritance. + return SbkDummyNew(metatype, args, kwds); + } + } // The meta type creates a new type when the Python programmer extends a wrapped C++ class. - SbkObjectType* newType = reinterpret_cast<SbkObjectType*>(PyType_Type.tp_new(metatype, args, kwds)); + newfunc type_new = reinterpret_cast<newfunc>(PepType(&PyType_Type)->tp_new); + SbkObjectType *newType = reinterpret_cast<SbkObjectType*>(type_new(metatype, args, kwds)); if (!newType) return 0; Shiboken::ObjectType::initPrivateData(newType); - SbkObjectTypePrivate* d = newType->d; + SbkObjectTypePrivate *sotp = PepType_SOTP(newType); std::list<SbkObjectType*> bases = Shiboken::getCppBaseClasses(reinterpret_cast<PyTypeObject*>(newType)); if (bases.size() == 1) { - SbkObjectTypePrivate* parentType = bases.front()->d; - d->mi_offsets = parentType->mi_offsets; - d->mi_init = parentType->mi_init; - d->mi_specialcast = parentType->mi_specialcast; - d->type_discovery = parentType->type_discovery; - d->cpp_dtor = parentType->cpp_dtor; - d->is_multicpp = 0; - d->converter = parentType->converter; + SbkObjectTypePrivate *parentType = PepType_SOTP(bases.front()); + sotp->mi_offsets = parentType->mi_offsets; + sotp->mi_init = parentType->mi_init; + sotp->mi_specialcast = parentType->mi_specialcast; + sotp->type_discovery = parentType->type_discovery; + sotp->cpp_dtor = parentType->cpp_dtor; + sotp->is_multicpp = 0; + sotp->converter = parentType->converter; } else { - d->mi_offsets = 0; - d->mi_init = 0; - d->mi_specialcast = 0; - d->type_discovery = 0; - d->cpp_dtor = 0; - d->is_multicpp = 1; - d->converter = 0; + sotp->mi_offsets = nullptr; + sotp->mi_init = nullptr; + sotp->mi_specialcast = nullptr; + sotp->type_discovery = nullptr; + sotp->cpp_dtor = nullptr; + sotp->is_multicpp = 1; + sotp->converter = nullptr; } if (bases.size() == 1) - d->original_name = strdup(bases.front()->d->original_name); + sotp->original_name = strdup(PepType_SOTP(bases.front())->original_name); else - d->original_name = strdup("object"); - d->user_data = 0; - d->d_func = 0; - d->is_user_type = 1; + sotp->original_name = strdup("object"); + sotp->user_data = nullptr; + sotp->d_func = nullptr; + sotp->is_user_type = 1; std::list<SbkObjectType*>::const_iterator it = bases.begin(); for (; it != bases.end(); ++it) { - if ((*it)->d->subtype_init) - (*it)->d->subtype_init(newType, args, kwds); + if (PepType_SOTP(*it)->subtype_init) + PepType_SOTP(*it)->subtype_init(newType, args, kwds); } return reinterpret_cast<PyObject*>(newType); @@ -392,18 +362,19 @@ static PyObject *_setupNew(SbkObject *self, PyTypeObject *subtype) Py_INCREF(reinterpret_cast<PyObject*>(subtype)); SbkObjectPrivate* d = new SbkObjectPrivate; - SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(subtype); - int numBases = ((sbkType->d && sbkType->d->is_multicpp) ? Shiboken::getNumberOfCppBaseClasses(subtype) : 1); + SbkObjectTypePrivate * sotp = PepType_SOTP(subtype); + int numBases = ((sotp && sotp->is_multicpp) ? + Shiboken::getNumberOfCppBaseClasses(subtype) : 1); d->cptr = new void*[numBases]; - std::memset(d->cptr, 0, sizeof(void*)*numBases); + std::memset(d->cptr, 0, sizeof(void*) * size_t(numBases)); d->hasOwnership = 1; d->containsCppWrapper = 0; d->validCppObject = 0; - d->parentInfo = 0; - d->referredObjects = 0; + d->parentInfo = nullptr; + d->referredObjects = nullptr; d->cppObjectCreated = 0; - self->ob_dict = 0; - self->weakreflist = 0; + self->ob_dict = nullptr; + self->weakreflist = nullptr; self->d = d; return reinterpret_cast<PyObject*>(self); } @@ -422,18 +393,37 @@ PyObject* SbkQAppTpNew(PyTypeObject* subtype, PyObject *, PyObject *) // For qApp, we need to create a singleton Python object. // We cannot track this with the GC, because it is a static variable! - // Python2 has a weird handling of flags in derived classes that Python3 + // Python 2 has a weird handling of flags in derived classes that Python 3 // does not have. Observed with bug_307.py. // But it could theoretically also happen with Python3. // Therefore we enforce that there is no GC flag, ever! + + // PYSIDE-560: + // We avoid to use this in Python 3, because we have a hard time to get + // write access to these flags +#ifndef IS_PY3K if (PyType_HasFeature(subtype, Py_TPFLAGS_HAVE_GC)) { subtype->tp_flags &= ~Py_TPFLAGS_HAVE_GC; subtype->tp_free = PyObject_Del; } +#endif SbkObject* self = reinterpret_cast<SbkObject*>(MakeSingletonQAppWrapper(subtype)); return self == 0 ? 0 : _setupNew(self, subtype); } +void +SbkDummyDealloc(PyObject *) +{} + +PyObject * +SbkDummyNew(PyTypeObject *type, PyObject*, PyObject*) +{ + // PYSIDE-595: Give the same error as type_call does when tp_new is NULL. + PyErr_Format(PyExc_TypeError, + "cannot create '%.100s' instances ¯\\_(ツ)_/¯", + PepType(type)->tp_name); + return nullptr; +} } //extern "C" @@ -464,16 +454,16 @@ static void decRefPyObjectList(const std::list<PyObject*> &pyObj, PyObject* skip static void _walkThroughClassHierarchy(PyTypeObject* currentType, HierarchyVisitor* visitor) { - PyObject* bases = currentType->tp_bases; + PyObject* bases = PepType(currentType)->tp_bases; Py_ssize_t numBases = PyTuple_GET_SIZE(bases); for (int i = 0; i < numBases; ++i) { PyTypeObject* type = reinterpret_cast<PyTypeObject*>(PyTuple_GET_ITEM(bases, i)); - if (!PyType_IsSubtype(type, reinterpret_cast<PyTypeObject*>(&SbkObject_Type))) { + if (!PyType_IsSubtype(type, reinterpret_cast<PyTypeObject*>(SbkObject_TypeF()))) { continue; } else { SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(type); - if (sbkType->d->is_user_type) + if (PepType_SOTP(sbkType)->is_user_type) _walkThroughClassHierarchy(type, visitor); else visitor->visit(sbkType); @@ -532,7 +522,7 @@ void DtorCallerVisitor::done() for (; it != m_ptrs.end(); ++it) { Shiboken::ThreadStateSaver threadSaver; threadSaver.save(); - it->second->d->cpp_dtor(it->first); + PepType_SOTP(it->second)->cpp_dtor(it->first); } } @@ -555,15 +545,17 @@ void init() PyEval_InitThreads(); //Init private data - Shiboken::ObjectType::initPrivateData(&SbkObject_Type); + Pep_Init(); + + Shiboken::ObjectType::initPrivateData(SbkObject_TypeF()); - if (PyType_Ready(&SbkEnumType_Type) < 0) + if (PyType_Ready(SbkEnumType_TypeF()) < 0) Py_FatalError("[libshiboken] Failed to initialise Shiboken.SbkEnumType metatype."); - if (PyType_Ready(&SbkObjectType_Type) < 0) + if (PyType_Ready(SbkObjectType_TypeF()) < 0) Py_FatalError("[libshiboken] Failed to initialise Shiboken.BaseWrapperType metatype."); - if (PyType_Ready(reinterpret_cast<PyTypeObject *>(&SbkObject_Type)) < 0) + if (PyType_Ready(reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())) < 0) Py_FatalError("[libshiboken] Failed to initialise Shiboken.BaseWrapper type."); VoidPtr::init(); @@ -581,10 +573,10 @@ void setErrorAboutWrongArguments(PyObject* args, const char* funcName, const cha if (i) params += ", "; PyObject* arg = PyTuple_GET_ITEM(args, i); - params += arg->ob_type->tp_name; + params += PepType((Py_TYPE(arg)))->tp_name; } } else { - params = args->ob_type->tp_name; + params = PepType((Py_TYPE(args)))->tp_name; } } @@ -660,12 +652,12 @@ namespace ObjectType bool checkType(PyTypeObject* type) { - return PyType_IsSubtype(type, reinterpret_cast<PyTypeObject*>(&SbkObject_Type)) != 0; + return PyType_IsSubtype(type, reinterpret_cast<PyTypeObject*>(SbkObject_TypeF())) != 0; } bool isUserType(PyTypeObject* type) { - return checkType(type) && reinterpret_cast<SbkObjectType*>(type)->d->is_user_type; + return checkType(type) && PepType_SOTP(type)->is_user_type; } bool canCallConstructor(PyTypeObject* myType, PyTypeObject* ctorType) @@ -673,7 +665,7 @@ bool canCallConstructor(PyTypeObject* myType, PyTypeObject* ctorType) FindBaseTypeVisitor visitor(ctorType); walkThroughClassHierarchy(myType, &visitor); if (!visitor.found()) { - PyErr_Format(PyExc_TypeError, "%s isn't a direct base class of %s", ctorType->tp_name, myType->tp_name); + PyErr_Format(PyExc_TypeError, "%s isn't a direct base class of %s", PepType(ctorType)->tp_name, PepType(myType)->tp_name); return false; } return true; @@ -681,114 +673,133 @@ bool canCallConstructor(PyTypeObject* myType, PyTypeObject* ctorType) bool hasCast(SbkObjectType* type) { - return type->d->mi_specialcast != 0; + return PepType_SOTP(type)->mi_specialcast != 0; } void* cast(SbkObjectType* sourceType, SbkObject* obj, PyTypeObject* targetType) { - return sourceType->d->mi_specialcast(Object::cppPointer(obj, targetType), reinterpret_cast<SbkObjectType*>(targetType)); + return PepType_SOTP(sourceType)->mi_specialcast(Object::cppPointer(obj, targetType), + reinterpret_cast<SbkObjectType*>(targetType)); } void setCastFunction(SbkObjectType* type, SpecialCastFunction func) { - type->d->mi_specialcast = func; + PepType_SOTP(type)->mi_specialcast = func; } -void setOriginalName(SbkObjectType* self, const char* name) +void setOriginalName(SbkObjectType* type, const char* name) { - if (self->d->original_name) - free(self->d->original_name); - self->d->original_name = strdup(name); + SbkObjectTypePrivate *sotp = PepType_SOTP(type); + if (sotp->original_name) + free(sotp->original_name); + sotp->original_name = strdup(name); } -const char* getOriginalName(SbkObjectType* self) +const char* getOriginalName(SbkObjectType* type) { - return self->d->original_name; + return PepType_SOTP(type)->original_name; } -void setTypeDiscoveryFunctionV2(SbkObjectType* self, TypeDiscoveryFuncV2 func) +void setTypeDiscoveryFunctionV2(SbkObjectType* type, TypeDiscoveryFuncV2 func) { - self->d->type_discovery = func; + PepType_SOTP(type)->type_discovery = func; } -void copyMultimpleheritance(SbkObjectType* self, SbkObjectType* other) +void copyMultimpleheritance(SbkObjectType* type, SbkObjectType* other) { - self->d->mi_init = other->d->mi_init; - self->d->mi_offsets = other->d->mi_offsets; - self->d->mi_specialcast = other->d->mi_specialcast; + PepType_SOTP(type)->mi_init = PepType_SOTP(other)->mi_init; + PepType_SOTP(type)->mi_offsets = PepType_SOTP(other)->mi_offsets; + PepType_SOTP(type)->mi_specialcast = PepType_SOTP(other)->mi_specialcast; } -void setMultipleIheritanceFunction(SbkObjectType* self, MultipleInheritanceInitFunction function) +void setMultipleInheritanceFunction(SbkObjectType* type, MultipleInheritanceInitFunction function) { - self->d->mi_init = function; + PepType_SOTP(type)->mi_init = function; } -MultipleInheritanceInitFunction getMultipleIheritanceFunction(SbkObjectType* self) +MultipleInheritanceInitFunction getMultipleIheritanceFunction(SbkObjectType* type) { - return self->d->mi_init; + return PepType_SOTP(type)->mi_init; } -void setDestructorFunction(SbkObjectType* self, ObjectDestructor func) +void setDestructorFunction(SbkObjectType* type, ObjectDestructor func) { - self->d->cpp_dtor = func; + PepType_SOTP(type)->cpp_dtor = func; } -void initPrivateData(SbkObjectType* self) +void initPrivateData(SbkObjectType* type) { - self->d = new SbkObjectTypePrivate; - memset(self->d, 0, sizeof(SbkObjectTypePrivate)); + PepType_SOTP(type) = new SbkObjectTypePrivate; + memset(PepType_SOTP(type), 0, sizeof(SbkObjectTypePrivate)); } -bool introduceWrapperType(PyObject *enclosingObject, - const char *typeName, const char *originalName, - SbkObjectType *type, - const char *signaturesString, - ObjectDestructor cppObjDtor, - SbkObjectType *baseType, PyObject *baseTypes, - bool isInnerClass) +SbkObjectType * +introduceWrapperType(PyObject *enclosingObject, + const char *typeName, + const char *originalName, + PyType_Spec *typeSpec, + const char *signaturesString, + ObjectDestructor cppObjDtor, + SbkObjectType *baseType, + PyObject *baseTypes, + bool isInnerClass) { - initPrivateData(type); - setOriginalName(type, originalName); - setDestructorFunction(type, cppObjDtor); - if (baseType) { - type->super.ht_type.tp_base = reinterpret_cast<PyTypeObject *>(baseType); + typeSpec->slots[0].pfunc = reinterpret_cast<void *>(baseType); + } + else { + typeSpec->slots[0].pfunc = reinterpret_cast<void *>(SbkObject_TypeF()); + } + PyObject *heaptype = PyType_FromSpecWithBases(typeSpec, baseTypes); + Py_TYPE(heaptype) = SbkObjectType_TypeF(); + Py_INCREF(Py_TYPE(heaptype)); + SbkObjectType *type = reinterpret_cast<SbkObjectType *>(heaptype); + if (baseType) { if (baseTypes) { for (int i = 0; i < PySequence_Fast_GET_SIZE(baseTypes); ++i) BindingManager::instance().addClassInheritance(reinterpret_cast<SbkObjectType *>(PySequence_Fast_GET_ITEM(baseTypes, i)), type); - type->super.ht_type.tp_bases = baseTypes; } else { BindingManager::instance().addClassInheritance(baseType, type); } } - - // PySide-510 - // here is the single change to support signatures. + // PYSIDE-510: Here is the single change to support signatures. if (SbkSpecial_Type_Ready(enclosingObject, reinterpret_cast<PyTypeObject *>(type), signaturesString) < 0) - return false; + return nullptr; - if (isInnerClass) - return PyDict_SetItemString(enclosingObject, typeName, reinterpret_cast<PyObject *>(type)) == 0; + initPrivateData(type); + setOriginalName(type, originalName); + setDestructorFunction(type, cppObjDtor); + + if (isInnerClass) { + if (PyDict_SetItemString(enclosingObject, typeName, reinterpret_cast<PyObject *>(type)) == 0) + return type; + else + return nullptr; + } //PyModule_AddObject steals type's reference. Py_INCREF(reinterpret_cast<PyObject *>(type)); - return PyModule_AddObject(enclosingObject, typeName, reinterpret_cast<PyObject *>(type)) == 0; + if (PyModule_AddObject(enclosingObject, typeName, reinterpret_cast<PyObject *>(type)) == 0) { + return type; + } + return nullptr; } -void setSubTypeInitHook(SbkObjectType* self, SubTypeInitHook func) +void setSubTypeInitHook(SbkObjectType* type, SubTypeInitHook func) { - self->d->subtype_init = func; + PepType_SOTP(type)->subtype_init = func; } -void* getTypeUserData(SbkObjectType* self) +void* getTypeUserData(SbkObjectType* type) { - return self->d->user_data; + return PepType_SOTP(type)->user_data; } -void setTypeUserData(SbkObjectType* self, void* userData, DeleteUserDataFunc d_func) +void setTypeUserData(SbkObjectType* type, void* userData, DeleteUserDataFunc d_func) { - self->d->user_data = userData; - self->d->d_func = d_func; + SbkObjectTypePrivate *sotp = PepType_SOTP(type); + sotp->user_data = userData; + sotp->d_func = d_func; } } // namespace ObjectType @@ -801,12 +812,12 @@ static void recursive_invalidate(SbkObject* self, std::set<SbkObject*>& seen); bool checkType(PyObject* pyObj) { - return ObjectType::checkType(pyObj->ob_type); + return ObjectType::checkType(Py_TYPE(pyObj)); } bool isUserType(PyObject* pyObj) { - return ObjectType::isUserType(pyObj->ob_type); + return ObjectType::isUserType(Py_TYPE(pyObj)); } Py_hash_t hash(PyObject* pyObj) @@ -858,14 +869,15 @@ bool wasCreatedByPython(SbkObject* pyObj) void callCppDestructors(SbkObject* pyObj) { - SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(Py_TYPE(pyObj)); - if (sbkType->d->is_multicpp) { + PyTypeObject *type = Py_TYPE(pyObj); + SbkObjectTypePrivate * sotp = PepType_SOTP(type); + if (sotp->is_multicpp) { Shiboken::DtorCallerVisitor visitor(pyObj); - Shiboken::walkThroughClassHierarchy(Py_TYPE(pyObj), &visitor); + Shiboken::walkThroughClassHierarchy(type, &visitor); } else { Shiboken::ThreadStateSaver threadSaver; threadSaver.save(); - sbkType->d->cpp_dtor(pyObj->d->cptr[0]); + sotp->cpp_dtor(pyObj->d->cptr[0]); } /* invalidate needs to be called before deleting pointer array because @@ -916,7 +928,7 @@ void releaseOwnership(SbkObject* self) { // skip if the ownership have already moved to c++ SbkObjectType* selfType = reinterpret_cast<SbkObjectType*>(Py_TYPE(self)); - if (!self->d->hasOwnership || Shiboken::Conversions::pythonTypeIsValueType(selfType->d->converter)) + if (!self->d->hasOwnership || Shiboken::Conversions::pythonTypeIsValueType(PepType_SOTP(selfType)->converter)) return; // remove object ownership @@ -1037,7 +1049,7 @@ void* cppPointer(SbkObject* pyObj, PyTypeObject* desiredType) { PyTypeObject* type = Py_TYPE(pyObj); int idx = 0; - if (reinterpret_cast<SbkObjectType*>(type)->d->is_multicpp) + if (PepType_SOTP(reinterpret_cast<SbkObjectType*>(type))->is_multicpp) idx = getTypeIndexOnHierarchy(type, desiredType); if (pyObj->d->cptr) return pyObj->d->cptr[idx]; @@ -1057,8 +1069,9 @@ std::vector<void*> cppPointers(SbkObject* pyObj) bool setCppPointer(SbkObject* sbkObj, PyTypeObject* desiredType, void* cptr) { int idx = 0; - if (reinterpret_cast<SbkObjectType*>(Py_TYPE(sbkObj))->d->is_multicpp) - idx = getTypeIndexOnHierarchy(Py_TYPE(sbkObj), desiredType); + PyTypeObject *type = Py_TYPE(sbkObj); + if (PepType_SOTP(type)->is_multicpp) + idx = getTypeIndexOnHierarchy(type, desiredType); const bool alreadyInitialized = sbkObj->d->cptr[idx] != 0; if (alreadyInitialized) @@ -1073,19 +1086,21 @@ bool setCppPointer(SbkObject* sbkObj, PyTypeObject* desiredType, void* cptr) bool isValid(PyObject* pyObj) { if (!pyObj || pyObj == Py_None - || Py_TYPE(pyObj->ob_type) != &SbkObjectType_Type) { + || Py_TYPE(Py_TYPE(pyObj)) != SbkObjectType_TypeF()) { return true; } SbkObjectPrivate* priv = reinterpret_cast<SbkObject*>(pyObj)->d; if (!priv->cppObjectCreated && isUserType(pyObj)) { - PyErr_Format(PyExc_RuntimeError, "'__init__' method of object's base class (%s) not called.", pyObj->ob_type->tp_name); + PyErr_Format(PyExc_RuntimeError, "'__init__' method of object's base class (%s) not called.", + PepType((Py_TYPE(pyObj)))->tp_name); return false; } if (!priv->validCppObject) { - PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.", pyObj->ob_type->tp_name); + PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.", + PepType((Py_TYPE(pyObj)))->tp_name); return false; } @@ -1100,13 +1115,15 @@ bool isValid(SbkObject* pyObj, bool throwPyError) SbkObjectPrivate* priv = pyObj->d; if (!priv->cppObjectCreated && isUserType(reinterpret_cast<PyObject*>(pyObj))) { if (throwPyError) - PyErr_Format(PyExc_RuntimeError, "Base constructor of the object (%s) not called.", Py_TYPE(pyObj)->tp_name); + PyErr_Format(PyExc_RuntimeError, "Base constructor of the object (%s) not called.", + PepType((Py_TYPE(pyObj)))->tp_name); return false; } if (!priv->validCppObject) { if (throwPyError) - PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.", Py_TYPE(pyObj)->tp_name); + PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.", + PepType((Py_TYPE(pyObj)))->tp_name); return false; } @@ -1116,7 +1133,7 @@ bool isValid(SbkObject* pyObj, bool throwPyError) bool isValid(PyObject* pyObj, bool throwPyError) { if (!pyObj || pyObj == Py_None || - !PyType_IsSubtype(pyObj->ob_type, reinterpret_cast<PyTypeObject*>(&SbkObject_Type))) { + !PyType_IsSubtype(Py_TYPE(pyObj), reinterpret_cast<PyTypeObject*>(SbkObject_TypeF()))) { return true; } return isValid(reinterpret_cast<SbkObject*>(pyObj), throwPyError); @@ -1384,24 +1401,25 @@ void deallocData(SbkObject* self, bool cleanup) } delete self->d; // PYSIDE-205: always delete d. Py_XDECREF(self->ob_dict); + // PYSIDE-571: qApp is no longer allocated. - if (PyObject_IS_GC((PyObject*)self)) - Py_TYPE(self)->tp_free(self); + if (PyObject_IS_GC(reinterpret_cast<PyObject*>(self))) + PepType(Py_TYPE(self))->tp_free(self); } void setTypeUserData(SbkObject* wrapper, void* userData, DeleteUserDataFunc d_func) { - SbkObjectType* ob_type = reinterpret_cast<SbkObjectType*>(Py_TYPE(wrapper)); - if (ob_type->d->user_data) - ob_type->d->d_func(ob_type->d->user_data); + SbkObjectTypePrivate *sotp = PepType_SOTP(Py_TYPE(wrapper)); + if (sotp->user_data) + sotp->d_func(sotp->user_data); - ob_type->d->d_func = d_func; - ob_type->d->user_data = userData; + sotp->d_func = d_func; + sotp->user_data = userData; } void* getTypeUserData(SbkObject* wrapper) { - return reinterpret_cast<SbkObjectType*>(Py_TYPE(wrapper))->d->user_data; + return PepType_SOTP(Py_TYPE(wrapper))->user_data; } void keepReference(SbkObject* self, const char* key, PyObject* referredObject, bool append) @@ -1483,7 +1501,7 @@ std::string info(SbkObject* self) s << "C++ address....... "; std::list<SbkObjectType*>::const_iterator it = bases.begin(); for (int i = 0; it != bases.end(); ++it, ++i) - s << reinterpret_cast<PyTypeObject *>(*it)->tp_name << '/' << self->d->cptr[i] << ' '; + s << PepType((reinterpret_cast<PyTypeObject*>(*it)))->tp_name << '/' << self->d->cptr[i] << ' '; s << "\n"; } else { diff --git a/sources/shiboken2/libshiboken/basewrapper.h b/sources/shiboken2/libshiboken/basewrapper.h index fc553cf8c..755058e8b 100644 --- a/sources/shiboken2/libshiboken/basewrapper.h +++ b/sources/shiboken2/libshiboken/basewrapper.h @@ -93,22 +93,34 @@ typedef void (*ObjectDestructor)(void*); typedef void (*SubTypeInitHook)(SbkObjectType*, PyObject*, PyObject*); -extern LIBSHIBOKEN_API PyTypeObject SbkObjectType_Type; -extern LIBSHIBOKEN_API SbkObjectType SbkObject_Type; +extern LIBSHIBOKEN_API PyTypeObject *SbkObjectType_TypeF(void); +extern LIBSHIBOKEN_API SbkObjectType *SbkObject_TypeF(void); struct SbkObjectTypePrivate; /// PyTypeObject extended with C++ multiple inheritance information. struct LIBSHIBOKEN_API SbkObjectType { - PyHeapTypeObject super; - SbkObjectTypePrivate* d; + PepTypeObject type; }; LIBSHIBOKEN_API PyObject* SbkObjectTpNew(PyTypeObject* subtype, PyObject*, PyObject*); // the special case of a switchable singleton LIBSHIBOKEN_API PyObject* SbkQAppTpNew(PyTypeObject *subtype, PyObject *args, PyObject *kwds); +/** + * PYSIDE-595: Use a null deallocator instead of nullptr. + * + * When moving to heaptypes, we were struck by a special default behavior of + * PyType_FromSpecWithBases that inserts subtype_dealloc when tp_dealloc is + * nullptr. To prevent inserting this, we use a null deallocator that is there + * as a placeholder. + * + * The same holds for a null tp_new. We use one that raises the right error. + */ +LIBSHIBOKEN_API void SbkDummyDealloc(PyObject*); +LIBSHIBOKEN_API PyObject *SbkDummyNew(PyTypeObject *type, PyObject*, PyObject*); + } // extern "C" namespace Shiboken @@ -173,7 +185,7 @@ LIBSHIBOKEN_API const char* getOriginalName(SbkObjectType* self); LIBSHIBOKEN_API void setTypeDiscoveryFunctionV2(SbkObjectType* self, TypeDiscoveryFuncV2 func); LIBSHIBOKEN_API void copyMultimpleheritance(SbkObjectType* self, SbkObjectType* other); -LIBSHIBOKEN_API void setMultipleIheritanceFunction(SbkObjectType* self, MultipleInheritanceInitFunction func); +LIBSHIBOKEN_API void setMultipleInheritanceFunction(SbkObjectType* self, MultipleInheritanceInitFunction func); LIBSHIBOKEN_API MultipleInheritanceInitFunction getMultipleIheritanceFunction(SbkObjectType* self); LIBSHIBOKEN_API void setDestructorFunction(SbkObjectType* self, ObjectDestructor func); @@ -197,13 +209,15 @@ LIBSHIBOKEN_API void initPrivateData(SbkObjectType* self); * wrapper type. * \returns true if the initialization went fine, false otherwise. */ -LIBSHIBOKEN_API bool introduceWrapperType(PyObject* enclosingObject, - const char* typeName, const char* originalName, - SbkObjectType* type, - const char* signaturesString, - ObjectDestructor cppObjDtor = 0, - SbkObjectType* baseType = 0, PyObject* baseTypes = 0, - bool isInnerClass = false); +LIBSHIBOKEN_API SbkObjectType *introduceWrapperType(PyObject *enclosingObject, + const char *typeName, + const char *originalName, + PyType_Spec *typeSpec, + const char *signaturesString, + ObjectDestructor cppObjDtor, + SbkObjectType *baseType, + PyObject *baseTypes, + bool isInnerClass); /** * Set the subtype init hook for a type. diff --git a/sources/shiboken2/libshiboken/bindingmanager.cpp b/sources/shiboken2/libshiboken/bindingmanager.cpp index de3458ab5..5a3283ab5 100644 --- a/sources/shiboken2/libshiboken/bindingmanager.cpp +++ b/sources/shiboken2/libshiboken/bindingmanager.cpp @@ -83,8 +83,10 @@ public: SbkObjectType* node1 = i->first; const NodeList& nodeList = i->second; NodeList::const_iterator j = nodeList.begin(); - for (; j != nodeList.end(); ++j) - file << '"' << (*j)->super.ht_type.tp_name << "\" -> \"" << node1->super.ht_type.tp_name << "\"\n"; + for (; j != nodeList.end(); ++j) { + file << '"' << PepType(*j)->tp_name << "\" -> \"" + << PepType(node1)->tp_name << "\"\n"; + } } file << "}\n"; } @@ -102,7 +104,10 @@ public: return newType; } } - void* typeFound = ((type->d && type->d->type_discovery) ? type->d->type_discovery(*cptr, baseType) : 0); + void *typeFound = nullptr; + if (PepType_SOTP(type) && PepType_SOTP(type)->type_discovery) { + typeFound = PepType_SOTP(type)->type_discovery(*cptr, baseType); + } if (typeFound) { // This "typeFound != type" is needed for backwards compatibility with old modules using a newer version of // libshiboken because old versions of type_discovery function used to return a SbkObjectType* instead of @@ -111,7 +116,7 @@ public: *cptr = typeFound; return type; } else { - return 0; + return nullptr; } } }; @@ -128,7 +133,7 @@ static void showWrapperMap(const WrapperMap& wrapperMap) const SbkObject *sbkObj = iter->second; fprintf(stderr, "key: %p, value: %p (%s, refcnt: %d)\n", iter->first, static_cast<const void *>(sbkObj), - Py_TYPE(sbkObj)->tp_name, + PepType((Py_TYPE(sbkObj)))->tp_name, int(reinterpret_cast<const PyObject *>(sbkObj)->ob_refcnt)); } fprintf(stderr, "-------------------------------\n"); @@ -210,7 +215,7 @@ bool BindingManager::hasWrapper(const void* cptr) void BindingManager::registerWrapper(SbkObject* pyObj, void* cptr) { SbkObjectType* instanceType = reinterpret_cast<SbkObjectType*>(Py_TYPE(pyObj)); - SbkObjectTypePrivate* d = instanceType->d; + SbkObjectTypePrivate* d = PepType_SOTP(instanceType); if (!d) return; @@ -231,7 +236,7 @@ void BindingManager::registerWrapper(SbkObject* pyObj, void* cptr) void BindingManager::releaseWrapper(SbkObject* sbkObj) { SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(Py_TYPE(sbkObj)); - SbkObjectTypePrivate* d = sbkType->d; + SbkObjectTypePrivate* d = PepType_SOTP(sbkType); int numBases = ((d && d->is_multicpp) ? getNumberOfCppBaseClasses(Py_TYPE(sbkObj)) : 1); void** cptrs = reinterpret_cast<SbkObject*>(sbkObj)->d->cptr; @@ -278,17 +283,17 @@ PyObject* BindingManager::getOverride(const void* cptr, const char* methodName) PyObject *method = PyObject_GetAttr(reinterpret_cast<PyObject *>(wrapper), pyMethodName); if (method && PyMethod_Check(method) - && reinterpret_cast<PyMethodObject*>(method)->im_self == reinterpret_cast<PyObject*>(wrapper)) { + && PyMethod_GET_SELF(method) == reinterpret_cast<PyObject*>(wrapper)) { PyObject* defaultMethod; - PyObject* mro = Py_TYPE(wrapper)->tp_mro; + PyObject* mro = PepType(Py_TYPE(wrapper))->tp_mro; // The first class in the mro (index 0) is the class being checked and it should not be tested. // The last class in the mro (size - 1) is the base Python object class which should not be tested also. for (int i = 1; i < PyTuple_GET_SIZE(mro) - 1; i++) { PyTypeObject* parent = reinterpret_cast<PyTypeObject*>(PyTuple_GET_ITEM(mro, i)); - if (parent->tp_dict) { - defaultMethod = PyDict_GetItem(parent->tp_dict, pyMethodName); - if (defaultMethod && reinterpret_cast<PyMethodObject*>(method)->im_func != defaultMethod) { + if (PepType(parent)->tp_dict) { + defaultMethod = PyDict_GetItem(PepType(parent)->tp_dict, pyMethodName); + if (defaultMethod && PyMethod_GET_FUNCTION(method) != defaultMethod) { Py_DECREF(pyMethodName); return method; } diff --git a/sources/shiboken2/libshiboken/bufferprocs27.cpp b/sources/shiboken2/libshiboken/bufferprocs27.cpp new file mode 100644 index 000000000..168a28a96 --- /dev/null +++ b/sources/shiboken2/libshiboken/bufferprocs27.cpp @@ -0,0 +1,397 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/***************************************************************************** + * + * Copied from abstract.c + * + * Py_buffer has been replaced by Pep_buffer + * + */ + +#ifdef Py_LIMITED_API + +#include "pep384impl.h" +/* Buffer C-API for Python 3.0 */ + +int +PyObject_GetBuffer(PyObject *obj, Pep_buffer *view, int flags) +{ + PyBufferProcs *pb = PepType_AS_BUFFER(Py_TYPE(obj)); + + if (pb == NULL || pb->bf_getbuffer == NULL) { + PyErr_Format(PyExc_TypeError, + "a bytes-like object is required, not '%.100s'", + PepType((Py_TYPE(obj)))->tp_name); + return -1; + } + return (*pb->bf_getbuffer)(obj, view, flags); +} + +static int +_IsFortranContiguous(const Pep_buffer *view) +{ + Py_ssize_t sd, dim; + int i; + + /* 1) len = product(shape) * itemsize + 2) itemsize > 0 + 3) len = 0 <==> exists i: shape[i] = 0 */ + if (view->len == 0) return 1; + if (view->strides == NULL) { /* C-contiguous by definition */ + /* Trivially F-contiguous */ + if (view->ndim <= 1) return 1; + + /* ndim > 1 implies shape != NULL */ + assert(view->shape != NULL); + + /* Effectively 1-d */ + sd = 0; + for (i=0; i<view->ndim; i++) { + if (view->shape[i] > 1) sd += 1; + } + return sd <= 1; + } + + /* strides != NULL implies both of these */ + assert(view->ndim > 0); + assert(view->shape != NULL); + + sd = view->itemsize; + for (i=0; i<view->ndim; i++) { + dim = view->shape[i]; + if (dim > 1 && view->strides[i] != sd) { + return 0; + } + sd *= dim; + } + return 1; +} + +static int +_IsCContiguous(const Pep_buffer *view) +{ + Py_ssize_t sd, dim; + int i; + + /* 1) len = product(shape) * itemsize + 2) itemsize > 0 + 3) len = 0 <==> exists i: shape[i] = 0 */ + if (view->len == 0) return 1; + if (view->strides == NULL) return 1; /* C-contiguous by definition */ + + /* strides != NULL implies both of these */ + assert(view->ndim > 0); + assert(view->shape != NULL); + + sd = view->itemsize; + for (i=view->ndim-1; i>=0; i--) { + dim = view->shape[i]; + if (dim > 1 && view->strides[i] != sd) { + return 0; + } + sd *= dim; + } + return 1; +} + +int +PyBuffer_IsContiguous(const Pep_buffer *view, char order) +{ + + if (view->suboffsets != NULL) return 0; + + if (order == 'C') + return _IsCContiguous(view); + else if (order == 'F') + return _IsFortranContiguous(view); + else if (order == 'A') + return (_IsCContiguous(view) || _IsFortranContiguous(view)); + return 0; +} + + +void* +PyBuffer_GetPointer(Pep_buffer *view, Py_ssize_t *indices) +{ + char* pointer; + int i; + pointer = (char *)view->buf; + for (i = 0; i < view->ndim; i++) { + pointer += view->strides[i]*indices[i]; + if ((view->suboffsets != NULL) && (view->suboffsets[i] >= 0)) { + pointer = *((char**)pointer) + view->suboffsets[i]; + } + } + return (void*)pointer; +} + + +void +_Py_add_one_to_index_F(int nd, Py_ssize_t *index, const Py_ssize_t *shape) +{ + int k; + + for (k=0; k<nd; k++) { + if (index[k] < shape[k]-1) { + index[k]++; + break; + } + else { + index[k] = 0; + } + } +} + +void +_Py_add_one_to_index_C(int nd, Py_ssize_t *index, const Py_ssize_t *shape) +{ + int k; + + for (k=nd-1; k>=0; k--) { + if (index[k] < shape[k]-1) { + index[k]++; + break; + } + else { + index[k] = 0; + } + } +} + +int +PyBuffer_FromContiguous(Pep_buffer *view, void *buf, Py_ssize_t len, char fort) +{ + int k; + void (*addone)(int, Py_ssize_t *, const Py_ssize_t *); + Py_ssize_t *indices, elements; + char *src, *ptr; + + if (len > view->len) { + len = view->len; + } + + if (PyBuffer_IsContiguous(view, fort)) { + /* simplest copy is all that is needed */ + memcpy(view->buf, buf, len); + return 0; + } + + /* Otherwise a more elaborate scheme is needed */ + + /* view->ndim <= 64 */ + indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*(view->ndim)); + if (indices == NULL) { + PyErr_NoMemory(); + return -1; + } + for (k=0; k<view->ndim;k++) { + indices[k] = 0; + } + + if (fort == 'F') { + addone = _Py_add_one_to_index_F; + } + else { + addone = _Py_add_one_to_index_C; + } + src = (char *)buf; // patched by CT + /* XXX : This is not going to be the fastest code in the world + several optimizations are possible. + */ + elements = len / view->itemsize; + while (elements--) { + ptr = (char *)PyBuffer_GetPointer(view, indices); // patched by CT + memcpy(ptr, src, view->itemsize); + src += view->itemsize; + addone(view->ndim, indices, view->shape); + } + + PyMem_Free(indices); + return 0; +} + +int PyObject_CopyData(PyObject *dest, PyObject *src) +{ + Pep_buffer view_dest, view_src; + int k; + Py_ssize_t *indices, elements; + char *dptr, *sptr; + + if (!PyObject_CheckBuffer(dest) || + !PyObject_CheckBuffer(src)) { + PyErr_SetString(PyExc_TypeError, + "both destination and source must be "\ + "bytes-like objects"); + return -1; + } + + if (PyObject_GetBuffer(dest, &view_dest, PyBUF_FULL) != 0) return -1; + if (PyObject_GetBuffer(src, &view_src, PyBUF_FULL_RO) != 0) { + PyBuffer_Release(&view_dest); + return -1; + } + + if (view_dest.len < view_src.len) { + PyErr_SetString(PyExc_BufferError, + "destination is too small to receive data from source"); + PyBuffer_Release(&view_dest); + PyBuffer_Release(&view_src); + return -1; + } + + if ((PyBuffer_IsContiguous(&view_dest, 'C') && + PyBuffer_IsContiguous(&view_src, 'C')) || + (PyBuffer_IsContiguous(&view_dest, 'F') && + PyBuffer_IsContiguous(&view_src, 'F'))) { + /* simplest copy is all that is needed */ + memcpy(view_dest.buf, view_src.buf, view_src.len); + PyBuffer_Release(&view_dest); + PyBuffer_Release(&view_src); + return 0; + } + + /* Otherwise a more elaborate copy scheme is needed */ + + /* XXX(nnorwitz): need to check for overflow! */ + indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view_src.ndim); + if (indices == NULL) { + PyErr_NoMemory(); + PyBuffer_Release(&view_dest); + PyBuffer_Release(&view_src); + return -1; + } + for (k=0; k<view_src.ndim;k++) { + indices[k] = 0; + } + elements = 1; + for (k=0; k<view_src.ndim; k++) { + /* XXX(nnorwitz): can this overflow? */ + elements *= view_src.shape[k]; + } + while (elements--) { + _Py_add_one_to_index_C(view_src.ndim, indices, view_src.shape); + dptr = (char *)PyBuffer_GetPointer(&view_dest, indices); // patched by CT + sptr = (char *)PyBuffer_GetPointer(&view_src, indices); // patched by CT + memcpy(dptr, sptr, view_src.itemsize); + } + PyMem_Free(indices); + PyBuffer_Release(&view_dest); + PyBuffer_Release(&view_src); + return 0; +} + +void +PyBuffer_FillContiguousStrides(int nd, Py_ssize_t *shape, + Py_ssize_t *strides, int itemsize, + char fort) +{ + int k; + Py_ssize_t sd; + + sd = itemsize; + if (fort == 'F') { + for (k=0; k<nd; k++) { + strides[k] = sd; + sd *= shape[k]; + } + } + else { + for (k=nd-1; k>=0; k--) { + strides[k] = sd; + sd *= shape[k]; + } + } + return; +} + +int +PyBuffer_FillInfo(Pep_buffer *view, PyObject *obj, void *buf, Py_ssize_t len, + int readonly, int flags) +{ + if (view == NULL) { + PyErr_SetString(PyExc_BufferError, + "PyBuffer_FillInfo: view==NULL argument is obsolete"); + return -1; + } + + if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) && + (readonly == 1)) { + PyErr_SetString(PyExc_BufferError, + "Object is not writable."); + return -1; + } + + view->obj = obj; + if (obj) + Py_INCREF(obj); + view->buf = buf; + view->len = len; + view->readonly = readonly; + view->itemsize = 1; + view->format = NULL; + if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) + view->format = (char *)"B"; // patched by CT + view->ndim = 1; + view->shape = NULL; + if ((flags & PyBUF_ND) == PyBUF_ND) + view->shape = &(view->len); + view->strides = NULL; + if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) + view->strides = &(view->itemsize); + view->suboffsets = NULL; + view->internal = NULL; + return 0; +} + +void +PyBuffer_Release(Pep_buffer *view) +{ + PyObject *obj = view->obj; + PyBufferProcs *pb; + if (obj == NULL) + return; + pb = PepType_AS_BUFFER(Py_TYPE(obj)); + if (pb && pb->bf_releasebuffer) + pb->bf_releasebuffer(obj, view); + view->obj = NULL; + Py_DECREF(obj); +} + +#endif // Py_LIMITED_API diff --git a/sources/shiboken2/libshiboken/bufferprocs27.h b/sources/shiboken2/libshiboken/bufferprocs27.h new file mode 100644 index 000000000..83c4a4750 --- /dev/null +++ b/sources/shiboken2/libshiboken/bufferprocs27.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +PSF LICENSE AGREEMENT FOR PYTHON 3.6.5¶ +1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and + the Individual or Organization ("Licensee") accessing and otherwise using Python + 3.6.2 software in source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby + grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, + analyze, test, perform and/or display publicly, prepare derivative works, + distribute, and otherwise use Python 3.6.2 alone or in any derivative + version, provided, however, that PSF's License Agreement and PSF's notice of + copyright, i.e., "Copyright © 2001-2017 Python Software Foundation; All Rights + Reserved" are retained in Python 3.6.2 alone or in any derivative version + prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on or + incorporates Python 3.6.2 or any part thereof, and wants to make the + derivative work available to others as provided herein, then Licensee hereby + agrees to include in any such work a brief summary of the changes made to Python + 3.6.2. + +4. PSF is making Python 3.6.2 available to Licensee on an "AS IS" basis. + PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF + EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR + WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE + USE OF PYTHON 3.6.2 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.6.2 + FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF + MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.6.2, OR ANY DERIVATIVE + THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material breach of + its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any relationship + of agency, partnership, or joint venture between PSF and Licensee. This License + Agreement does not grant permission to use PSF trademarks or trade name in a + trademark sense to endorse or promote products or services of Licensee, or any + third party. + +8. By copying, installing or otherwise using Python 3.6.2, Licensee agrees + to be bound by the terms and conditions of this License Agreement. +*/ + +#ifndef BUFFER_REENABLE_H +#define BUFFER_REENABLE_H + +/* buffer interface */ +// This has been renamed to Pep_buffer and will be used. +typedef struct bufferinfo { + void *buf; + PyObject *obj; /* owned reference */ + Py_ssize_t len; + Py_ssize_t itemsize; /* This is Py_ssize_t so it can be + pointed to by strides in simple case.*/ + int readonly; + int ndim; + char *format; + Py_ssize_t *shape; + Py_ssize_t *strides; + Py_ssize_t *suboffsets; + void *internal; +} Pep_buffer; + +typedef int (*getbufferproc)(PyObject *, Pep_buffer *, int); +typedef void (*releasebufferproc)(PyObject *, Pep_buffer *); + +/* Maximum number of dimensions */ +#define PyBUF_MAX_NDIM 64 + +/* Flags for getting buffers */ +#define PyBUF_SIMPLE 0 +#define PyBUF_WRITABLE 0x0001 +/* we used to include an E, backwards compatible alias */ +#define PyBUF_WRITEABLE PyBUF_WRITABLE +#define PyBUF_FORMAT 0x0004 +#define PyBUF_ND 0x0008 +#define PyBUF_STRIDES (0x0010 | PyBUF_ND) +#define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES) +#define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES) +#define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES) +#define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES) + +#define PyBUF_CONTIG (PyBUF_ND | PyBUF_WRITABLE) +#define PyBUF_CONTIG_RO (PyBUF_ND) + +#define PyBUF_STRIDED (PyBUF_STRIDES | PyBUF_WRITABLE) +#define PyBUF_STRIDED_RO (PyBUF_STRIDES) + +#define PyBUF_RECORDS (PyBUF_STRIDES | PyBUF_WRITABLE | PyBUF_FORMAT) +#define PyBUF_RECORDS_RO (PyBUF_STRIDES | PyBUF_FORMAT) + +#define PyBUF_FULL (PyBUF_INDIRECT | PyBUF_WRITABLE | PyBUF_FORMAT) +#define PyBUF_FULL_RO (PyBUF_INDIRECT | PyBUF_FORMAT) + + +#define PyBUF_READ 0x100 +#define PyBUF_WRITE 0x200 + +/* End buffer interface */ +LIBSHIBOKEN_API PyObject *PyMemoryView_FromBuffer(Pep_buffer *info); +#define Py_buffer Pep_buffer + +#endif // BUFFER_REENABLE_H diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp new file mode 100644 index 000000000..2707d3716 --- /dev/null +++ b/sources/shiboken2/libshiboken/pep384impl.cpp @@ -0,0 +1,924 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "pep384impl.h" + +extern "C" +{ + +/********************************************************************** + ********************************************************************** + + + The New Type API + ================ + + After converting everything but the "object.h" file, we could not + believe our eyes: it suddenly was clear that we would have no more + access to type objects, and even more scary that all types which we + use have to be heap types, only! + + For PySide with it's intense use of heap type extensions in various + flavors, it seemed to be quite unsolvable. In the end, it was + nicely solved, but it took almost 3.5 months to get that right. + + Before we see how this is done, we will explain the differences + between the APIs and their consequences. + + + The Interface + ------------- + + The old type API of Python knows static types and heap types. + Static types are written down as a declaration of a PyTypeObject + structure with all its fields filled in. Here is for example + the definition of the Python type "object": + + PyTypeObject PyBaseObject_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "object", |* tp_name *| + sizeof(PyObject), |* tp_basicsize *| + 0, |* tp_itemsize *| + object_dealloc, |* tp_dealloc *| + 0, |* tp_print *| + 0, |* tp_getattr *| + 0, |* tp_setattr *| + 0, |* tp_reserved *| + object_repr, |* tp_repr *| + 0, |* tp_as_number *| + 0, |* tp_as_sequence *| + 0, |* tp_as_mapping *| + (hashfunc)_Py_HashPointer, |* tp_hash *| + 0, |* tp_call *| + object_str, |* tp_str *| + PyObject_GenericGetAttr, |* tp_getattro *| + PyObject_GenericSetAttr, |* tp_setattro *| + 0, |* tp_as_buffer *| + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, |* tp_flags *| + PyDoc_STR("object()\n--\n\nThe most base type"), |* tp_doc *| + 0, |* tp_traverse *| + 0, |* tp_clear *| + object_richcompare, |* tp_richcompare *| + 0, |* tp_weaklistoffset *| + 0, |* tp_iter *| + 0, |* tp_iternext *| + object_methods, |* tp_methods *| + 0, |* tp_members *| + object_getsets, |* tp_getset *| + 0, |* tp_base *| + 0, |* tp_dict *| + 0, |* tp_descr_get *| + 0, |* tp_descr_set *| + 0, |* tp_dictoffset *| + object_init, |* tp_init *| + PyType_GenericAlloc, |* tp_alloc *| + object_new, |* tp_new *| + PyObject_Del, |* tp_free *| + }; + + We can write the same structure in form of a PyType_Spec structure, + and there is even a tool that does this for us, but I had to fix a + few things because there is little support for this. + + The tool is XXX go home and continue..... + + + + + The Transition To Simpler Types + =============================== + + After all code has been converted to the limited API, there is the + PyHeapTypeObject remaining as a problem. + + Why a problem? Well, all the type structures in shiboken use + special extra fields at the end of the heap type object. This + currently enforces knowledge at compile time about how large the + heap type object is. In a clean implementation, we would only use + the PyTypeObject itself and access the fields "behind" the type + by a pointer that is computed at runtime. + + + Excursion: PepTypeObject + ------------------------ + + Before we are going into details, let us motivate the existence of + the PepTypeObject, an alias to PyTypeObject: + + Originally, we wanted to use PyTypeObject as an opaque type and + restrict ourselves to only use the access function PyType_GetSlot. + This function allows access to all fields which are supported by + the limited API. + + But this is a restriction, because we get no access to tp_dict, + which we need to support the signature extension. But we can work + around that. + + The real restriction is that PyType_GetSlot only works for heap + types. This makes the function quite useless, because we have + no access to PyType_Type, which is the most important type "type" + in Python. We need that for instance to compute the size of + PyHeapTypeObject dynamically. + + With much effort, it is possible to clone PyType_Type as a heap + type. But due to a bug in the Pep 384 support, we need + access to the nb_index field of a normal type. Cloning does not + help because PyNumberMethods fields are not inherited. + + After I realized this dead end, I changed the concept and did not + use PyType_GetSlot at all (except in function copyNumberMethods), + but created PepTypeObject as a remake of PyTypeObject with only + those fields defined that are needed in PySide. + + Is this breakage of the limited API? I don't think so. A special + function runs on program startup that checks the correct position + of the fields of PepHeapType, although a change in those fields is + more than unlikely. + The really crucial thing is to no longer use PyHeapTypeObject + explicitly because that _does_ change its layout over time. + + + Diversification + --------------- + + There are multiple SbkXXX structures which all use a "d" field + for their private data. This makes it not easy to find the right + fields when switching between types and objects. + + struct LIBSHIBOKEN_API SbkObjectType + { + PyHeapTypeObject super; + SbkObjectTypePrivate *d; + }; + + struct LIBSHIBOKEN_API SbkObject + { + PyObject_HEAD + PyObject* ob_dict; + PyObject* weakreflist; + SbkObjectPrivate* d; + }; + + The first step was to rename the SbkObjectTypePrivate from "d" to + "sotp". It was chosen to be short but easy to remember. + + + Abstraction + ----------- + + After renaming the type extension pointers to "sotp", I replaced + them by function-like macros which did the special access "behind" + the types, instead of those explicit fields. For instance, the + expression + + type->sotp->converter + + became + + PepType_SOTP(type)->converter + + The macro expression can be seen here: + + #define _genericTypeExtender(etype) \ + (reinterpret_cast<char*>(etype) + \ + (reinterpret_cast<PepTypeObject*>(&PyType_Type))->tp_basicsize) + + #define PepType_SOTP(etype) \ + (*reinterpret_cast<SbkObjectTypePrivate**>(_genericTypeExtender(etype))) + + It looks complicated, but in the end there is only a single new + indirection via PyType_Type, which happens at runtime. This is the + key to fulfil what Pep 384 wants: No version-dependent fields. + + + Simplification + -------------- + + After all type extension fields were replaced by macro calls, we + could remove the version dependent definition + + typedef struct _pepheaptypeobject { + union { + PepTypeObject ht_type; + void *opaque[PY_HEAPTYPE_SIZE]; + }; + } PepHeapTypeObject; + + and the version dependent structure + + struct LIBSHIBOKEN_API SbkObjectType + { + PepHeapTypeObject super; + SbkObjectTypePrivate *sotp; + }; + + could be replaced by the simplified + + struct LIBSHIBOKEN_API SbkObjectType + { + PepTypeObject type; + }; + + which is no longer version-dependent. + + + Verification Of PepTypeObject + ============================= + + We have introduced PepTypeObject as a new alias for PyTypeObject, + and now we need to prove that we are allowed to do so. + + When using the limited API as intended, then types are completely + opaque, and access is only through PyType_FromSpec and (from + version 3.5 upwards) through PyType_GetSlot. + + Python then uses all the slot definitions in the type description + and produces a regular type object. + + + Unused Information + ------------------ + + But we know many things about types that are not explicitly said, + but they are inherently clear: + + a) The basic structure of a type is always the same, regardless + if it is a static type or a heap type. + + b) types are evolving very slowly, and a field is never replaced + by another field with different semantics. + + Inherent rule a) gives us the following information: If we calculate + the offsets of the fields, then this info is also usable for non- + -heap types. + + The validation checks if rule b) is still valid. + + + How it Works + ------------ + + The basic idea of the validation is to produce a new type using + PyType_FromSpec and to see where in the type structure these fields + show up. So we build a PyType_Slot structure with all the fields we + are using and make sure that these values are all unique in the + type. + + Most fields are not investigated by PyType_FromSpec, and so we + simply used some numeric value. Some fields are interpreted, like + tp_members. This field must really be a PyMemberDef. And there are + tp_base and tp_bases which have to be type objects and lists + thereof. It was easiest to not produce these fields from scratch + but use them from the "type" object PyType_Type. + + Then one would think to write a function that searches the known + values in the opaque type structure. + + But we can do better and use optimistically the observation (b): + We simply use the PepTypeObject structure and assume that every + field lands exactly where we are awaiting it. + + And that is the whole proof: If we find all the disjoint values at + the places where we expect them, thenthis is q.e.d. :) + + + About tp_dict + ------------- + + One word about the tp_dict field: This field is a bit special in + the proof, since it does not appear in the spec and cannot easily + be checked by "type.__dict__" because that creates a dictproxy + object. So how do we proove that is really the right dict? + + We have to create that PyMethodDef structure anyway, and instead of + leaving it empty, we insert a dummy function. Then we ask the + tp_dict field if it has that object in it, and that's q.e.d. + + + *********/ + + +/***************************************************************************** + * + * Support for object.h + * + */ + +/* + * Here is the verification code for PepTypeObject. + * We create a type object and check if its fields + * appear at the right offsets. + */ + +#define make_dummy_int(x) (x * sizeof(void*)) +#define make_dummy(x) (reinterpret_cast<void*>(make_dummy_int(x))) + +#ifdef Py_LIMITED_API +datetime_struc *PyDateTimeAPI = NULL; +#endif + +static PyObject * +dummy_func(PyObject *self, PyObject *args) +{ + Py_RETURN_NONE; +} + +static struct PyMethodDef probe_methoddef[] = { + {"dummy", dummy_func, METH_NOARGS}, + {0} +}; + +#define probe_tp_call make_dummy(1) +#define probe_tp_str make_dummy(2) +#define probe_tp_traverse make_dummy(3) +#define probe_tp_clear make_dummy(4) +#define probe_tp_methods probe_methoddef +#define probe_tp_descr_get make_dummy(6) +#define probe_tp_init make_dummy(7) +#define probe_tp_alloc make_dummy(8) +#define probe_tp_new make_dummy(9) +#define probe_tp_free make_dummy(10) +#define probe_tp_is_gc make_dummy(11) + +#define probe_tp_name "type.probe" +#define probe_tp_basicsize make_dummy_int(42) + +static PyType_Slot typeprobe_slots[] = { + {Py_tp_call, probe_tp_call}, + {Py_tp_str, probe_tp_str}, + {Py_tp_traverse, probe_tp_traverse}, + {Py_tp_clear, probe_tp_clear}, + {Py_tp_methods, probe_tp_methods}, + {Py_tp_descr_get, probe_tp_descr_get}, + {Py_tp_init, probe_tp_init}, + {Py_tp_alloc, probe_tp_alloc}, + {Py_tp_new, probe_tp_new}, + {Py_tp_free, probe_tp_free}, + {Py_tp_is_gc, probe_tp_is_gc}, + {0, 0} +}; +static PyType_Spec typeprobe_spec = { + probe_tp_name, + probe_tp_basicsize, + 0, + Py_TPFLAGS_DEFAULT, + typeprobe_slots, +}; + +static void +check_PepTypeObject_valid(void) +{ + PyObject *obtype = reinterpret_cast<PyObject*>(&PyType_Type); + PyTypeObject *probe_tp_base = reinterpret_cast<PyTypeObject*>( + PyObject_GetAttrString(obtype, "__base__")); + PyObject *probe_tp_bases = PyObject_GetAttrString(obtype, "__bases__"); + PepTypeObject *check = reinterpret_cast<PepTypeObject*>( + PyType_FromSpecWithBases(&typeprobe_spec, probe_tp_bases)); + PepTypeObject *typetype = reinterpret_cast<PepTypeObject*>(obtype); + PyObject *w = PyObject_GetAttrString(obtype, "__weakrefoffset__"); + long probe_tp_weakrefoffset = PyLong_AsLong(w); + PyObject *d = PyObject_GetAttrString(obtype, "__dictoffset__"); + long probe_tp_dictoffset = PyLong_AsLong(d); + PyObject *probe_tp_mro = PyObject_GetAttrString(obtype, "__mro__"); + if (false + || probe_tp_name != check->tp_name + || probe_tp_basicsize != check->tp_basicsize + || probe_tp_call != check->tp_call + || probe_tp_str != check->tp_str + || probe_tp_traverse != check->tp_traverse + || probe_tp_clear != check->tp_clear + || probe_tp_weakrefoffset != typetype->tp_weaklistoffset + || probe_tp_methods != check->tp_methods + || probe_tp_base != typetype->tp_base + || !PyDict_Check(check->tp_dict) + || !PyDict_GetItemString(check->tp_dict, "dummy") + || probe_tp_descr_get != check->tp_descr_get + || probe_tp_dictoffset != typetype->tp_dictoffset + || probe_tp_init != check->tp_init + || probe_tp_alloc != check->tp_alloc + || probe_tp_new != check->tp_new + || probe_tp_free != check->tp_free + || probe_tp_is_gc != check->tp_is_gc + || probe_tp_bases != typetype->tp_bases + || probe_tp_mro != typetype->tp_mro) + Py_FatalError("The structure of type objects has changed!"); + Py_DECREF(check); + Py_DECREF(probe_tp_base); + Py_DECREF(w); + Py_DECREF(d); + Py_DECREF(probe_tp_bases); + Py_DECREF(probe_tp_mro); +} + + +#ifdef Py_LIMITED_API + +// This structure is only here because Python 3 has an error. +// I will fix that. + +typedef struct { + /* Number implementations must check *both* + arguments for proper type and implement the necessary conversions + in the slot functions themselves. */ + + binaryfunc nb_add; + binaryfunc nb_subtract; + binaryfunc nb_multiply; + binaryfunc nb_remainder; + binaryfunc nb_divmod; + ternaryfunc nb_power; + unaryfunc nb_negative; + unaryfunc nb_positive; + unaryfunc nb_absolute; + inquiry nb_bool; + unaryfunc nb_invert; + binaryfunc nb_lshift; + binaryfunc nb_rshift; + binaryfunc nb_and; + binaryfunc nb_xor; + binaryfunc nb_or; + unaryfunc nb_int; + void *nb_reserved; /* the slot formerly known as nb_long */ + unaryfunc nb_float; + + binaryfunc nb_inplace_add; + binaryfunc nb_inplace_subtract; + binaryfunc nb_inplace_multiply; + binaryfunc nb_inplace_remainder; + ternaryfunc nb_inplace_power; + binaryfunc nb_inplace_lshift; + binaryfunc nb_inplace_rshift; + binaryfunc nb_inplace_and; + binaryfunc nb_inplace_xor; + binaryfunc nb_inplace_or; + + binaryfunc nb_floor_divide; + binaryfunc nb_true_divide; + binaryfunc nb_inplace_floor_divide; + binaryfunc nb_inplace_true_divide; + + unaryfunc nb_index; + + binaryfunc nb_matrix_multiply; + binaryfunc nb_inplace_matrix_multiply; +} PyNumberMethods; + +// temporary structure until we have a generator for the offsets +typedef struct _oldtypeobject { + PyVarObject ob_base; + void *X01; // const char *tp_name; + void *X02; // Py_ssize_t tp_basicsize; + void *X03; // Py_ssize_t tp_itemsize; + void *X04; // destructor tp_dealloc; + void *X05; // printfunc tp_print; + void *X06; // getattrfunc tp_getattr; + void *X07; // setattrfunc tp_setattr; + void *X08; // PyAsyncMethods *tp_as_async; + void *X09; // reprfunc tp_repr; + PyNumberMethods *tp_as_number; + +} PyOldTypeObject; + +// There is a bug in Python 3.6 that turned the Index_Check function +// into a macro without taking care of the limited API. +// This leads to the single problem that we don't have +// access to PyLong_Type's nb_index field which is no heap type. +// We cannot easily create this function by inheritance since it is +// not inherited. +// +// Simple solution: Create the structure and write such a function. +// Long term: Submit a patch to python.org . + +unaryfunc +PepType_nb_index(PyTypeObject *type) +{ + return reinterpret_cast<PyOldTypeObject*>(type)->tp_as_number->nb_index; +} + +int PyIndex_Check(PyObject *obj) +{ + PyOldTypeObject *type = reinterpret_cast<PyOldTypeObject*>(Py_TYPE(obj)); + return type->tp_as_number != NULL && + type->tp_as_number->nb_index != NULL; +} + +/***************************************************************************** + * + * Support for unicodeobject.h + * + */ + +char * +_PepUnicode_AsString(PyObject *str) +{ + /* + * We need to keep the string alive but cannot borrow the Python object. + * Ugly easy way out: We re-code as an interned bytes string. This + * produces a pseudo-leak as long there are new strings. + * Typically, this function is used for name strings, and the dict size + * will not grow so much. + */ +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) +#define AT __FILE__ ":" TOSTRING(__LINE__) + + static PyObject *cstring_dict = NULL; + if (cstring_dict == NULL) { + cstring_dict = PyDict_New(); + if (cstring_dict == NULL) + Py_FatalError("Error in " AT); + } + PyObject *bytesStr = PyUnicode_AsEncodedString(str, "utf8", NULL); + PyObject *entry = PyDict_GetItem(cstring_dict, bytesStr); + if (entry == NULL) { + int e = PyDict_SetItem(cstring_dict, bytesStr, bytesStr); + if (e != 0) + Py_FatalError("Error in " AT); + entry = bytesStr; + } + else + Py_DECREF(bytesStr); + return PyBytes_AsString(entry); +} + +/***************************************************************************** + * + * Support for longobject.h + * + */ + +/* + * This is the original Python function _PyLong_AsInt() from longobject.c . + * We define it here because we are not allowed to use the function + * from Python with an underscore. + */ + +/* Get a C int from an int object or any object that has an __int__ + method. Return -1 and set an error if overflow occurs. */ + +int +_PepLong_AsInt(PyObject *obj) +{ + int overflow; + long result = PyLong_AsLongAndOverflow(obj, &overflow); + if (overflow || result > INT_MAX || result < INT_MIN) { + /* XXX: could be cute and give a different + message for overflow == -1 */ + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C int"); + return -1; + } + return (int)result; +} + +/***************************************************************************** + * + * Support for pydebug.h + * + */ +static PyObject *sys_flags = NULL; + +int +Pep_GetFlag(const char *name) +{ + static int initialized = 0; + int ret = -1; + + if (!initialized) { + sys_flags = PySys_GetObject("flags"); + // func gives no error if NULL is returned and does not incref. + Py_XINCREF(sys_flags); + initialized = 1; + } + if (sys_flags != NULL) { + PyObject *ob_ret = PyObject_GetAttrString(sys_flags, name); + if (ob_ret != NULL) { + long long_ret = PyLong_AsLong(ob_ret); + Py_DECREF(ob_ret); + ret = (int) long_ret; + } + } + return ret; +} + +int +Pep_GetVerboseFlag() +{ + static int initialized = 0; + static int verbose_flag = -1; + + if (!initialized) { + verbose_flag = Pep_GetFlag("verbose"); + if (verbose_flag != -1) + initialized = 1; + } + return verbose_flag; +} + +/***************************************************************************** + * + * Support for code.h + * + */ + +int +PepCode_Get(PyCodeObject *co, const char *name) +{ + PyObject *ob = (PyObject *)co; + PyObject *ob_ret; + int ret = -1; + + ob_ret = PyObject_GetAttrString(ob, name); + if (ob_ret != NULL) { + long long_ret = PyLong_AsLong(ob_ret); + Py_DECREF(ob_ret); + ret = (int) long_ret; + } + return ret; +} + +/***************************************************************************** + * + * Support for datetime.h + * + */ + +static PyTypeObject *dt_getCheck(const char *name) +{ + PyObject *op = PyObject_GetAttrString(PyDateTimeAPI->module, name); + if (op == NULL) { + fprintf(stderr, "datetime.%s not found\n", name); + Py_FatalError("aborting"); + } + return (PyTypeObject *)op; +} + +// init_DateTime is called earlier than our module init. +// We use the provided PyDateTime_IMPORT machinery. +datetime_struc * +init_DateTime(void) +{ + static int initialized = 0; + if (!initialized) { + PyDateTimeAPI = (datetime_struc *)malloc(sizeof(datetime_struc)); + if (PyDateTimeAPI == NULL) + Py_FatalError("PyDateTimeAPI malloc error, aborting"); + PyDateTimeAPI->module = PyImport_ImportModule("datetime"); + if (PyDateTimeAPI->module == NULL) + Py_FatalError("datetime module not found, aborting"); + PyDateTimeAPI->DateType = dt_getCheck("date"); + PyDateTimeAPI->DateTimeType = dt_getCheck("datetime"); + PyDateTimeAPI->TimeType = dt_getCheck("time"); + PyDateTimeAPI->DeltaType = dt_getCheck("timedelta"); + PyDateTimeAPI->TZInfoType = dt_getCheck("tzinfo"); + initialized = 1; + } + return PyDateTimeAPI; +} + +int +PyDateTime_Get(PyObject *ob, const char *name) +{ + PyObject *ob_ret; + int ret = -1; + + ob_ret = PyObject_GetAttrString(ob, name); + if (ob_ret != NULL) { + long long_ret = PyLong_AsLong(ob_ret); + Py_DECREF(ob_ret); + ret = (int) long_ret; + } + return ret; +} + +PyObject * +PyDate_FromDate(int year, int month, int day) +{ + return PyObject_CallFunction((PyObject *)PyDateTimeAPI->DateType, + (char *)"(iii)", year, month, day); +} + +PyObject * +PyDateTime_FromDateAndTime(int year, int month, int day, + int hour, int min, int sec, int usec) +{ + return PyObject_CallFunction((PyObject *)PyDateTimeAPI->DateTimeType, + (char *)"(iiiiiii)", year, month, day, + hour, min, sec, usec); +} + +PyObject * +PyTime_FromTime(int hour, int min, int sec, int usec) +{ + return PyObject_CallFunction((PyObject *)PyDateTimeAPI->TimeType, + (char *)"(iiii)", hour, min, sec, usec); +} + +/***************************************************************************** + * + * Support for pythonrun.h + * + */ + +// Flags are ignored in these simple helpers. +PyObject * +PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals) +{ + PyObject* code = Py_CompileString(str, "pyscript", start); + PyObject* ret = NULL; + + if (code != NULL) { + ret = PyEval_EvalCode(code, globals, locals); + } + Py_XDECREF(code); + return ret; +} + +// This is only a simple local helper that returns a computed variable. +static PyObject * +PepRun_GetResult(const char *command, const char *resvar) +{ + PyObject *d, *v, *res; + + d = PyDict_New(); + if (d == NULL || PyDict_SetItemString(d, "__builtins__", + PyEval_GetBuiltins()) < 0) + return NULL; + v = PyRun_String(command, Py_file_input, d, d); + res = v ? PyDict_GetItemString(d, resvar) : NULL; + Py_XDECREF(v); + Py_DECREF(d); + return res; +} + +/***************************************************************************** + * + * Support for classobject.h + * + */ + +PyTypeObject *PepMethod_TypePtr = NULL; + +static PyTypeObject *getMethodType(void) +{ + static const char prog[] = + "class _C:\n" + " def _m(self): pass\n" + "MethodType = type(_C()._m)\n"; + return (PyTypeObject *) PepRun_GetResult(prog, "MethodType"); +} + +// We have no access to PyMethod_New and must call types.MethodType, instead. +PyObject * +PyMethod_New(PyObject *func, PyObject *self) +{ + return PyObject_CallFunction((PyObject *)PepMethod_TypePtr, + (char *)"(OO)", func, self); +} + +PyObject * +PyMethod_Function(PyObject *im) +{ + PyObject *ret = PyObject_GetAttrString(im, "__func__"); + + // We have to return a borrowed reference. + Py_DECREF(ret); + return ret; +} + +PyObject * +PyMethod_Self(PyObject *im) +{ + PyObject *ret = PyObject_GetAttrString(im, "__self__"); + + // We have to return a borrowed reference. + // If we don't obey that here, then we get a test error! + Py_DECREF(ret); + return ret; +} + +/***************************************************************************** + * + * Support for funcobject.h + * + */ + +PyObject * +PepFunction_Get(PyObject *ob, const char *name) +{ + PyObject *ret; + + // We have to return a borrowed reference. + ret = PyObject_GetAttrString(ob, name); + Py_XDECREF(ret); + return ret; +} + +/***************************************************************************** + * + * Support for funcobject.h + * + */ + +// this became necessary after Windows was activated. + +PyTypeObject *PepFunction_TypePtr = NULL; + +static PyTypeObject *getFunctionType(void) +{ + static const char prog[] = + "from types import FunctionType\n"; + return (PyTypeObject *) PepRun_GetResult(prog, "FunctionType"); +} + +/***************************************************************************** + * + * Extra support for signature.cpp + * + */ + +PyTypeObject *PepStaticMethod_TypePtr = NULL; + +static PyTypeObject *getStaticMethodType(void) +{ + static const char prog[] = + "StaticMethodType = type(str.__dict__['maketrans'])\n"; + return (PyTypeObject *) PepRun_GetResult(prog, "StaticMethodType"); +} + +#endif // Py_LIMITED_API + +/***************************************************************************** + * + * Common newly needed functions + * + */ + +// The introduction of heaptypes converted many type names to the +// dotted form, since PyType_FromSpec uses it to compute the module +// name. This function reverts this effect. +const char * +PepType_GetNameStr(PyTypeObject *type) +{ + const char *ret = PepType(type)->tp_name; + const char *nodots = strrchr(ret, '.'); + if (nodots) + ret = nodots + 1; + return ret; +} + +/***************************************************************************** + * + * Module Initialization + * + */ + +void +Pep_Init() +{ + check_PepTypeObject_valid(); +#ifdef Py_LIMITED_API + Pep_GetVerboseFlag(); + PepMethod_TypePtr = getMethodType(); + PepFunction_TypePtr = getFunctionType(); + PepStaticMethod_TypePtr = getStaticMethodType(); +#endif +} + +} // extern "C" diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h new file mode 100644 index 000000000..fc0e3b40e --- /dev/null +++ b/sources/shiboken2/libshiboken/pep384impl.h @@ -0,0 +1,571 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PEP384IMPL_H +#define PEP384IMPL_H + +#include "sbkpython.h" + +extern "C" +{ + +/***************************************************************************** + * + * RESOLVED: memoryobject.h + * + */ + +// Extracted into bufferprocs27.h +#ifdef Py_LIMITED_API +#include "bufferprocs27.h" +#endif + +/***************************************************************************** + * + * RESOLVED: object.h + * + */ +#ifdef Py_LIMITED_API +// Why the hell is this useful debugging function not allowed? +LIBSHIBOKEN_API void _PyObject_Dump(PyObject *); +#endif + +/* + * There are a few structures that are needed, but cannot be used without + * breaking the API. We use some heuristics to get those fields anyway + * and validate that we really found them, see Pepresolve.cpp . + */ + +// PepType is just a typecast that allows direct access. This is +// often better to read than the reversal via the former macro +// functions PepType_tp_xxx. +#define PepType(o) (reinterpret_cast<PepTypeObject*>(o)) + +#ifdef Py_LIMITED_API + +/* + * These are the type object fields that we use. + * We will verify that they never change. + * The unused fields are intentionally named as "void *Xnn" because + * the chance is smaller to forget to validate a field. + * When we need more fields, we replace it back and add it to the + * validation. + */ +typedef struct _peptypeobject { + PyVarObject ob_base; + const char *tp_name; + Py_ssize_t tp_basicsize; + void *X03; // Py_ssize_t tp_itemsize; + void *X04; // destructor tp_dealloc; + void *X05; // printfunc tp_print; + void *X06; // getattrfunc tp_getattr; + void *X07; // setattrfunc tp_setattr; + void *X08; // PyAsyncMethods *tp_as_async; + void *X09; // reprfunc tp_repr; + void *X10; // PyNumberMethods *tp_as_number; + void *X11; // PySequenceMethods *tp_as_sequence; + void *X12; // PyMappingMethods *tp_as_mapping; + void *X13; // hashfunc tp_hash; + ternaryfunc tp_call; + reprfunc tp_str; + void *X16; // getattrofunc tp_getattro; + void *X17; // setattrofunc tp_setattro; + void *X18; // PyBufferProcs *tp_as_buffer; + void *X19; // unsigned long tp_flags; + void *X20; // const char *tp_doc; + traverseproc tp_traverse; + inquiry tp_clear; + void *X23; // richcmpfunc tp_richcompare; + Py_ssize_t tp_weaklistoffset; + void *X25; // getiterfunc tp_iter; + void *X26; // iternextfunc tp_iternext; + struct PyMethodDef *tp_methods; + void *X28; // struct PyMemberDef *tp_members; + void *X29; // struct PyGetSetDef *tp_getset; + struct _typeobject *tp_base; + PyObject *tp_dict; + descrgetfunc tp_descr_get; + void *X33; // descrsetfunc tp_descr_set; + Py_ssize_t tp_dictoffset; + initproc tp_init; + allocfunc tp_alloc; + newfunc tp_new; + freefunc tp_free; + inquiry tp_is_gc; /* For PyObject_IS_GC */ + PyObject *tp_bases; + PyObject *tp_mro; /* method resolution order */ + +} PepTypeObject; + +LIBSHIBOKEN_API unaryfunc PepType_nb_index(PyTypeObject *type); + +#undef PyIndex_Check + +LIBSHIBOKEN_API int PyIndex_Check(PyObject *obj); + +#undef PyObject_IS_GC +#define PyObject_IS_GC(o) (PyType_IS_GC(Py_TYPE(o)) && \ + ( PepType(Py_TYPE(o))->tp_is_gc == NULL || \ + PepType(Py_TYPE(o))->tp_is_gc(o) )) + +#else +#define PepTypeObject PyTypeObject +#define PepType_nb_index(o) (PepType(o)->nb_index) +#endif // Py_LIMITED_API + +struct SbkObjectTypePrivate; +struct PySideQFlagsTypePrivate; +struct _SbkGenericTypePrivate; + +#define PepHeapType_SIZE \ + (reinterpret_cast<PepTypeObject*>(&PyType_Type)->tp_basicsize) + +#define _genericTypeExtender(etype) \ + (reinterpret_cast<char*>(etype) + PepHeapType_SIZE) + +#define PepType_SOTP(etype) \ + (*reinterpret_cast<SbkObjectTypePrivate**>(_genericTypeExtender(etype))) + +#define PepType_SETP(etype) \ + (reinterpret_cast<SbkEnumTypePrivate*>(_genericTypeExtender(etype))) + +#define PepType_PFTP(etype) \ + (reinterpret_cast<PySideQFlagsTypePrivate*>(_genericTypeExtender(etype))) + +#define PepType_SGTP(etype) \ + (reinterpret_cast<_SbkGenericTypePrivate*>(_genericTypeExtender(etype))) + +// functions used everywhere +LIBSHIBOKEN_API const char *PepType_GetNameStr(PyTypeObject *type); + +/***************************************************************************** + * + * RESOLVED: longobject.h + * + */ +#ifdef Py_LIMITED_API +LIBSHIBOKEN_API int _PepLong_AsInt(PyObject *); +#else +#define _PepLong_AsInt _PyLong_AsInt +#endif + +/***************************************************************************** + * + * RESOLVED: pydebug.h + * + */ +#ifdef Py_LIMITED_API +/* + * We have no direct access to Py_VerboseFlag because debugging is not + * supported. The python developers are partially a bit too rigorous. + * Instead, we compute the value and use a function call macro. + * Was before: extern LIBSHIBOKEN_API int Py_VerboseFlag; + */ +LIBSHIBOKEN_API int Pep_GetFlag(const char *name); +LIBSHIBOKEN_API int Pep_GetVerboseFlag(void); +#define Py_VerboseFlag Pep_GetVerboseFlag() +#endif + +/***************************************************************************** + * + * RESOLVED: unicodeobject.h + * + */ +#ifdef Py_LIMITED_API + +LIBSHIBOKEN_API char *_PepUnicode_AsString(PyObject *); + +#define PyUnicode_GET_SIZE(op) PyUnicode_GetSize((PyObject *)(op)) + +#else +#define _PepUnicode_AsString PyUnicode_AsUTF8 +#endif + +/***************************************************************************** + * + * RESOLVED: bytesobject.h + * + */ +#ifdef Py_LIMITED_API +#define PyBytes_AS_STRING(op) PyBytes_AsString(op) +#define PyBytes_GET_SIZE(op) PyBytes_Size(op) +#endif + +/***************************************************************************** + * + * RESOLVED: floatobject.h + * + */ +#ifdef Py_LIMITED_API +#define PyFloat_AS_DOUBLE(op) PyFloat_AsDouble(op) +#endif + +/***************************************************************************** + * + * RESOLVED: tupleobject.h + * + */ +#ifdef Py_LIMITED_API +#define PyTuple_GET_ITEM(op, i) PyTuple_GetItem((PyObject *)op, i) +#define PyTuple_GET_SIZE(op) PyTuple_Size((PyObject *)op) +#define PyTuple_SET_ITEM(op, i, v) PyTuple_SetItem(op, i, v) +#endif + +/***************************************************************************** + * + * RESOLVED: listobject.h + * + */ +#ifdef Py_LIMITED_API +#define PyList_GET_ITEM(op, i) PyList_GetItem(op, i) +#define PyList_SET_ITEM(op, i, v) PyList_SetItem(op, i, v) +#define PyList_GET_SIZE(op) PyList_Size(op) +#endif + +/***************************************************************************** + * + * RESOLVED: methodobject.h + * + */ + +#ifdef Py_LIMITED_API + +typedef struct _pycfunc PyCFunctionObject; +#define PyCFunction_GET_FUNCTION(func) PyCFunction_GetFunction((PyObject *)func) +#define PyCFunction_GET_SELF(func) PyCFunction_GetSelf((PyObject *)func) +#define PyCFunction_GET_FLAGS(func) PyCFunction_GetFlags((PyObject *)func) +#define PepCFunction_GET_NAMESTR(func) \ + _PepUnicode_AsString(PyObject_GetAttrString((PyObject *)func, "__name__")) +#else +#define PepCFunction_GET_NAMESTR(func) ((func)->m_ml->ml_name) +#endif + +/***************************************************************************** + * + * RESOLVED: descrobject.h + * + */ +#ifdef Py_LIMITED_API +typedef struct _methoddescr PyMethodDescrObject; +#endif + +/***************************************************************************** + * + * RESOLVED: pystate.h + * + */ + +/* + * pystate provides the data structure that is needed for the trashcan + * algorithm. Unfortunately, it is not included in the limited API. + * We have two options: + * + * (1) ignore trashcan and live without secured deeply nested structures, + * (2) maintain the structure ourselves and make sure it does not change. + * + * I have chosen the second option. + * + * When a new python version appears, you need to check compatibility of + * the PyThreadState structure (pystate.h) and the trashcan macros at the + * end of object.h . + */ + +#ifdef Py_LIMITED_API + +#define Py_TRASH_MIN_COMPATIBLE 0x03020400 +#define Py_TRASH_MAX_COMPATIBLE 0x030700A0 + +#if PY_VERSION_HEX >= Py_TRASH_MIN_COMPATIBLE && \ + PY_VERSION_HEX <= Py_TRASH_MAX_COMPATIBLE +typedef int (*Py_tracefunc)(PyObject *, struct _frame *, int, PyObject *); + +// This structure has the trashcan variables since Python 3.2.4. +// We renamed all but the trashcan fields to make sure that we don't use +// anything else somewhere. + +typedef struct _ts { + struct _ts *Pep_prev; + struct _ts *Pep_next; + PyInterpreterState *Pep_interp; + + struct _frame *Pep_frame; + int Pep_recursion_depth; + char Pep_overflowed; + char Pep_recursion_critical; + + int Pep_tracing; + int Pep_use_tracing; + + Py_tracefunc Pep_c_profilefunc; + Py_tracefunc Pep_c_tracefunc; + PyObject *Pep_c_profileobj; + PyObject *Pep_c_traceobj; + + PyObject *Pep_curexc_type; + PyObject *Pep_curexc_value; + PyObject *Pep_curexc_traceback; + + PyObject *Pep_exc_type; + PyObject *Pep_exc_value; + PyObject *Pep_exc_traceback; + + PyObject *Pep_dict; + + int Pep_gilstate_counter; + + PyObject *Pep_async_exc; + long Pep_thread_id; + // These two variables only are of interest to us. + int trash_delete_nesting; + PyObject *trash_delete_later; + // Here we cut away the rest of the reduced structure. +} PyThreadState; +#else +#error *** Please check compatibility of the trashcan code, see Pep.h *** +#endif + +#endif // Py_LIMITED_API + +/***************************************************************************** + * + * RESOLVED: pythonrun.h + * + */ +#ifdef Py_LIMITED_API +LIBSHIBOKEN_API PyObject *PyRun_String(const char *, int, PyObject *, PyObject *); +#endif + +/***************************************************************************** + * + * RESOLVED: abstract.h + * + */ +#ifdef Py_LIMITED_API + +// This definition breaks the limited API a little, because it re-enables the +// buffer functions. +// But this is no problem as we check it's validity for every version. + +#define PYTHON_BUFFER_VERSION_COMPATIBLE (PY_VERSION_HEX >= 0x03030000 && \ + PY_VERSION_HEX < 0X0306FFFF) +#if !PYTHON_BUFFER_VERSION_COMPATIBLE +# error Please check the buffer compatibility for this python version! +#endif + +typedef struct { + getbufferproc bf_getbuffer; + releasebufferproc bf_releasebuffer; +} PyBufferProcs; + +typedef struct _Pepbuffertype { + PyVarObject ob_base; + void *skip[17]; + PyBufferProcs *tp_as_buffer; +} PepBufferType; + +#define PepType_AS_BUFFER(type) \ + reinterpret_cast<PepBufferType *>(type)->tp_as_buffer + +#define PyObject_CheckBuffer(obj) \ + ((PepType_AS_BUFFER(Py_TYPE(obj)) != NULL) && \ + (PepType_AS_BUFFER(Py_TYPE(obj))->bf_getbuffer != NULL)) + +LIBSHIBOKEN_API int PyObject_GetBuffer(PyObject *ob, Pep_buffer *view, int flags); +LIBSHIBOKEN_API void PyBuffer_Release(Pep_buffer *view); + +#else + +#define Pep_buffer Py_buffer + +#endif /* Py_LIMITED_API */ + +/***************************************************************************** + * + * RESOLVED: funcobject.h + * + */ +#ifdef Py_LIMITED_API +typedef struct _func PyFunctionObject; + +extern LIBSHIBOKEN_API PyTypeObject *PepFunction_TypePtr; +LIBSHIBOKEN_API PyObject *PepFunction_Get(PyObject *, const char *); + +#define PyFunction_Check(op) (Py_TYPE(op) == PepFunction_TypePtr) +#define PyFunction_GET_CODE(func) PyFunction_GetCode(func) + +#define PyFunction_GetCode(func) PepFunction_Get((PyObject *)func, "__code__") +#define PepFunction_GetName(func) PepFunction_Get((PyObject *)func, "__name__") +#else +#define PepFunction_GetName(func) (((PyFunctionObject *)func)->func_name) +#endif + +/***************************************************************************** + * + * RESOLVED: classobject.h + * + */ +#ifdef Py_LIMITED_API + +typedef struct _meth PyMethodObject; + +extern LIBSHIBOKEN_API PyTypeObject *PepMethod_TypePtr; + +LIBSHIBOKEN_API PyObject *PyMethod_New(PyObject *, PyObject *); +LIBSHIBOKEN_API PyObject *PyMethod_Function(PyObject *); +LIBSHIBOKEN_API PyObject *PyMethod_Self(PyObject *); + +#define PyMethod_Check(op) ((op)->ob_type == PepMethod_TypePtr) + +#define PyMethod_GET_SELF(op) PyMethod_Self(op) +#define PyMethod_GET_FUNCTION(op) PyMethod_Function(op) +#endif + +/***************************************************************************** + * + * RESOLVED: code.h + * + */ +#ifdef Py_LIMITED_API +/* Bytecode object */ + // we have to grab the code object from python +typedef struct _code PyCodeObject; + +LIBSHIBOKEN_API int PepCode_Get(PyCodeObject *co, const char *name); + +#define PepCode_GET_FLAGS(o) PepCode_Get(o, "co_flags") +#define PepCode_GET_ARGCOUNT(o) PepCode_Get(o, "co_argcount") + +/* Masks for co_flags above */ +#define CO_OPTIMIZED 0x0001 +#define CO_NEWLOCALS 0x0002 +#define CO_VARARGS 0x0004 +#define CO_VARKEYWORDS 0x0008 +#define CO_NESTED 0x0010 +#define CO_GENERATOR 0x0020 +#else +#define PepCode_GET_FLAGS(o) ((o)->co_flags) +#define PepCode_GET_ARGCOUNT(o) ((o)->co_argcount) +#endif + +/***************************************************************************** + * + * RESOLVED: datetime.h + * + */ +#ifdef Py_LIMITED_API + +LIBSHIBOKEN_API int PyDateTime_Get(PyObject *ob, const char *name); + +#define PyDateTime_GetYear(o) PyDateTime_Get(o, "year") +#define PyDateTime_GetMonth(o) PyDateTime_Get(o, "month") +#define PyDateTime_GetDay(o) PyDateTime_Get(o, "day") +#define PyDateTime_GetHour(o) PyDateTime_Get(o, "hour") +#define PyDateTime_GetMinute(o) PyDateTime_Get(o, "minute") +#define PyDateTime_GetSecond(o) PyDateTime_Get(o, "second") +#define PyDateTime_GetMicrosecond(o) PyDateTime_Get(o, "microsecond") +#define PyDateTime_GetFold(o) PyDateTime_Get(o, "fold") + +#define PyDateTime_GET_YEAR(o) PyDateTime_GetYear(o) +#define PyDateTime_GET_MONTH(o) PyDateTime_GetMonth(o) +#define PyDateTime_GET_DAY(o) PyDateTime_GetDay(o) + +#define PyDateTime_DATE_GET_HOUR(o) PyDateTime_GetHour(o) +#define PyDateTime_DATE_GET_MINUTE(o) PyDateTime_GetMinute(o) +#define PyDateTime_DATE_GET_SECOND(o) PyDateTime_GetSecond(o) +#define PyDateTime_DATE_GET_MICROSECOND(o) PyDateTime_GetMicrosecond(o) +#define PyDateTime_DATE_GET_FOLD(o) PyDateTime_GetFold(o) + +#define PyDateTime_TIME_GET_HOUR(o) PyDateTime_GetHour(o) +#define PyDateTime_TIME_GET_MINUTE(o) PyDateTime_GetMinute(o) +#define PyDateTime_TIME_GET_SECOND(o) PyDateTime_GetSecond(o) +#define PyDateTime_TIME_GET_MICROSECOND(o) PyDateTime_GetMicrosecond(o) +#define PyDateTime_TIME_GET_FOLD(o) PyDateTime_GetFold(o) + +/* Define structure slightly similar to C API. */ +typedef struct { + PyObject *module; + /* type objects */ + PyTypeObject *DateType; + PyTypeObject *DateTimeType; + PyTypeObject *TimeType; + PyTypeObject *DeltaType; + PyTypeObject *TZInfoType; +} datetime_struc; + +LIBSHIBOKEN_API datetime_struc *init_DateTime(void); + +#define PyDateTime_IMPORT PyDateTimeAPI = init_DateTime() + +extern LIBSHIBOKEN_API datetime_struc *PyDateTimeAPI; + +#define PyDate_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateType) +#define PyDateTime_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateTimeType) +#define PyTime_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->TimeType) + +LIBSHIBOKEN_API PyObject *PyDate_FromDate(int year, int month, int day); +LIBSHIBOKEN_API PyObject *PyDateTime_FromDateAndTime( + int year, int month, int day, int hour, int min, int sec, int usec); +LIBSHIBOKEN_API PyObject *PyTime_FromTime( + int hour, int minute, int second, int usecond); + +#endif /* Py_LIMITED_API */ + +/***************************************************************************** + * + * Extra support for signature.cpp + * + */ + +#ifdef Py_LIMITED_API +extern LIBSHIBOKEN_API PyTypeObject *PepStaticMethod_TypePtr; +#else +#define PepStaticMethod_TypePtr &PyStaticMethod_Type +#endif + +/***************************************************************************** + * + * Module Initialization + * + */ + +LIBSHIBOKEN_API void Pep_Init(void); + +} // extern "C" + +#endif // PEP384IMPL_H diff --git a/sources/shiboken2/libshiboken/python25compat.h b/sources/shiboken2/libshiboken/python25compat.h index 42f78481d..fc25aa3e5 100644 --- a/sources/shiboken2/libshiboken/python25compat.h +++ b/sources/shiboken2/libshiboken/python25compat.h @@ -39,7 +39,7 @@ #ifndef PYTHON25COMPAT_H #define PYTHON25COMPAT_H -#include <Python.h> +#include "sbkpython.h" #include <cstring> /* diff --git a/sources/shiboken2/libshiboken/qapp_macro.cpp b/sources/shiboken2/libshiboken/qapp_macro.cpp index e6a877a32..f69d0f937 100644 --- a/sources/shiboken2/libshiboken/qapp_macro.cpp +++ b/sources/shiboken2/libshiboken/qapp_macro.cpp @@ -119,8 +119,8 @@ MakeSingletonQAppWrapper(PyTypeObject *type) if (type == NULL) type = Py_NONE_TYPE; if (!(type == Py_NONE_TYPE || Py_TYPE(qApp_content) == Py_NONE_TYPE)) { - const char *res_name = strrchr(Py_TYPE(qApp_content)->tp_name, '.')+1; - const char *type_name = strrchr(type->tp_name, '.')+1; + const char *res_name = PepType_GetNameStr(Py_TYPE(qApp_content)); + const char *type_name = PepType_GetNameStr(type); PyErr_Format(PyExc_RuntimeError, "Please destroy the %s singleton before" " creating a new %s instance.", res_name, type_name); return NULL; diff --git a/sources/shiboken2/libshiboken/qt_attribution.json b/sources/shiboken2/libshiboken/qt_attribution.json new file mode 100644 index 000000000..a90cc604b --- /dev/null +++ b/sources/shiboken2/libshiboken/qt_attribution.json @@ -0,0 +1,12 @@ +{ + "Id": "python", + "Name": "Python", + "QDocModule": "QtForPython", + "QtUsage": "Used for Qt for Python in the signature extension.", + "Description": "Qt for Python is an add-on for Python. The libshiboken packages of PySide uses certain parts of the source files (typespec.cpp, typespec.h, bufferprocs27.cpp, bufferprocs27.h). See the folder sources/shiboken2/libshiboken .", + "Homepage": "http://www.python.org/", + "Version": "3.6.5", + "License": "PSF LICENSE AGREEMENT FOR PYTHON 3.6.5", + "LicenseFile": "bufferprocs27.h", + "Copyright": "© Copyright 2001-2018, Python Software Foundation." +} diff --git a/sources/shiboken2/libshiboken/sbkarrayconverter.cpp b/sources/shiboken2/libshiboken/sbkarrayconverter.cpp index 1646c9117..58e0b18a8 100644 --- a/sources/shiboken2/libshiboken/sbkarrayconverter.cpp +++ b/sources/shiboken2/libshiboken/sbkarrayconverter.cpp @@ -162,7 +162,7 @@ static void sequenceToCppIntArray(PyObject *pyIn, void *cppOut) { ArrayHandle<int> *handle = reinterpret_cast<ArrayHandle<int> *>(cppOut); handle->allocate(PySequence_Size(pyIn)); - convertPySequence(pyIn, _PyLong_AsInt, handle->data()); + convertPySequence(pyIn, _PepLong_AsInt, handle->data()); } static PythonToCppFunc sequenceToCppIntArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */) diff --git a/sources/shiboken2/libshiboken/sbkconverter.cpp b/sources/shiboken2/libshiboken/sbkconverter.cpp index 64884d601..d4d3ac899 100644 --- a/sources/shiboken2/libshiboken/sbkconverter.cpp +++ b/sources/shiboken2/libshiboken/sbkconverter.cpp @@ -112,6 +112,8 @@ SbkConverter *createConverterObject(PyTypeObject *type, { SbkConverter* converter = new SbkConverter; converter->pythonType = type; + // PYSIDE-595: All types are heaptypes now, so provide reference. + Py_XINCREF(type); converter->pointerToPython = pointerToPythonFunc; converter->copyToPython = copyToPythonFunc; @@ -133,7 +135,7 @@ SbkConverter* createConverter(SbkObjectType* type, createConverterObject(reinterpret_cast<PyTypeObject *>(type), toCppPointerConvFunc, toCppPointerCheckFunc, pointerToPythonFunc, copyToPythonFunc); - type->d->converter = converter; + PepType_SOTP(type)->converter = converter; return converter; } @@ -172,12 +174,12 @@ void addPythonToCppValueConversion(SbkObjectType* type, PythonToCppFunc pythonToCppFunc, IsConvertibleToCppFunc isConvertibleToCppFunc) { - addPythonToCppValueConversion(type->d->converter, pythonToCppFunc, isConvertibleToCppFunc); + addPythonToCppValueConversion(PepType_SOTP(type)->converter, pythonToCppFunc, isConvertibleToCppFunc); } -PyObject* pointerToPython(const SbkObjectType *type, const void *cppIn) +PyObject* pointerToPython(SbkObjectType *type, const void *cppIn) { - return pointerToPython(type->d->converter, cppIn); + return pointerToPython(PepType_SOTP(type)->converter, cppIn); } PyObject* pointerToPython(const SbkConverter *converter, const void *cppIn) @@ -187,15 +189,15 @@ PyObject* pointerToPython(const SbkConverter *converter, const void *cppIn) Py_RETURN_NONE; if (!converter->pointerToPython) { warning(PyExc_RuntimeWarning, 0, "pointerToPython(): SbkConverter::pointerToPython is null for \"%s\".", - converter->pythonType->tp_name); + PepType(converter->pythonType)->tp_name); Py_RETURN_NONE; } return converter->pointerToPython(cppIn); } -PyObject* referenceToPython(const SbkObjectType *type, const void *cppIn) +PyObject* referenceToPython(SbkObjectType *type, const void *cppIn) { - return referenceToPython(type->d->converter, cppIn); + return referenceToPython(PepType_SOTP(type)->converter, cppIn); } PyObject* referenceToPython(const SbkConverter *converter, const void *cppIn) @@ -209,7 +211,7 @@ PyObject* referenceToPython(const SbkConverter *converter, const void *cppIn) } if (!converter->pointerToPython) { warning(PyExc_RuntimeWarning, 0, "referenceToPython(): SbkConverter::pointerToPython is null for \"%s\".", - converter->pythonType->tp_name); + PepType(converter->pythonType)->tp_name); Py_RETURN_NONE; } return converter->pointerToPython(cppIn); @@ -221,24 +223,24 @@ static inline PyObject* CopyCppToPython(const SbkConverter *converter, const voi Py_RETURN_NONE; if (!converter->copyToPython) { warning(PyExc_RuntimeWarning, 0, "CopyCppToPython(): SbkConverter::copyToPython is null for \"%s\".", - converter->pythonType->tp_name); + PepType(converter->pythonType)->tp_name); Py_RETURN_NONE; } return converter->copyToPython(cppIn); } -PyObject* copyToPython(const SbkObjectType *type, const void *cppIn) +PyObject* copyToPython(SbkObjectType *type, const void *cppIn) { - return CopyCppToPython(type->d->converter, cppIn); + return CopyCppToPython(PepType_SOTP(type)->converter, cppIn); } PyObject* copyToPython(const SbkConverter *converter, const void *cppIn) { return CopyCppToPython(converter, cppIn); } -PythonToCppFunc isPythonToCppPointerConvertible(const SbkObjectType *type, PyObject *pyIn) +PythonToCppFunc isPythonToCppPointerConvertible(SbkObjectType *type, PyObject *pyIn) { assert(pyIn); - return type->d->converter->toCppPointerConversion.first(pyIn); + return PepType_SOTP(type)->converter->toCppPointerConversion.first(pyIn); } static inline PythonToCppFunc IsPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn) @@ -252,9 +254,9 @@ static inline PythonToCppFunc IsPythonToCppConvertible(const SbkConverter *conve } return 0; } -PythonToCppFunc isPythonToCppValueConvertible(const SbkObjectType *type, PyObject *pyIn) +PythonToCppFunc isPythonToCppValueConvertible(SbkObjectType *type, PyObject *pyIn) { - return IsPythonToCppConvertible(type->d->converter, pyIn); + return IsPythonToCppConvertible(PepType_SOTP(type)->converter, pyIn); } PythonToCppFunc isPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn) { @@ -272,7 +274,7 @@ PythonToCppFunc isPythonToCppConvertible(const SbkArrayConverter *converter, return nullptr; } -PythonToCppFunc isPythonToCppReferenceConvertible(const SbkObjectType *type, PyObject *pyIn) +PythonToCppFunc isPythonToCppReferenceConvertible(SbkObjectType *type, PyObject *pyIn) { if (pyIn != Py_None) { PythonToCppFunc toCpp = isPythonToCppPointerConvertible(type, pyIn); @@ -329,10 +331,10 @@ static void _pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void toCpp(pyIn, cppOut); } -void pythonToCppCopy(const SbkObjectType *type, PyObject *pyIn, void *cppOut) +void pythonToCppCopy(SbkObjectType *type, PyObject *pyIn, void *cppOut) { assert(type); - _pythonToCppCopy(type->d->converter, pyIn, cppOut); + _pythonToCppCopy(PepType_SOTP(type)->converter, pyIn, cppOut); } void pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut) @@ -340,16 +342,16 @@ void pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut _pythonToCppCopy(converter, pyIn, cppOut); } -bool isImplicitConversion(const SbkObjectType *type, PythonToCppFunc toCppFunc) +bool isImplicitConversion(SbkObjectType *type, PythonToCppFunc toCppFunc) { // This is the Object Type or Value Type conversion that only // retrieves the C++ pointer held in the Python wrapper. - if (toCppFunc == type->d->converter->toCppPointerConversion.second) + if (toCppFunc == PepType_SOTP(type)->converter->toCppPointerConversion.second) return false; // Object Types doesn't have any kind of value conversion, // only C++ pointer retrieval. - if (type->d->converter->toCppConversions.empty()) + if (PepType_SOTP(type)->converter->toCppConversions.empty()) return false; // The first conversion of the non-pointer conversion list is @@ -359,7 +361,7 @@ bool isImplicitConversion(const SbkObjectType *type, PythonToCppFunc toCppFunc) // Note that we don't check if the Python to C++ conversion is in // the list of the type's conversions, for it is expected that the // caller knows what he's doing. - ToCppConversionList::iterator conv = type->d->converter->toCppConversions.begin(); + ToCppConversionList::iterator conv = PepType_SOTP(type)->converter->toCppConversions.begin(); return toCppFunc != (*conv).second; } @@ -411,10 +413,10 @@ bool convertibleSequenceTypes(const SbkConverter *converter, PyObject *pyIn) } return true; } -bool convertibleSequenceTypes(const SbkObjectType *type, PyObject *pyIn) +bool convertibleSequenceTypes(SbkObjectType *type, PyObject *pyIn) { assert(type); - return convertibleSequenceTypes(type->d->converter, pyIn); + return convertibleSequenceTypes(PepType_SOTP(type)->converter, pyIn); } bool checkPairTypes(PyTypeObject* firstType, PyTypeObject* secondType, PyObject* pyIn) diff --git a/sources/shiboken2/libshiboken/sbkconverter.h b/sources/shiboken2/libshiboken/sbkconverter.h index da71db5b5..0effebf57 100644 --- a/sources/shiboken2/libshiboken/sbkconverter.h +++ b/sources/shiboken2/libshiboken/sbkconverter.h @@ -191,7 +191,7 @@ LIBSHIBOKEN_API void addPythonToCppValueConversion(SbkObjectType* type, * TYPE* var; * PyObject* pyVar = pointerToPython(SBKTYPE, &var); */ -LIBSHIBOKEN_API PyObject* pointerToPython(const SbkObjectType *type, const void *cppIn); +LIBSHIBOKEN_API PyObject* pointerToPython(SbkObjectType *type, const void *cppIn); LIBSHIBOKEN_API PyObject* pointerToPython(const SbkConverter *converter, const void *cppIn); /** @@ -203,7 +203,7 @@ LIBSHIBOKEN_API PyObject* pointerToPython(const SbkConverter *converter, const v * TYPE& var = SOMETHING; * PyObject* pyVar = referenceToPython(SBKTYPE, &var); */ -LIBSHIBOKEN_API PyObject* referenceToPython(const SbkObjectType *type, const void *cppIn); +LIBSHIBOKEN_API PyObject* referenceToPython(SbkObjectType *type, const void *cppIn); LIBSHIBOKEN_API PyObject* referenceToPython(const SbkConverter *converter, const void *cppIn); /** @@ -213,7 +213,7 @@ LIBSHIBOKEN_API PyObject* referenceToPython(const SbkConverter *converter, const * TYPE var; * PyObject* pyVar = copyToPython(SBKTYPE, &var); */ -LIBSHIBOKEN_API PyObject* copyToPython(const SbkObjectType *type, const void *cppIn); +LIBSHIBOKEN_API PyObject* copyToPython(SbkObjectType *type, const void *cppIn); LIBSHIBOKEN_API PyObject* copyToPython(const SbkConverter *converter, const void *cppIn); // Python -> C++ --------------------------------------------------------------------------- @@ -222,7 +222,7 @@ LIBSHIBOKEN_API PyObject* copyToPython(const SbkConverter *converter, const void * Returns a Python to C++ conversion function if the Python object is convertible to a C++ pointer. * It returns NULL if the Python object is not convertible to \p type. */ -LIBSHIBOKEN_API PythonToCppFunc isPythonToCppPointerConvertible(const SbkObjectType *type, PyObject *pyIn); +LIBSHIBOKEN_API PythonToCppFunc isPythonToCppPointerConvertible(SbkObjectType *type, PyObject *pyIn); /** * Returns a Python to C++ conversion function if the Python object is convertible to a C++ value. @@ -230,7 +230,7 @@ LIBSHIBOKEN_API PythonToCppFunc isPythonToCppPointerConvertible(const SbkObjectT * convert the object to the expected \p type. * It returns NULL if the Python object is not convertible to \p type. */ -LIBSHIBOKEN_API PythonToCppFunc isPythonToCppValueConvertible(const SbkObjectType *type, PyObject *pyIn); +LIBSHIBOKEN_API PythonToCppFunc isPythonToCppValueConvertible(SbkObjectType *type, PyObject *pyIn); /** * Returns a Python to C++ conversion function if the Python object is convertible to a C++ reference. @@ -238,7 +238,7 @@ LIBSHIBOKEN_API PythonToCppFunc isPythonToCppValueConvertible(const SbkObjectTyp * or a new C++ value if it must be a implicit conversion. * It returns NULL if the Python object is not convertible to \p type. */ -LIBSHIBOKEN_API PythonToCppFunc isPythonToCppReferenceConvertible(const SbkObjectType *type, PyObject *pyIn); +LIBSHIBOKEN_API PythonToCppFunc isPythonToCppReferenceConvertible(SbkObjectType *type, PyObject *pyIn); /// This is the same as isPythonToCppValueConvertible function. LIBSHIBOKEN_API PythonToCppFunc isPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn); @@ -257,7 +257,7 @@ LIBSHIBOKEN_API void pythonToCppPointer(SbkObjectType* type, PyObject* pyIn, voi LIBSHIBOKEN_API void pythonToCppPointer(const SbkConverter *converter, PyObject *pyIn, void *cppOut); /// Converts a Python object \p pyIn to C++, and copies the result in the C++ variable passed in \p cppOut. -LIBSHIBOKEN_API void pythonToCppCopy(const SbkObjectType *type, PyObject *pyIn, void *cppOut); +LIBSHIBOKEN_API void pythonToCppCopy(SbkObjectType *type, PyObject *pyIn, void *cppOut); LIBSHIBOKEN_API void pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut); /** @@ -271,7 +271,7 @@ LIBSHIBOKEN_API void nonePythonToCppNullPtr(PyObject*, void* cppOut); * It is used when C++ expects a reference argument, so it may be the same object received * from Python, or another created through implicit conversion. */ -LIBSHIBOKEN_API bool isImplicitConversion(const SbkObjectType *type, PythonToCppFunc toCpp); +LIBSHIBOKEN_API bool isImplicitConversion(SbkObjectType *type, PythonToCppFunc toCpp); /// Registers a converter with a type name that may be used to retrieve the converter. LIBSHIBOKEN_API void registerConverterName(SbkConverter* converter, const char* typeName); @@ -289,7 +289,7 @@ LIBSHIBOKEN_API bool checkSequenceTypes(PyTypeObject* type, PyObject* pyIn); LIBSHIBOKEN_API bool convertibleSequenceTypes(const SbkConverter *converter, PyObject *pyIn); /// Returns true if a Python sequence is comprised of objects of a type convertible to \p type. -LIBSHIBOKEN_API bool convertibleSequenceTypes(const SbkObjectType *type, PyObject *pyIn); +LIBSHIBOKEN_API bool convertibleSequenceTypes(SbkObjectType *type, PyObject *pyIn); /// Returns true if a Python sequence can be converted to a C++ pair. LIBSHIBOKEN_API bool checkPairTypes(PyTypeObject* firstType, PyTypeObject* secondType, PyObject* pyIn); @@ -394,8 +394,9 @@ template<> inline PyTypeObject* SbkType<unsigned short>() { return &PyInt_Type; #define PyObject_Check(X) true #define SbkChar_Check(X) (SbkNumber_Check(X) || Shiboken::String::checkChar(X)) -struct _SbkGenericType { PyHeapTypeObject super; SbkConverter** converter; }; -#define SBK_CONVERTER(pyType) (*reinterpret_cast<_SbkGenericType*>(pyType)->converter) +struct _SbkGenericTypePrivate { + SbkConverter** converter; +}; #endif // SBK_CONVERTER_H diff --git a/sources/shiboken2/libshiboken/sbkenum.cpp b/sources/shiboken2/libshiboken/sbkenum.cpp index 37649f6fa..5f753293c 100644 --- a/sources/shiboken2/libshiboken/sbkenum.cpp +++ b/sources/shiboken2/libshiboken/sbkenum.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt for Python. @@ -54,14 +54,18 @@ extern "C" { -struct SbkEnumType +struct SbkEnumTypePrivate { - PyHeapTypeObject super; SbkConverter** converterPtr; SbkConverter* converter; const char* cppName; }; +struct SbkEnumType +{ + PepTypeObject type; +}; + struct SbkEnumObject { PyObject_HEAD @@ -73,21 +77,9 @@ static PyObject* SbkEnumObject_repr(PyObject* self) { const SbkEnumObject *enumObj = reinterpret_cast<SbkEnumObject *>(self); if (enumObj->ob_name) - return Shiboken::String::fromFormat("%s.%s", self->ob_type->tp_name, PyBytes_AS_STRING(enumObj->ob_name)); - else - return Shiboken::String::fromFormat("%s(%ld)", self->ob_type->tp_name, enumObj->ob_value); -} - -static int SbkEnumObject_print(PyObject* self, FILE* fp, int) -{ - Py_BEGIN_ALLOW_THREADS - const SbkEnumObject *enumObj = reinterpret_cast<SbkEnumObject *>(self); - if (enumObj->ob_name) - fprintf(fp, "%s.%s", self->ob_type->tp_name, PyBytes_AS_STRING(enumObj->ob_name)); + return Shiboken::String::fromFormat("%s.%s", PepType((Py_TYPE(self)))->tp_name, PyBytes_AS_STRING(enumObj->ob_name)); else - fprintf(fp, "%s(%ld)", self->ob_type->tp_name, enumObj->ob_value); - Py_END_ALLOW_THREADS - return 0; + return Shiboken::String::fromFormat("%s(%ld)", PepType((Py_TYPE(self)))->tp_name, enumObj->ob_value); } static PyObject* SbkEnumObject_name(PyObject* self, void*) @@ -266,114 +258,54 @@ static PyGetSetDef SbkEnumGetSetList[] = { {0, 0, 0, 0, 0} // Sentinel }; -static PyNumberMethods enum_as_number = { - /* nb_add */ enum_add, - /* nb_subtract */ enum_subtract, - /* nb_multiply */ enum_multiply, -#ifndef IS_PY3K - /* nb_divide */ enum_divide, -#endif - /* nb_remainder */ 0, - /* nb_divmod */ 0, - /* nb_power */ 0, - /* nb_negative */ 0, - /* nb_positive */ enum_int, - /* nb_absolute */ 0, - /* nb_bool/nb_nonzero */ enum_bool, - /* nb_invert */ 0, - /* nb_lshift */ 0, - /* nb_rshift */ 0, - /* nb_and */ enum_and, - /* nb_xor */ enum_xor, - /* nb_or */ enum_or, +static void SbkEnumTypeDealloc(PyObject* pyObj); +static PyObject* SbkEnumTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds); + +static PyType_Slot SbkEnumType_Type_slots[] = { + {Py_tp_dealloc, (void *)SbkEnumTypeDealloc}, + {Py_nb_add, (void *)enum_add}, + {Py_nb_subtract, (void *)enum_subtract}, + {Py_nb_multiply, (void *)enum_multiply}, #ifndef IS_PY3K - /* nb_coerce */ 0, + {Py_nb_divide, (void *)enum_divide}, #endif - /* nb_int */ enum_int, + {Py_nb_positive, (void *)enum_int}, #ifdef IS_PY3K - /* nb_reserved */ 0, - /* nb_float */ 0, + {Py_nb_bool, (void *)enum_bool}, #else - /* nb_long */ enum_int, - /* nb_float */ 0, - /* nb_oct */ 0, - /* nb_hex */ 0, -#endif - - /* nb_inplace_add */ 0, - /* nb_inplace_subtract */ 0, - /* nb_inplace_multiply */ 0, -#ifndef IS_PY3K - /* nb_inplace_div */ 0, + {Py_nb_nonzero, (void *)enum_bool}, + {Py_nb_long, (void *)enum_int}, #endif - /* nb_inplace_remainder */ 0, - /* nb_inplace_power */ 0, - /* nb_inplace_lshift */ 0, - /* nb_inplace_rshift */ 0, - /* nb_inplace_and */ 0, - /* nb_inplace_xor */ 0, - /* nb_inplace_or */ 0, - - /* nb_floor_divide */ 0, - /* nb_true_divide */ 0, - /* nb_inplace_floor_divide */ 0, - /* nb_inplace_true_divide */ 0, - - /* nb_index */ enum_int + {Py_nb_and, (void *)enum_and}, + {Py_nb_xor, (void *)enum_xor}, + {Py_nb_or, (void *)enum_or}, + {Py_nb_int, (void *)enum_int}, + {Py_nb_index, (void *)enum_int}, + {Py_tp_base, (void *)&PyType_Type}, + {Py_tp_alloc, (void *)PyType_GenericAlloc}, + {Py_tp_new, (void *)SbkEnumTypeTpNew}, + {Py_tp_free, (void *)PyObject_GC_Del}, + {0, 0} +}; +static PyType_Spec SbkEnumType_Type_spec = { + "Shiboken.EnumType", + 0, // filled in later + sizeof(PyMemberDef), + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, + SbkEnumType_Type_slots, }; -static void SbkEnumTypeDealloc(PyObject* pyObj); -static PyObject* SbkEnumTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds); -PyTypeObject SbkEnumType_Type = { - PyVarObject_HEAD_INIT(0, 0) - /*tp_name*/ "Shiboken.EnumType", - /*tp_basicsize*/ sizeof(SbkEnumType), - /*tp_itemsize*/ 0, - /*tp_dealloc*/ SbkEnumTypeDealloc, - /*tp_print*/ 0, - /*tp_getattr*/ 0, - /*tp_setattr*/ 0, - /*tp_compare*/ 0, - /*tp_repr*/ 0, - /*tp_as_number*/ &enum_as_number, - /*tp_as_sequence*/ 0, - /*tp_as_mapping*/ 0, - /*tp_hash*/ 0, - /*tp_call*/ 0, - /*tp_str*/ 0, - /*tp_getattro*/ 0, - /*tp_setattro*/ 0, - /*tp_as_buffer*/ 0, - /*tp_flags*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, - /*tp_doc*/ 0, - /*tp_traverse*/ 0, - /*tp_clear*/ 0, - /*tp_richcompare*/ 0, - /*tp_weaklistoffset*/ 0, - /*tp_iter*/ 0, - /*tp_iternext*/ 0, - /*tp_methods*/ 0, - /*tp_members*/ 0, - /*tp_getset*/ 0, - /*tp_base*/ &PyType_Type, - /*tp_dict*/ 0, - /*tp_descr_get*/ 0, - /*tp_descr_set*/ 0, - /*tp_dictoffset*/ 0, - /*tp_init*/ 0, - /*tp_alloc*/ PyType_GenericAlloc, - /*tp_new*/ SbkEnumTypeTpNew, - /*tp_free*/ PyObject_GC_Del, - /*tp_is_gc*/ 0, - /*tp_bases*/ 0, - /*tp_mro*/ 0, - /*tp_cache*/ 0, - /*tp_subclasses*/ 0, - /*tp_weaklist*/ 0, - /*tp_del*/ 0, - /*tp_version_tag*/ 0 -}; +PyTypeObject *SbkEnumType_TypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) { + SbkEnumType_Type_spec.basicsize = + PepHeapType_SIZE + sizeof(SbkEnumTypePrivate); + type = (PyTypeObject *)PyType_FromSpec(&SbkEnumType_Type_spec); + } + return type; +} void SbkEnumTypeDealloc(PyObject* pyObj) { @@ -381,15 +313,16 @@ void SbkEnumTypeDealloc(PyObject* pyObj) PyObject_GC_UnTrack(pyObj); Py_TRASHCAN_SAFE_BEGIN(pyObj); - if (sbkType->converter) { - Shiboken::Conversions::deleteConverter(sbkType->converter); + if (PepType_SETP(sbkType)->converter) { + Shiboken::Conversions::deleteConverter(PepType_SETP(sbkType)->converter); } Py_TRASHCAN_SAFE_END(pyObj); } PyObject* SbkEnumTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds) { - SbkEnumType* newType = reinterpret_cast<SbkEnumType*>(PyType_Type.tp_new(metatype, args, kwds)); + newfunc type_new = reinterpret_cast<newfunc>(PyType_GetSlot(&PyType_Type, Py_tp_new)); + SbkEnumType *newType = reinterpret_cast<SbkEnumType*>(type_new(metatype, args, kwds)); if (!newType) return 0; return reinterpret_cast<PyObject*>(newType); @@ -417,14 +350,14 @@ namespace Enum { bool check(PyObject* pyObj) { - return Py_TYPE(pyObj->ob_type) == &SbkEnumType_Type; + return Py_TYPE(Py_TYPE(pyObj)) == SbkEnumType_TypeF(); } PyObject* getEnumItemFromValue(PyTypeObject* enumType, long itemValue) { PyObject *key, *value; Py_ssize_t pos = 0; - PyObject* values = PyDict_GetItemString(enumType->tp_dict, const_cast<char*>("values")); + PyObject *values = PyDict_GetItemString(PepType(enumType)->tp_dict, const_cast<char*>("values")); while (PyDict_Next(values, &pos, &key, &value)) { SbkEnumObject *obj = reinterpret_cast<SbkEnumObject *>(value); @@ -438,9 +371,7 @@ PyObject* getEnumItemFromValue(PyTypeObject* enumType, long itemValue) static PyTypeObject* createEnum(const char* fullName, const char* cppName, const char* shortName, PyTypeObject* flagsType) { - PyTypeObject* enumType = newTypeWithName(fullName, cppName); - if (flagsType) - enumType->tp_as_number = flagsType->tp_as_number; + PyTypeObject* enumType = newTypeWithName(fullName, cppName, flagsType); if (PyType_Ready(enumType) < 0) return 0; return enumType; @@ -451,7 +382,8 @@ PyTypeObject* createGlobalEnum(PyObject* module, const char* name, const char* f PyTypeObject* enumType = createEnum(fullName, cppName, name, flagsType); if (enumType && PyModule_AddObject(module, name, reinterpret_cast<PyObject *>(enumType)) < 0) return 0; - if (flagsType && PyModule_AddObject(module, flagsType->tp_name, reinterpret_cast<PyObject *>(flagsType)) < 0) + if (flagsType && PyModule_AddObject(module, PepType_GetNameStr(flagsType), + reinterpret_cast<PyObject *>(flagsType)) < 0) return 0; return enumType; } @@ -459,17 +391,20 @@ PyTypeObject* createGlobalEnum(PyObject* module, const char* name, const char* f PyTypeObject* createScopedEnum(SbkObjectType* scope, const char* name, const char* fullName, const char* cppName, PyTypeObject* flagsType) { PyTypeObject* enumType = createEnum(fullName, cppName, name, flagsType); - if (enumType && PyDict_SetItemString(scope->super.ht_type.tp_dict, name, reinterpret_cast<PyObject *>(enumType)) < 0) - return 0; - if (flagsType && PyDict_SetItemString(scope->super.ht_type.tp_dict, flagsType->tp_name, reinterpret_cast<PyObject *>(flagsType)) < 0) - return 0; + if (enumType && PyDict_SetItemString(PepType(scope)->tp_dict, name, + reinterpret_cast<PyObject *>(enumType)) < 0) + return nullptr; + if (flagsType && PyDict_SetItemString(PepType(scope)->tp_dict, + PepType_GetNameStr(flagsType), + reinterpret_cast<PyObject *>(flagsType)) < 0) + return nullptr; return enumType; } static PyObject* createEnumItem(PyTypeObject* enumType, const char* itemName, long itemValue) { PyObject* enumItem = newItem(enumType, itemValue, itemName); - if (PyDict_SetItemString(enumType->tp_dict, itemName, enumItem) < 0) + if (PyDict_SetItemString(PepType(enumType)->tp_dict, itemName, enumItem) < 0) return 0; Py_DECREF(enumItem); return enumItem; @@ -496,7 +431,7 @@ bool createScopedEnumItem(PyTypeObject *enumType, PyTypeObject *scope, const char *itemName, long itemValue) { if (PyObject *enumItem = createEnumItem(enumType, itemName, itemValue)) { - if (PyDict_SetItemString(scope->tp_dict, itemName, enumItem) < 0) + if (PyDict_SetItemString(PepType(scope)->tp_dict, itemName, enumItem) < 0) return false; Py_DECREF(enumItem); return true; @@ -506,15 +441,17 @@ bool createScopedEnumItem(PyTypeObject *enumType, PyTypeObject *scope, bool createScopedEnumItem(PyTypeObject* enumType, SbkObjectType* scope, const char* itemName, long itemValue) { - return createScopedEnumItem(enumType, &scope->super.ht_type, itemName, itemValue); + return createScopedEnumItem(enumType, reinterpret_cast<PyTypeObject *>(scope), itemName, itemValue); } -PyObject* newItem(PyTypeObject* enumType, long itemValue, const char* itemName) +PyObject * +newItem(PyTypeObject *enumType, long itemValue, const char *itemName) { bool newValue = true; SbkEnumObject* enumObj; if (!itemName) { - enumObj = reinterpret_cast<SbkEnumObject*>(getEnumItemFromValue(enumType, itemValue)); + enumObj = reinterpret_cast<SbkEnumObject*>( + getEnumItemFromValue(enumType, itemValue)); if (enumObj) return reinterpret_cast<PyObject*>(enumObj); @@ -529,10 +466,10 @@ PyObject* newItem(PyTypeObject* enumType, long itemValue, const char* itemName) enumObj->ob_value = itemValue; if (newValue) { - PyObject* values = PyDict_GetItemString(enumType->tp_dict, const_cast<char*>("values")); + PyObject* values = PyDict_GetItemString(PepType(enumType)->tp_dict, const_cast<char*>("values")); if (!values) { values = PyDict_New(); - PyDict_SetItemString(enumType->tp_dict, const_cast<char*>("values"), values); + PyDict_SetItemString(PepType(enumType)->tp_dict, const_cast<char*>("values"), values); Py_DECREF(values); // ^ values still alive, because setitemstring incref it } PyDict_SetItemString(values, itemName, reinterpret_cast<PyObject*>(enumObj)); @@ -541,39 +478,140 @@ PyObject* newItem(PyTypeObject* enumType, long itemValue, const char* itemName) return reinterpret_cast<PyObject*>(enumObj); } -PyTypeObject* newType(const char* name) -{ - return newTypeWithName(name, ""); -} +static PyType_Slot SbkNewType_slots[] = { + {Py_tp_repr, (void *)SbkEnumObject_repr}, + {Py_tp_str, (void *)SbkEnumObject_repr}, + {Py_tp_getset, (void *)SbkEnumGetSetList}, + {Py_tp_new, (void *)SbkEnum_tp_new}, + {Py_nb_add, (void *)enum_add}, + {Py_nb_subtract, (void *)enum_subtract}, + {Py_nb_multiply, (void *)enum_multiply}, +#ifndef IS_PY3K + {Py_nb_divide, (void *)enum_divide}, +#endif + {Py_nb_positive, (void *)enum_int}, +#ifdef IS_PY3K + {Py_nb_bool, (void *)enum_bool}, +#else + {Py_nb_nonzero, (void *)enum_bool}, + {Py_nb_long, (void *)enum_int}, +#endif + {Py_nb_and, (void *)enum_and}, + {Py_nb_xor, (void *)enum_xor}, + {Py_nb_or, (void *)enum_or}, + {Py_nb_int, (void *)enum_int}, + {Py_nb_index, (void *)enum_int}, + {Py_tp_richcompare, (void *)enum_richcompare}, + {Py_tp_hash, (void *)enum_hash}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} +}; +static PyType_Spec SbkNewType_spec = { + "missing Enum name", // to be inserted later + sizeof(SbkEnumObject), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES, + SbkNewType_slots, +}; -PyTypeObject* newTypeWithName(const char* name, const char* cppName) +static void +copyNumberMethods(PyTypeObject *flagsType, + PyType_Slot number_slots[], + int *pidx) { - PyTypeObject* type = reinterpret_cast<PyTypeObject*>(new SbkEnumType); - ::memset(type, 0, sizeof(SbkEnumType)); - Py_TYPE(type) = &SbkEnumType_Type; - type->tp_basicsize = sizeof(SbkEnumObject); - type->tp_print = &SbkEnumObject_print; - type->tp_repr = &SbkEnumObject_repr; - type->tp_str = &SbkEnumObject_repr; - type->tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES; - type->tp_name = name; - type->tp_getset = SbkEnumGetSetList; - type->tp_new = SbkEnum_tp_new; - type->tp_as_number = &enum_as_number; - type->tp_richcompare = &enum_richcompare; - type->tp_hash = &enum_hash; + int idx = *pidx; +#ifdef IS_PY3K +# define SLOT slot +#else +# define SLOT slot_ +#endif +#define PUT_SLOT(name) \ + number_slots[idx].SLOT = (name); \ + number_slots[idx].pfunc = PyType_GetSlot(flagsType, (name)); \ + ++idx; + + PUT_SLOT(Py_nb_absolute); + PUT_SLOT(Py_nb_add); + PUT_SLOT(Py_nb_and); +#ifdef IS_PY3K + PUT_SLOT(Py_nb_bool); +#else + PUT_SLOT(Py_nb_nonzero); +#endif + PUT_SLOT(Py_nb_divmod); + PUT_SLOT(Py_nb_float); + PUT_SLOT(Py_nb_floor_divide); + PUT_SLOT(Py_nb_index); + PUT_SLOT(Py_nb_inplace_add); + PUT_SLOT(Py_nb_inplace_and); + PUT_SLOT(Py_nb_inplace_floor_divide); + PUT_SLOT(Py_nb_inplace_lshift); + PUT_SLOT(Py_nb_inplace_multiply); + PUT_SLOT(Py_nb_inplace_or); + PUT_SLOT(Py_nb_inplace_power); + PUT_SLOT(Py_nb_inplace_remainder); + PUT_SLOT(Py_nb_inplace_rshift); + PUT_SLOT(Py_nb_inplace_subtract); + PUT_SLOT(Py_nb_inplace_true_divide); + PUT_SLOT(Py_nb_inplace_xor); + PUT_SLOT(Py_nb_int); + PUT_SLOT(Py_nb_invert); + PUT_SLOT(Py_nb_lshift); + PUT_SLOT(Py_nb_multiply); + PUT_SLOT(Py_nb_negative); + PUT_SLOT(Py_nb_or); + PUT_SLOT(Py_nb_positive); + PUT_SLOT(Py_nb_power); + PUT_SLOT(Py_nb_remainder); + PUT_SLOT(Py_nb_rshift); + PUT_SLOT(Py_nb_subtract); + PUT_SLOT(Py_nb_true_divide); + PUT_SLOT(Py_nb_xor); +#ifndef IS_PY3K + PUT_SLOT(Py_nb_long); + PUT_SLOT(Py_nb_divide); +#endif +#undef PUT_SLOT + *pidx = idx; +} + +PyTypeObject * +newTypeWithName(const char* name, + const char* cppName, + PyTypeObject *numbers_fromFlag) +{ + // Careful: PyType_FromSpec does not allocate the string. + PyType_Slot newslots[99] = {}; // enough but not too big for the stack + PyType_Spec *newspec = new PyType_Spec; + newspec->name = strdup(name); + newspec->basicsize = SbkNewType_spec.basicsize; + newspec->itemsize = SbkNewType_spec.itemsize; + newspec->flags = SbkNewType_spec.flags; + // we must append all the number methods, so rebuild everything: + int idx = 0; + while (SbkNewType_slots[idx].SLOT) { + newslots[idx].SLOT = SbkNewType_slots[idx].SLOT; + newslots[idx].pfunc = SbkNewType_slots[idx].pfunc; + ++idx; + } + if (numbers_fromFlag) + copyNumberMethods(numbers_fromFlag, newslots, &idx); + newspec->slots = newslots; + PyTypeObject *type = reinterpret_cast<PyTypeObject *>(PyType_FromSpec(newspec)); + Py_TYPE(type) = SbkEnumType_TypeF(); + Py_INCREF(Py_TYPE(type)); SbkEnumType* enumType = reinterpret_cast<SbkEnumType*>(type); - enumType->cppName = cppName; - enumType->converterPtr = &enumType->converter; + PepType_SETP(enumType)->cppName = cppName; + PepType_SETP(enumType)->converterPtr = &PepType_SETP(enumType)->converter; DeclaredEnumTypes::instance().addEnumType(type); return type; } const char* getCppName(PyTypeObject* enumType) { - assert(Py_TYPE(enumType) == &SbkEnumType_Type); - return reinterpret_cast<SbkEnumType*>(enumType)->cppName;; + assert(Py_TYPE(enumType) == SbkEnumType_TypeF()); + return PepType_SETP(reinterpret_cast<SbkEnumType*>(enumType))->cppName; } long int getValue(PyObject* enumItem) @@ -585,13 +623,13 @@ long int getValue(PyObject* enumItem) void setTypeConverter(PyTypeObject* enumType, SbkConverter* converter) { //reinterpret_cast<SbkEnumType*>(enumType)->converter = converter; - SBK_CONVERTER(enumType) = converter; + *PepType_SGTP(enumType)->converter = converter; } SbkConverter* getTypeConverter(PyTypeObject* enumType) { //return reinterpret_cast<SbkEnumType*>(enumType)->converter; - return SBK_CONVERTER(enumType); + return *PepType_SGTP(enumType)->converter; } } // namespace Enum @@ -609,8 +647,17 @@ DeclaredEnumTypes::DeclaredEnumTypes() DeclaredEnumTypes::~DeclaredEnumTypes() { std::list<PyTypeObject*>::const_iterator it = m_enumTypes.begin(); - for (; it != m_enumTypes.end(); ++it) - delete *it; + for (; it != m_enumTypes.end(); ++it) { + /* + * PYSIDE-595: This was "delete *it;" before introducing 'PyType_FromSpec'. + * XXX what should I do now? + * Refcounts in tests are 30 or 0 at end. + * When I add the default tp_dealloc, we get negative refcounts! + * So right now I am doing nothing. Surely wrong but no crash. + * See also the comment in function 'createGlobalEnumItem'. + */ + //fprintf(stderr, "ttt %d %s\n", Py_REFCNT(*it), PepType(*it)->tp_name); + } m_enumTypes.clear(); } diff --git a/sources/shiboken2/libshiboken/sbkenum.h b/sources/shiboken2/libshiboken/sbkenum.h index 4e4665423..c1ec7c4c1 100644 --- a/sources/shiboken2/libshiboken/sbkenum.h +++ b/sources/shiboken2/libshiboken/sbkenum.h @@ -46,9 +46,11 @@ extern "C" { -extern LIBSHIBOKEN_API PyTypeObject SbkEnumType_Type; +extern LIBSHIBOKEN_API PyTypeObject *SbkEnumType_TypeF(void); struct SbkObjectType; struct SbkConverter; +struct SbkEnumType; +struct SbkEnumTypePrivate; } // extern "C" @@ -57,7 +59,7 @@ namespace Shiboken inline bool isShibokenEnum(PyObject* pyObj) { - return Py_TYPE(pyObj->ob_type) == &SbkEnumType_Type; + return Py_TYPE(Py_TYPE(pyObj)) == SbkEnumType_TypeF(); } namespace Enum @@ -101,9 +103,8 @@ namespace Enum LIBSHIBOKEN_API PyObject* newItem(PyTypeObject* enumType, long itemValue, const char* itemName = 0); - /// \deprecated Use 'newTypeWithName' - SBK_DEPRECATED(LIBSHIBOKEN_API PyTypeObject* newType(const char* name)); - LIBSHIBOKEN_API PyTypeObject* newTypeWithName(const char* name, const char* cppName); + LIBSHIBOKEN_API PyTypeObject* newTypeWithName(const char* name, const char* cppName, + PyTypeObject *numbers_fromFlag=nullptr); LIBSHIBOKEN_API const char* getCppName(PyTypeObject* type); LIBSHIBOKEN_API long getValue(PyObject* enumItem); diff --git a/sources/shiboken2/libshiboken/sbkpython.h b/sources/shiboken2/libshiboken/sbkpython.h index 6d90f4086..5fe364a29 100644 --- a/sources/shiboken2/libshiboken/sbkpython.h +++ b/sources/shiboken2/libshiboken/sbkpython.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt for Python. @@ -40,8 +40,15 @@ #ifndef SBKPYTHON_H #define SBKPYTHON_H -#include "Python.h" +#include "sbkversion.h" + +#include <Python.h> +#include <structmember.h> +// Now we have the usual variables from Python.h . #include "python25compat.h" +#include "shibokenmacros.h" +#include "pep384impl.h" +#include "typespec.h" #if PY_MAJOR_VERSION >= 3 #define IS_PY3K diff --git a/sources/shiboken2/libshiboken/sbkstring.cpp b/sources/shiboken2/libshiboken/sbkstring.cpp index 58f58d286..b92674383 100644 --- a/sources/shiboken2/libshiboken/sbkstring.cpp +++ b/sources/shiboken2/libshiboken/sbkstring.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt for Python. @@ -108,7 +108,7 @@ const char* toCString(PyObject* str, Py_ssize_t* len) } // Return unicode from str instead of uniStr, because the lifetime of the returned pointer // depends on the lifetime of str. - return _PyUnicode_AsString(str); + return _PepUnicode_AsString(str); } #endif if (PyBytes_Check(str)) { diff --git a/sources/shiboken2/libshiboken/sbkversion.h.in b/sources/shiboken2/libshiboken/sbkversion.h.in index 447376c1b..99ee7f93e 100644 --- a/sources/shiboken2/libshiboken/sbkversion.h.in +++ b/sources/shiboken2/libshiboken/sbkversion.h.in @@ -46,5 +46,8 @@ #define SHIBOKEN_MICRO_VERSION @shiboken_MICRO_VERSION@ #define SHIBOKEN_RELEASE_LEVEL "final" #define SHIBOKEN_SERIAL 0 +#define PYTHON_VERSION_MAJOR @PYTHON_VERSION_MAJOR@ +#define PYTHON_VERSION_MINOR @PYTHON_VERSION_MINOR@ +#define PYTHON_VERSION_PATCH @PYTHON_VERSION_PATCH@ #endif diff --git a/sources/shiboken2/libshiboken/shibokenbuffer.cpp b/sources/shiboken2/libshiboken/shibokenbuffer.cpp index 2404aeb66..05b68dade 100644 --- a/sources/shiboken2/libshiboken/shibokenbuffer.cpp +++ b/sources/shiboken2/libshiboken/shibokenbuffer.cpp @@ -84,7 +84,9 @@ PyObject* Shiboken::Buffer::newObject(void* memory, Py_ssize_t size, Type type) view.itemsize = sizeof(char); Py_ssize_t shape[] = { size }; view.shape = shape; - return PyMemoryView_FromBuffer(&view); + // Pep384: This is way too complicated and impossible with the limited api: + //return PyMemoryView_FromBuffer(&view); + return PyMemoryView_FromMemory((char *)view.buf, size, type == ReadOnly ? PyBUF_READ : PyBUF_WRITE); #else return type == ReadOnly ? PyBuffer_FromMemory(memory, size) : PyBuffer_FromReadWriteMemory(memory, size); #endif diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp index b266784c0..fc83f89cd 100644 --- a/sources/shiboken2/libshiboken/signature.cpp +++ b/sources/shiboken2/libshiboken/signature.cpp @@ -114,7 +114,7 @@ extern "C" #if EXTENSION_ENABLED // These constants were needed in former versions of the module: -#define PYTHON_HAS_QUALNAME (PY_VERSION_HEX >= 0x03060000) +#define PYTHON_HAS_QUALNAME (PY_VERSION_HEX >= 0x03030000) #define PYTHON_HAS_UNICODE (PY_VERSION_HEX >= 0x03000000) #define PYTHON_HAS_WEAKREF_PYCFUNCTION (PY_VERSION_HEX >= 0x030500A0) #define PYTHON_IS_PYTHON3 (PY_VERSION_HEX >= 0x03000000) @@ -124,15 +124,16 @@ extern "C" #define PYTHON_HAS_METH_REDUCE (PYTHON_HAS_DESCR_REDUCE) #define PYTHON_NEEDS_ITERATOR_FLAG (!PYTHON_IS_PYTHON3) #define PYTHON_EXPOSES_METHODDESCR (PYTHON_IS_PYTHON3) +#define PYTHON_NO_TYPE_IN_FUNCTIONS (!PYTHON_IS_PYTHON3 || Py_LIMITED_API) // These constants are still in use: #define PYTHON_USES_D_COMMON (PY_VERSION_HEX >= 0x03020000) -#define PYTHON_NO_TYPE_IN_FUNCTIONS (!PYTHON_IS_PYTHON3) typedef struct safe_globals_struc { // init part 1: get arg_dict PyObject *helper_module; PyObject *arg_dict; + PyObject *map_dict; // init part 2: run module PyObject *sigparse_func; PyObject *createsig_func; @@ -164,9 +165,9 @@ CreateSignature(PyObject *props, const char *sig_kind) } static PyObject * -pyside_cf_get___signature__(PyCFunctionObject *func) +pyside_cf_get___signature__(PyObject *func) { - return GetSignature_Function(func); + return GetSignature_Function((PyCFunctionObject *)func); } static PyObject * @@ -180,22 +181,107 @@ pyside_sm_get___signature__(PyObject *sm) return ret; } +#ifdef Py_LIMITED_API + +static int +build_qualname_to_func(PyObject *obtype) +{ + PyTypeObject *type = (PyTypeObject *)obtype; + PyMethodDef *meth = PepType(type)->tp_methods; + + if (meth == 0) + return 0; + + for (; meth->ml_name != NULL; meth++) { + PyObject *func = PyCFunction_NewEx(meth, obtype, NULL); + PyObject *qualname = PyObject_GetAttrString(func, "__qualname__"); + if (func == NULL || qualname == NULL) { + return -1; + } + if (PyDict_SetItem(pyside_globals->map_dict, qualname, func) < 0) { + return -1; + } + Py_DECREF(func); + Py_DECREF(qualname); + } + return 0; +} + static PyObject * -pyside_md_get___signature__(PyMethodDescrObject *descr) +qualname_to_typename(PyObject *qualname) { - PyCFunctionObject *func; - PyObject *result; + PyObject *func = PyObject_GetAttrString(qualname, "split"); + PyObject *list = func ? PyObject_CallFunction(func, (char *)"(s)", ".") + : NULL; + PyObject *res = list ? PyList_GetItem(list, 0) : NULL; + Py_XINCREF(res); + Py_XDECREF(func); + Py_XDECREF(list); + return res; +} + +static PyObject * +qualname_to_func(PyObject *ob) +{ + /* + * If we have __qualname__, then we can easily build a mapping + * from __qualname__ to PyCFunction. This is necessary when + * the limited API does not let us go easily from descriptor + * to PyMethodDef. + */ + PyObject *ret; + PyObject *qualname = PyObject_GetAttrString((PyObject *)ob, + "__qualname__"); + if (qualname != NULL) { + ret = PyDict_GetItem(pyside_globals->map_dict, qualname); + if (ret == NULL) { + // do a lazy initialization + PyObject *type_name = qualname_to_typename(qualname); + PyObject *type = PyDict_GetItem(pyside_globals->map_dict, + type_name); + Py_XDECREF(type_name); + if (type == NULL) + Py_RETURN_NONE; + if (build_qualname_to_func(type) < 0) + return NULL; + ret = PyDict_GetItem(pyside_globals->map_dict, qualname); + } + Py_XINCREF(ret); + Py_DECREF(qualname); + } + else + Py_RETURN_NONE; + return ret; +} +#endif - func = (PyCFunctionObject *) - PyCFunction_NewEx(descr->d_method, -#if PYTHON_USES_D_COMMON - (PyObject *)descr->d_common.d_type, NULL +static PyObject * +pyside_md_get___signature__(PyObject *ob) +{ + PyObject *func; + PyObject *result; +#ifndef Py_LIMITED_API + PyMethodDescrObject *descr = (PyMethodDescrObject *)ob; + +# if PYTHON_USES_D_COMMON + func = PyCFunction_NewEx(descr->d_method, + (PyObject *)descr->d_common.d_type, NULL); +# else + func = PyCFunction_NewEx(descr->d_method, + (PyObject *)descr->d_type, NULL); +# endif #else - (PyObject *)descr->d_type, NULL + /* + * With limited access, we cannot use the fields of a method descriptor, + * but in Python 3 we have the __qualname__ field which allows us to + * grab the method object from our registry. + */ + func = qualname_to_func(ob); #endif - ); + if (func == Py_None) + return Py_None; if (func == NULL) - return NULL; + Py_FatalError("missing mapping in MethodDescriptor"); result = pyside_cf_get___signature__(func); Py_DECREF(func); return result; @@ -215,16 +301,15 @@ GetSignature_Function(PyCFunctionObject *func) const char *sig_kind; int flags; - selftype = func->m_self; - if (selftype == NULL) { -#if PYTHON_NO_TYPE_IN_FUNCTIONS - selftype = PyDict_GetItem(pyside_globals->arg_dict, (PyObject *)func); - } + selftype = PyCFunction_GET_SELF((PyObject *)func); + if (selftype == NULL) + selftype = PyDict_GetItem(pyside_globals->map_dict, (PyObject *)func); if (selftype == NULL) { -#endif if (!PyErr_Occurred()) { PyErr_Format(PyExc_SystemError, - "the signature for \"%s\" should exist", func->m_ml->ml_name); + "the signature for \"%s\" should exist", + PepCFunction_GET_NAMESTR(func) + ); } return NULL; } @@ -251,7 +336,7 @@ GetSignature_Function(PyCFunctionObject *func) props = PyDict_GetItem(dict, func_name); if (props == NULL) Py_RETURN_NONE; - flags = PyCFunction_GET_FLAGS(func); + flags = PyCFunction_GET_FLAGS((PyObject *)func); if (flags & METH_CLASS) sig_kind = "classmethod"; else if (flags & METH_STATIC) @@ -347,6 +432,11 @@ init_phase_1(void) goto error; Py_DECREF(v); + // build a dict for diverse mappings + p->map_dict = PyDict_New(); + if (p->map_dict == NULL) + goto error; + // Build a dict for the prepared arguments p->arg_dict = PyDict_New(); if (p->arg_dict == NULL) @@ -387,7 +477,7 @@ error: static int add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp) { - PyObject *dict = type->tp_dict; + PyObject *dict = PepType(type)->tp_dict; for (; gsp->name != NULL; gsp++) { PyObject *descr; @@ -479,16 +569,17 @@ PySideType_Ready(PyTypeObject *type) // PyMethodDescr_Type 'type(str.__dict__["split"])' // PyClassMethodDescr_Type. 'type(dict.__dict__["fromkeys"])' // The latter is not needed until we use class methods in PySide. - md = PyDict_GetItemString(PyString_Type.tp_dict, "split"); + md = PyObject_GetAttrString((PyObject *)&PyString_Type, "split"); if (md == NULL || PyType_Ready(Py_TYPE(md)) < 0 || add_more_getsets(Py_TYPE(md), new_PyMethodDescr_getsets) < 0 || add_more_getsets(&PyCFunction_Type, new_PyCFunction_getsets) < 0 - || add_more_getsets(&PyStaticMethod_Type, new_PyStaticMethod_getsets) < 0 + || add_more_getsets(PepStaticMethod_TypePtr, new_PyStaticMethod_getsets) < 0 || add_more_getsets(&PyType_Type, new_PyType_getsets) < 0) return -1; + Py_DECREF(md); #ifndef _WIN32 - // we enable the stack trace in CI, only. + // We enable the stack trace in CI, only. const char *testEnv = getenv("QTEST_ENVIRONMENT"); if (testEnv && strstr(testEnv, "ci")) signal(SIGSEGV, handler); // install our handler @@ -498,20 +589,12 @@ PySideType_Ready(PyTypeObject *type) return PyType_Ready(type); } -#if PYTHON_NO_TYPE_IN_FUNCTIONS - -typedef struct { - PyObject_HEAD - PyObject *sm_callable; - PyObject *sm_dict; -} staticmethod; - static int build_func_to_type(PyObject *obtype) { PyTypeObject *type = (PyTypeObject *)obtype; - PyObject *dict = type->tp_dict; - PyMethodDef *meth = type->tp_methods; + PyObject *dict = PepType(type)->tp_dict; + PyMethodDef *meth = PepType(type)->tp_methods; if (meth == 0) return 0; @@ -521,19 +604,16 @@ build_func_to_type(PyObject *obtype) PyObject *descr = PyDict_GetItemString(dict, meth->ml_name); if (descr == NULL) return -1; - staticmethod *sm = (staticmethod *)descr; - PyObject *cfunc = sm->sm_callable; - if (cfunc == NULL) - return -1; - if (PyDict_SetItem(pyside_globals->arg_dict, cfunc, obtype) < 0) + PyObject *func = PyObject_GetAttrString(descr, "__func__"); + if (func == NULL || + PyDict_SetItem(pyside_globals->map_dict, func, obtype) < 0) return -1; + Py_DECREF(func); } } return 0; } -#endif - static int PySide_BuildSignatureArgs(PyObject *module, PyObject *type, const char *signatures) @@ -574,6 +654,12 @@ PySide_BuildSignatureArgs(PyObject *module, PyObject *type, return -1; if (PyDict_SetItem(pyside_globals->arg_dict, type_name, arg_tup) < 0) return -1; + /* + * We record also a mapping from type name to type. This helps to lazily + * initialize the Py_LIMITED_API in qualname_to_func(). + */ + if (PyDict_SetItem(pyside_globals->map_dict, type_name, type) < 0) + return -1; return 0; } @@ -650,13 +736,16 @@ PySide_FinishSignatures(PyObject *module, const char *signatures) if (PySide_BuildSignatureArgs(module, module, signatures) < 0) return -1; -#if PYTHON_NO_TYPE_IN_FUNCTIONS /* * Python2 does not abuse the 'm_self' field for the type. So we need to * supply this for all static methods. * * Note: This function crashed when called from PySide_BuildSignatureArgs. * Probably this was too early. + * + * Pep384: We need to switch this always on since we have no access + * to the PyCFunction attributes. Therefore I simplified things + * and always use our own mapping. */ { PyObject *key, *value; @@ -668,12 +757,12 @@ PySide_FinishSignatures(PyObject *module, const char *signatures) while (PyDict_Next(dict, &pos, &key, &value)) { if (PyType_Check(value)) { - if (build_func_to_type(value) < 0) + PyObject *type = value; + if (build_func_to_type(type) < 0) return -1; } } } -#endif return 0; } #endif // EXTENSION_ENABLED diff --git a/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.cpp b/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.cpp index 7c20b9b58..8e351cedd 100644 --- a/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.cpp +++ b/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.cpp @@ -180,7 +180,7 @@ void pythonToCppPointer(SbkObjectType* type, PyObject* pyIn, void* cppOut) { assert(pyIn); assert(cppOut); - SbkObjectType* inType = (SbkObjectType*)pyIn->ob_type; + SbkObjectType* inType = (SbkObjectType*)Py_TYPE(pyIn); if (ObjectType::hasCast(inType)) *((void**)cppOut) = ObjectType::cast(inType, (SbkObject*)pyIn, (PyTypeObject*)type); else diff --git a/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.h b/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.h index f139a491a..cc9ea7a19 100644 --- a/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.h +++ b/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.h @@ -41,7 +41,7 @@ #define SBK_CONVERTER_H #include <limits> -#include <Python.h> +#include "sbkpython.h" #include "shibokenmacros.h" #include "basewrapper.h" diff --git a/sources/shiboken2/libshiboken/typespec.cpp b/sources/shiboken2/libshiboken/typespec.cpp new file mode 100644 index 000000000..d532c97ed --- /dev/null +++ b/sources/shiboken2/libshiboken/typespec.cpp @@ -0,0 +1,776 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "typespec.h" +#include <structmember.h> + +#if PY_MAJOR_VERSION < 3 + +extern "C" +{ + +// for some reason python 2.7 needs this on Windows +#ifdef WIN32 +static PyGC_Head *_PyGC_generation0; +#endif + +// from pymacro.h +#ifndef Py_PYMACRO_H +#define Py_PYMACRO_H + +/* Minimum value between x and y */ +#define Py_MIN(x, y) (((x) > (y)) ? (y) : (x)) + +/* Maximum value between x and y */ +#define Py_MAX(x, y) (((x) > (y)) ? (x) : (y)) + +/* Absolute value of the number x */ +#define Py_ABS(x) ((x) < 0 ? -(x) : (x)) + +#define _Py_XSTRINGIFY(x) #x + +/* Convert the argument to a string. For example, Py_STRINGIFY(123) is replaced + with "123" by the preprocessor. Defines are also replaced by their value. + For example Py_STRINGIFY(__LINE__) is replaced by the line number, not + by "__LINE__". */ +#define Py_STRINGIFY(x) _Py_XSTRINGIFY(x) + +/* Get the size of a structure member in bytes */ +#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) + +/* Argument must be a char or an int in [-128, 127] or [0, 255]. */ +#define Py_CHARMASK(c) ((unsigned char)((c) & 0xff)) + +/* Assert a build-time dependency, as an expression. + + Your compile will fail if the condition isn't true, or can't be evaluated + by the compiler. This can be used in an expression: its value is 0. + + Example: + + #define foo_to_char(foo) \ + ((char *)(foo) \ + + Py_BUILD_ASSERT_EXPR(offsetof(struct foo, string) == 0)) + + Written by Rusty Russell, public domain, http://ccodearchive.net/ */ +#define Py_BUILD_ASSERT_EXPR(cond) \ + (sizeof(char [1 - 2*!(cond)]) - 1) + +#define Py_BUILD_ASSERT(cond) do { \ + (void)Py_BUILD_ASSERT_EXPR(cond); \ + } while (0) + +/* Get the number of elements in a visible array + + This does not work on pointers, or arrays declared as [], or function + parameters. With correct compiler support, such usage will cause a build + error (see Py_BUILD_ASSERT_EXPR). + + Written by Rusty Russell, public domain, http://ccodearchive.net/ + + Requires at GCC 3.1+ */ +// Simplified by "0 &&" +#if 0 && (defined(__GNUC__) && !defined(__STRICT_ANSI__) && \ + (((__GNUC__ == 3) && (__GNU_MINOR__ >= 1)) || (__GNUC__ >= 4))) +/* Two gcc extensions. + &a[0] degrades to a pointer: a different type from an array */ +#define Py_ARRAY_LENGTH(array) \ + (sizeof(array) / sizeof((array)[0]) \ + + Py_BUILD_ASSERT_EXPR(!__builtin_types_compatible_p(typeof(array), \ + typeof(&(array)[0])))) +#else +#define Py_ARRAY_LENGTH(array) \ + (sizeof(array) / sizeof((array)[0])) +#endif + + +/* Define macros for inline documentation. */ +#define PyDoc_VAR(name) static char name[] +#define PyDoc_STRVAR(name,str) PyDoc_VAR(name) = PyDoc_STR(str) +#ifdef WITH_DOC_STRINGS +#define PyDoc_STR(str) str +#else +#define PyDoc_STR(str) "" +#endif + +/* Below "a" is a power of 2. */ +/* Round down size "n" to be a multiple of "a". */ +#define _Py_SIZE_ROUND_DOWN(n, a) ((size_t)(n) & ~(size_t)((a) - 1)) +/* Round up size "n" to be a multiple of "a". */ +#define _Py_SIZE_ROUND_UP(n, a) (((size_t)(n) + \ + (size_t)((a) - 1)) & ~(size_t)((a) - 1)) +/* Round pointer "p" down to the closest "a"-aligned address <= "p". */ +#define _Py_ALIGN_DOWN(p, a) ((void *)((uintptr_t)(p) & ~(uintptr_t)((a) - 1))) +/* Round pointer "p" up to the closest "a"-aligned address >= "p". */ +#define _Py_ALIGN_UP(p, a) ((void *)(((uintptr_t)(p) + \ + (uintptr_t)((a) - 1)) & ~(uintptr_t)((a) - 1))) +/* Check if pointer "p" is aligned to "a"-bytes boundary. */ +#define _Py_IS_ALIGNED(p, a) (!((uintptr_t)(p) & (uintptr_t)((a) - 1))) + +#ifdef __GNUC__ +#define Py_UNUSED(name) _unused_ ## name __attribute__((unused)) +#else +#define Py_UNUSED(name) _unused_ ## name +#endif + +#endif /* Py_PYMACRO_H */ + +// from typeobject.c +static int +extra_ivars(PyTypeObject *type, PyTypeObject *base) +{ + size_t t_size = type->tp_basicsize; + size_t b_size = base->tp_basicsize; + + assert(t_size >= b_size); /* Else type smaller than base! */ + if (type->tp_itemsize || base->tp_itemsize) { + /* If itemsize is involved, stricter rules */ + return t_size != b_size || + type->tp_itemsize != base->tp_itemsize; + } + if (type->tp_weaklistoffset && base->tp_weaklistoffset == 0 && + type->tp_weaklistoffset + sizeof(PyObject *) == t_size && + type->tp_flags & Py_TPFLAGS_HEAPTYPE) + t_size -= sizeof(PyObject *); + if (type->tp_dictoffset && base->tp_dictoffset == 0 && + type->tp_dictoffset + sizeof(PyObject *) == t_size && + type->tp_flags & Py_TPFLAGS_HEAPTYPE) + t_size -= sizeof(PyObject *); + + return t_size != b_size; +} + +static void +clear_slots(PyTypeObject *type, PyObject *self) +{ + Py_ssize_t i, n; + PyMemberDef *mp; + + n = Py_SIZE(type); + mp = PyHeapType_GET_MEMBERS((PyHeapTypeObject *)type); + for (i = 0; i < n; i++, mp++) { + if (mp->type == T_OBJECT_EX && !(mp->flags & READONLY)) { + char *addr = (char *)self + mp->offset; + PyObject *obj = *(PyObject **)addr; + if (obj != NULL) { + *(PyObject **)addr = NULL; + Py_DECREF(obj); + } + } + } +} + +static void +subtype_dealloc(PyObject *self) +{ + PyTypeObject *type, *base; + destructor basedealloc; + PyThreadState *tstate = PyThreadState_GET(); + + /* Extract the type; we expect it to be a heap type */ + type = Py_TYPE(self); + assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE); + + /* Test whether the type has GC exactly once */ + + if (!PyType_IS_GC(type)) { + /* It's really rare to find a dynamic type that doesn't have + GC; it can only happen when deriving from 'object' and not + adding any slots or instance variables. This allows + certain simplifications: there's no need to call + clear_slots(), or DECREF the dict, or clear weakrefs. */ + + /* Maybe call finalizer; exit early if resurrected */ + if (type->tp_del) { + type->tp_del(self); + if (self->ob_refcnt > 0) + return; + } + + /* Find the nearest base with a different tp_dealloc */ + base = type; + while ((basedealloc = base->tp_dealloc) == subtype_dealloc) { + assert(Py_SIZE(base) == 0); + base = base->tp_base; + assert(base); + } + + /* Extract the type again; tp_del may have changed it */ + type = Py_TYPE(self); + + /* Call the base tp_dealloc() */ + assert(basedealloc); + basedealloc(self); + + /* Can't reference self beyond this point */ + Py_DECREF(type); + + /* Done */ + return; + } + + /* We get here only if the type has GC */ + + /* UnTrack and re-Track around the trashcan macro, alas */ + /* See explanation at end of function for full disclosure */ + PyObject_GC_UnTrack(self); + ++_PyTrash_delete_nesting; + ++ tstate->trash_delete_nesting; + Py_TRASHCAN_SAFE_BEGIN(self); + --_PyTrash_delete_nesting; + -- tstate->trash_delete_nesting; + /* DO NOT restore GC tracking at this point. weakref callbacks + * (if any, and whether directly here or indirectly in something we + * call) may trigger GC, and if self is tracked at that point, it + * will look like trash to GC and GC will try to delete self again. + */ + + /* Find the nearest base with a different tp_dealloc */ + base = type; + while ((basedealloc = base->tp_dealloc) == subtype_dealloc) { + base = base->tp_base; + assert(base); + } + + /* If we added a weaklist, we clear it. Do this *before* calling + the finalizer (__del__), clearing slots, or clearing the instance + dict. */ + + if (type->tp_weaklistoffset && !base->tp_weaklistoffset) + PyObject_ClearWeakRefs(self); + + /* Maybe call finalizer; exit early if resurrected */ + if (type->tp_del) { + _PyObject_GC_TRACK(self); + type->tp_del(self); + if (self->ob_refcnt > 0) + goto endlabel; /* resurrected */ + else + _PyObject_GC_UNTRACK(self); + /* New weakrefs could be created during the finalizer call. + If this occurs, clear them out without calling their + finalizers since they might rely on part of the object + being finalized that has already been destroyed. */ + if (type->tp_weaklistoffset && !base->tp_weaklistoffset) { + /* Modeled after GET_WEAKREFS_LISTPTR() */ + PyWeakReference **list = (PyWeakReference **) \ + PyObject_GET_WEAKREFS_LISTPTR(self); + while (*list) + _PyWeakref_ClearRef(*list); + } + } + + /* Clear slots up to the nearest base with a different tp_dealloc */ + base = type; + while (base->tp_dealloc == subtype_dealloc) { + if (Py_SIZE(base)) + clear_slots(base, self); + base = base->tp_base; + assert(base); + } + + /* If we added a dict, DECREF it */ + if (type->tp_dictoffset && !base->tp_dictoffset) { + PyObject **dictptr = _PyObject_GetDictPtr(self); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + if (dict != NULL) { + Py_DECREF(dict); + *dictptr = NULL; + } + } + } + + /* Extract the type again; tp_del may have changed it */ + type = Py_TYPE(self); + + /* Call the base tp_dealloc(); first retrack self if + * basedealloc knows about gc. + */ + if (PyType_IS_GC(base)) + _PyObject_GC_TRACK(self); + assert(basedealloc); + basedealloc(self); + + /* Can't reference self beyond this point */ + Py_DECREF(type); + + endlabel: + ++_PyTrash_delete_nesting; + ++ tstate->trash_delete_nesting; + Py_TRASHCAN_SAFE_END(self); + --_PyTrash_delete_nesting; + -- tstate->trash_delete_nesting; + + /* Explanation of the weirdness around the trashcan macros: + + Q. What do the trashcan macros do? + + A. Read the comment titled "Trashcan mechanism" in object.h. + For one, this explains why there must be a call to GC-untrack + before the trashcan begin macro. Without understanding the + trashcan code, the answers to the following questions don't make + sense. + + Q. Why do we GC-untrack before the trashcan and then immediately + GC-track again afterward? + + A. In the case that the base class is GC-aware, the base class + probably GC-untracks the object. If it does that using the + UNTRACK macro, this will crash when the object is already + untracked. Because we don't know what the base class does, the + only safe thing is to make sure the object is tracked when we + call the base class dealloc. But... The trashcan begin macro + requires that the object is *untracked* before it is called. So + the dance becomes: + + GC untrack + trashcan begin + GC track + + Q. Why did the last question say "immediately GC-track again"? + It's nowhere near immediately. + + A. Because the code *used* to re-track immediately. Bad Idea. + self has a refcount of 0, and if gc ever gets its hands on it + (which can happen if any weakref callback gets invoked), it + looks like trash to gc too, and gc also tries to delete self + then. But we're already deleting self. Double deallocation is + a subtle disaster. + + Q. Why the bizarre (net-zero) manipulation of + _PyTrash_delete_nesting around the trashcan macros? + + A. Some base classes (e.g. list) also use the trashcan mechanism. + The following scenario used to be possible: + + - suppose the trashcan level is one below the trashcan limit + + - subtype_dealloc() is called + + - the trashcan limit is not yet reached, so the trashcan level + is incremented and the code between trashcan begin and end is + executed + + - this destroys much of the object's contents, including its + slots and __dict__ + + - basedealloc() is called; this is really list_dealloc(), or + some other type which also uses the trashcan macros + + - the trashcan limit is now reached, so the object is put on the + trashcan's to-be-deleted-later list + + - basedealloc() returns + + - subtype_dealloc() decrefs the object's type + + - subtype_dealloc() returns + + - later, the trashcan code starts deleting the objects from its + to-be-deleted-later list + + - subtype_dealloc() is called *AGAIN* for the same object + + - at the very least (if the destroyed slots and __dict__ don't + cause problems) the object's type gets decref'ed a second + time, which is *BAD*!!! + + The remedy is to make sure that if the code between trashcan + begin and end in subtype_dealloc() is called, the code between + trashcan begin and end in basedealloc() will also be called. + This is done by decrementing the level after passing into the + trashcan block, and incrementing it just before leaving the + block. + + But now it's possible that a chain of objects consisting solely + of objects whose deallocator is subtype_dealloc() will defeat + the trashcan mechanism completely: the decremented level means + that the effective level never reaches the limit. Therefore, we + *increment* the level *before* entering the trashcan block, and + matchingly decrement it after leaving. This means the trashcan + code will trigger a little early, but that's no big deal. + + Q. Are there any live examples of code in need of all this + complexity? + + A. Yes. See SF bug 668433 for code that crashed (when Python was + compiled in debug mode) before the trashcan level manipulations + were added. For more discussion, see SF patches 581742, 575073 + and bug 574207. + */ +} + +static PyTypeObject * +solid_base(PyTypeObject *type) +{ + PyTypeObject *base; + + if (type->tp_base) + base = solid_base(type->tp_base); + else + base = &PyBaseObject_Type; + if (extra_ivars(type, base)) + return type; + else + return base; +} + +/* Calculate the best base amongst multiple base classes. + This is the first one that's on the path to the "solid base". */ + +static PyTypeObject * +best_base(PyObject *bases) +{ + Py_ssize_t i, n; + PyTypeObject *base, *winner, *candidate, *base_i; + PyObject *base_proto; + + assert(PyTuple_Check(bases)); + n = PyTuple_GET_SIZE(bases); + assert(n > 0); + base = NULL; + winner = NULL; + for (i = 0; i < n; i++) { + base_proto = PyTuple_GET_ITEM(bases, i); + if (PyClass_Check(base_proto)) + continue; + if (!PyType_Check(base_proto)) { + PyErr_SetString( + PyExc_TypeError, + "bases must be types"); + return NULL; + } + base_i = (PyTypeObject *)base_proto; + if (base_i->tp_dict == NULL) { + if (PyType_Ready(base_i) < 0) + return NULL; + } + if (!PyType_HasFeature(base_i, Py_TPFLAGS_BASETYPE)) { + PyErr_Format(PyExc_TypeError, + "type '%.100s' is not an acceptable base type", + base_i->tp_name); + return NULL; + } + candidate = solid_base(base_i); + if (winner == NULL) { + winner = candidate; + base = base_i; + } + else if (PyType_IsSubtype(winner, candidate)) + ; + else if (PyType_IsSubtype(candidate, winner)) { + winner = candidate; + base = base_i; + } + else { + PyErr_SetString( + PyExc_TypeError, + "multiple bases have " + "instance lay-out conflict"); + return NULL; + } + } + if (base == NULL) + PyErr_SetString(PyExc_TypeError, + "a new-style class can't have only classic bases"); + return base; +} + +static const short slotoffsets[] = { + -1, /* invalid slot_ */ +/* Generated by typeslots.py */ +0, +0, +offsetof(PyHeapTypeObject, as_mapping.mp_ass_subscript), +offsetof(PyHeapTypeObject, as_mapping.mp_length), +offsetof(PyHeapTypeObject, as_mapping.mp_subscript), +offsetof(PyHeapTypeObject, as_number.nb_absolute), +offsetof(PyHeapTypeObject, as_number.nb_add), +offsetof(PyHeapTypeObject, as_number.nb_and), +offsetof(PyHeapTypeObject, as_number.nb_nonzero), +offsetof(PyHeapTypeObject, as_number.nb_divmod), +offsetof(PyHeapTypeObject, as_number.nb_float), +offsetof(PyHeapTypeObject, as_number.nb_floor_divide), +offsetof(PyHeapTypeObject, as_number.nb_index), +offsetof(PyHeapTypeObject, as_number.nb_inplace_add), +offsetof(PyHeapTypeObject, as_number.nb_inplace_and), +offsetof(PyHeapTypeObject, as_number.nb_inplace_floor_divide), +offsetof(PyHeapTypeObject, as_number.nb_inplace_lshift), +offsetof(PyHeapTypeObject, as_number.nb_inplace_multiply), +offsetof(PyHeapTypeObject, as_number.nb_inplace_or), +offsetof(PyHeapTypeObject, as_number.nb_inplace_power), +offsetof(PyHeapTypeObject, as_number.nb_inplace_remainder), +offsetof(PyHeapTypeObject, as_number.nb_inplace_rshift), +offsetof(PyHeapTypeObject, as_number.nb_inplace_subtract), +offsetof(PyHeapTypeObject, as_number.nb_inplace_true_divide), +offsetof(PyHeapTypeObject, as_number.nb_inplace_xor), +offsetof(PyHeapTypeObject, as_number.nb_int), +offsetof(PyHeapTypeObject, as_number.nb_invert), +offsetof(PyHeapTypeObject, as_number.nb_lshift), +offsetof(PyHeapTypeObject, as_number.nb_multiply), +offsetof(PyHeapTypeObject, as_number.nb_negative), +offsetof(PyHeapTypeObject, as_number.nb_or), +offsetof(PyHeapTypeObject, as_number.nb_positive), +offsetof(PyHeapTypeObject, as_number.nb_power), +offsetof(PyHeapTypeObject, as_number.nb_remainder), +offsetof(PyHeapTypeObject, as_number.nb_rshift), +offsetof(PyHeapTypeObject, as_number.nb_subtract), +offsetof(PyHeapTypeObject, as_number.nb_true_divide), +offsetof(PyHeapTypeObject, as_number.nb_xor), +offsetof(PyHeapTypeObject, as_sequence.sq_ass_item), +offsetof(PyHeapTypeObject, as_sequence.sq_concat), +offsetof(PyHeapTypeObject, as_sequence.sq_contains), +offsetof(PyHeapTypeObject, as_sequence.sq_inplace_concat), +offsetof(PyHeapTypeObject, as_sequence.sq_inplace_repeat), +offsetof(PyHeapTypeObject, as_sequence.sq_item), +offsetof(PyHeapTypeObject, as_sequence.sq_length), +offsetof(PyHeapTypeObject, as_sequence.sq_repeat), +offsetof(PyHeapTypeObject, ht_type.tp_alloc), +offsetof(PyHeapTypeObject, ht_type.tp_base), +offsetof(PyHeapTypeObject, ht_type.tp_bases), +offsetof(PyHeapTypeObject, ht_type.tp_call), +offsetof(PyHeapTypeObject, ht_type.tp_clear), +offsetof(PyHeapTypeObject, ht_type.tp_dealloc), +offsetof(PyHeapTypeObject, ht_type.tp_del), +offsetof(PyHeapTypeObject, ht_type.tp_descr_get), +offsetof(PyHeapTypeObject, ht_type.tp_descr_set), +offsetof(PyHeapTypeObject, ht_type.tp_doc), +offsetof(PyHeapTypeObject, ht_type.tp_getattr), +offsetof(PyHeapTypeObject, ht_type.tp_getattro), +offsetof(PyHeapTypeObject, ht_type.tp_hash), +offsetof(PyHeapTypeObject, ht_type.tp_init), +offsetof(PyHeapTypeObject, ht_type.tp_is_gc), +offsetof(PyHeapTypeObject, ht_type.tp_iter), +offsetof(PyHeapTypeObject, ht_type.tp_iternext), +offsetof(PyHeapTypeObject, ht_type.tp_methods), +offsetof(PyHeapTypeObject, ht_type.tp_new), +offsetof(PyHeapTypeObject, ht_type.tp_repr), +offsetof(PyHeapTypeObject, ht_type.tp_richcompare), +offsetof(PyHeapTypeObject, ht_type.tp_setattr), +offsetof(PyHeapTypeObject, ht_type.tp_setattro), +offsetof(PyHeapTypeObject, ht_type.tp_str), +offsetof(PyHeapTypeObject, ht_type.tp_traverse), +offsetof(PyHeapTypeObject, ht_type.tp_members), +offsetof(PyHeapTypeObject, ht_type.tp_getset), +offsetof(PyHeapTypeObject, ht_type.tp_free), +offsetof(PyHeapTypeObject, as_number.nb_long), +offsetof(PyHeapTypeObject, as_number.nb_divide), +offsetof(PyHeapTypeObject, as_sequence.sq_slice), +}; + +PyObject * +PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) +{ + PyHeapTypeObject *res = (PyHeapTypeObject*)PyType_GenericAlloc(&PyType_Type, 0); + PyTypeObject *type, *base; + PyObject *modname; + char *s; + char *res_start = (char*)res; + PyType_Slot *slot_; + + /* Set the type name and qualname */ + s = (char *)strrchr(spec->name, '.'); // C++11 + if (s == NULL) + s = (char*)spec->name; + else + s++; + + if (res == NULL) + return NULL; + type = &res->ht_type; + /* The flags must be initialized early, before the GC traverses us */ + type->tp_flags = spec->flags | Py_TPFLAGS_HEAPTYPE; + // was PyUnicode_FromString in Python 3 + res->ht_name = PyString_FromString(s); + if (!res->ht_name) + goto fail; + // no ht_qualname in Python 2 + // res->ht_qualname = res->ht_name; + // Py_INCREF(res->ht_qualname); + type->tp_name = spec->name; + if (!type->tp_name) + goto fail; + + /* Adjust for empty tuple bases */ + if (!bases) { + base = &PyBaseObject_Type; + /* See whether Py_tp_base(s) was specified */ + for (slot_ = spec->slots; slot_->slot_; slot_++) { + if (slot_->slot_ == Py_tp_base) + base = (PyTypeObject *)slot_->pfunc; // C++11 + else if (slot_->slot_ == Py_tp_bases) { + bases = (PyObject *)slot_->pfunc; // C++11 + Py_INCREF(bases); + } + } + if (!bases) + bases = PyTuple_Pack(1, base); + if (!bases) + goto fail; + } + else + Py_INCREF(bases); + + /* Calculate best base, and check that all bases are type objects */ + base = best_base(bases); + if (base == NULL) { + goto fail; + } + if (!PyType_HasFeature(base, Py_TPFLAGS_BASETYPE)) { + PyErr_Format(PyExc_TypeError, + "type '%.100s' is not an acceptable base type", + base->tp_name); + goto fail; + } + + /* Initialize essential fields */ + // no async in Python 2 + // type->tp_as_async = &res->as_async; + type->tp_as_number = &res->as_number; + type->tp_as_sequence = &res->as_sequence; + type->tp_as_mapping = &res->as_mapping; + type->tp_as_buffer = &res->as_buffer; + /* Set tp_base and tp_bases */ + type->tp_bases = bases; + bases = NULL; + Py_INCREF(base); + type->tp_base = base; + + type->tp_basicsize = spec->basicsize; + type->tp_itemsize = spec->itemsize; + + for (slot_ = spec->slots; slot_->slot_; slot_++) { + if (slot_->slot_ < 0 + || (size_t)slot_->slot_ >= Py_ARRAY_LENGTH(slotoffsets)) { + PyErr_SetString(PyExc_RuntimeError, "invalid slot_ offset"); + goto fail; + } + if (slot_->slot_ == Py_tp_base || slot_->slot_ == Py_tp_bases) + /* Processed above */ + continue; + *(void**)(res_start + slotoffsets[slot_->slot_]) = slot_->pfunc; + + /* need to make a copy of the docstring slot_, which usually + points to a static string literal */ + if (slot_->slot_ == Py_tp_doc) { + // No signature in Python 2 + // const char *old_doc = _PyType_DocWithoutSignature(type->tp_name, slot_->pfunc); + const char *old_doc = (const char *)slot_->pfunc; + size_t len = strlen(old_doc)+1; + char *tp_doc = (char *)PyObject_MALLOC(len); // C++11 + if (tp_doc == NULL) { + PyErr_NoMemory(); + goto fail; + } + memcpy(tp_doc, old_doc, len); + type->tp_doc = tp_doc; + } + } + if (type->tp_dealloc == NULL) { + /* It's a heap type, so needs the heap types' dealloc. + subtype_dealloc will call the base type's tp_dealloc, if + necessary. */ + type->tp_dealloc = subtype_dealloc; + } + + if (PyType_Ready(type) < 0) + goto fail; + + // no ht_hached_keys in Python 2 + // if (type->tp_dictoffset) { + // res->ht_cached_keys = _PyDict_NewKeysForClass(); + // } + + /* Set type.__module__ */ + s = (char *)strrchr(spec->name, '.'); // c++11 + if (s != NULL) { + int err; + // was PyUnicode_FromStringAndSize in Python 3 + modname = PyString_FromStringAndSize( + spec->name, (Py_ssize_t)(s - spec->name)); + if (modname == NULL) { + goto fail; + } + // no PyId_ things in Python 2 + // err = _PyDict_SetItemId(type->tp_dict, &PyId___module__, modname); + err = PyDict_SetItemString(type->tp_dict, "__module__", modname); + Py_DECREF(modname); + if (err != 0) + goto fail; + } else { + // no PyErr_WarnFormat in Python 2 + // if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + // "builtin type %.200s has no __module__ attribute", + // spec->name)) + char msg[250]; + sprintf(msg, "builtin type %.200s has no __module__ attribute", spec->name); + if (PyErr_WarnEx(PyExc_DeprecationWarning, msg, 1)) + goto fail; + } + + return (PyObject*)res; + + fail: + Py_DECREF(res); + return NULL; +} + +PyObject * +PyType_FromSpec(PyType_Spec *spec) +{ + return PyType_FromSpecWithBases(spec, NULL); +} + +void * +PyType_GetSlot(PyTypeObject *type, int slot_) +{ + if (!PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE) || slot_ < 0) { + PyErr_BadInternalCall(); + return NULL; + } + if ((size_t)slot_ >= Py_ARRAY_LENGTH(slotoffsets)) { + /* Extension module requesting slot_ from a future version */ + return NULL; + } + return *(void**)(((char*)type) + slotoffsets[slot_]); +} + +} // extern "C" +#endif // PY_MAJOR_VERSION < 3 diff --git a/sources/shiboken2/libshiboken/typespec.h b/sources/shiboken2/libshiboken/typespec.h new file mode 100644 index 000000000..799fcb1b8 --- /dev/null +++ b/sources/shiboken2/libshiboken/typespec.h @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TYPESPEC_H +#define TYPESPEC_H + +#include <Python.h> +#include "shibokenmacros.h" + +#if PY_MAJOR_VERSION < 3 +extern "C" +{ + +typedef struct{ + int slot_; // slot is somehow reserved in Qt /* slot id, see below */ + void *pfunc; /* function pointer */ +} PyType_Slot; + +typedef struct{ + const char* name; + int basicsize; + int itemsize; + unsigned int flags; + PyType_Slot *slots; /* terminated by slot==0. */ +} PyType_Spec; + +LIBSHIBOKEN_API PyObject *PyType_FromSpec(PyType_Spec*); +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 +LIBSHIBOKEN_API PyObject *PyType_FromSpecWithBases(PyType_Spec*, PyObject*); +#endif +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03040000 +LIBSHIBOKEN_API void* PyType_GetSlot(PyTypeObject*, int); +#endif + +// from typeslots.h +/* Do not renumber the file; these numbers are part of the stable ABI. */ +/* Disabled, see #10181 */ +#undef Py_bf_getbuffer +#undef Py_bf_releasebuffer +#define Py_mp_ass_subscript 3 +#define Py_mp_length 4 +#define Py_mp_subscript 5 +#define Py_nb_absolute 6 +#define Py_nb_add 7 +#define Py_nb_and 8 +#define Py_nb_nonzero 9 +#define Py_nb_divmod 10 +#define Py_nb_float 11 +#define Py_nb_floor_divide 12 +#define Py_nb_index 13 +#define Py_nb_inplace_add 14 +#define Py_nb_inplace_and 15 +#define Py_nb_inplace_floor_divide 16 +#define Py_nb_inplace_lshift 17 +#define Py_nb_inplace_multiply 18 +#define Py_nb_inplace_or 19 +#define Py_nb_inplace_power 20 +#define Py_nb_inplace_remainder 21 +#define Py_nb_inplace_rshift 22 +#define Py_nb_inplace_subtract 23 +#define Py_nb_inplace_true_divide 24 +#define Py_nb_inplace_xor 25 +#define Py_nb_int 26 +#define Py_nb_invert 27 +#define Py_nb_lshift 28 +#define Py_nb_multiply 29 +#define Py_nb_negative 30 +#define Py_nb_or 31 +#define Py_nb_positive 32 +#define Py_nb_power 33 +#define Py_nb_remainder 34 +#define Py_nb_rshift 35 +#define Py_nb_subtract 36 +#define Py_nb_true_divide 37 +#define Py_nb_xor 38 +#define Py_sq_ass_item 39 +#define Py_sq_concat 40 +#define Py_sq_contains 41 +#define Py_sq_inplace_concat 42 +#define Py_sq_inplace_repeat 43 +#define Py_sq_item 44 +#define Py_sq_length 45 +#define Py_sq_repeat 46 +#define Py_tp_alloc 47 +#define Py_tp_base 48 +#define Py_tp_bases 49 +#define Py_tp_call 50 +#define Py_tp_clear 51 +#define Py_tp_dealloc 52 +#define Py_tp_del 53 +#define Py_tp_descr_get 54 +#define Py_tp_descr_set 55 +#define Py_tp_doc 56 +#define Py_tp_getattr 57 +#define Py_tp_getattro 58 +#define Py_tp_hash 59 +#define Py_tp_init 60 +#define Py_tp_is_gc 61 +#define Py_tp_iter 62 +#define Py_tp_iternext 63 +#define Py_tp_methods 64 +#define Py_tp_new 65 +#define Py_tp_repr 66 +#define Py_tp_richcompare 67 +#define Py_tp_setattr 68 +#define Py_tp_setattro 69 +#define Py_tp_str 70 +#define Py_tp_traverse 71 +#define Py_tp_members 72 +#define Py_tp_getset 73 +#define Py_tp_free 74 +#define Py_nb_long 75 +#define Py_nb_divide 76 +#define Py_sq_slice 77 +} // extern "C" +#endif // PY_MAJOR_VERSION < 3 +#endif // TYPESPEC_H diff --git a/sources/shiboken2/libshiboken/voidptr.cpp b/sources/shiboken2/libshiboken/voidptr.cpp index 790297595..afb3f4040 100644 --- a/sources/shiboken2/libshiboken/voidptr.cpp +++ b/sources/shiboken2/libshiboken/voidptr.cpp @@ -55,7 +55,8 @@ typedef struct { PyObject *SbkVoidPtrObject_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - SbkVoidPtrObject *self = reinterpret_cast<SbkVoidPtrObject *>(type->tp_alloc(type, 0)); + SbkVoidPtrObject *self = + reinterpret_cast<SbkVoidPtrObject *>(PepType(type)->tp_alloc); if (self != 0) { self->cptr = 0; @@ -66,7 +67,7 @@ PyObject *SbkVoidPtrObject_new(PyTypeObject *type, PyObject *args, PyObject *kwd return reinterpret_cast<PyObject *>(self); } -#define SbkVoidPtr_Check(op) (Py_TYPE(op) == &SbkVoidPtrType) +#define SbkVoidPtr_Check(op) (Py_TYPE(op) == SbkVoidPtrTypeF()) int SbkVoidPtrObject_init(PyObject *self, PyObject *args, PyObject *kwds) @@ -168,62 +169,6 @@ PyObject *SbkVoidPtrObject_int(PyObject *v) return PyLong_FromVoidPtr(sbkObject->cptr); } -static PyNumberMethods SbkVoidPtrObjectAsNumber = { - /* nb_add */ 0, - /* nb_subtract */ 0, - /* nb_multiply */ 0, -#ifndef IS_PY3K - /* nb_divide */ 0, -#endif - /* nb_remainder */ 0, - /* nb_divmod */ 0, - /* nb_power */ 0, - /* nb_negative */ 0, - /* nb_positive */ 0, - /* nb_absolute */ 0, - /* nb_bool/nb_nonzero */ 0, - /* nb_invert */ 0, - /* nb_lshift */ 0, - /* nb_rshift */ 0, - /* nb_and */ 0, - /* nb_xor */ 0, - /* nb_or */ 0, -#ifndef IS_PY3K - /* nb_coerce */ 0, -#endif - /* nb_int */ SbkVoidPtrObject_int, -#ifdef IS_PY3K - /* nb_reserved */ 0, - /* nb_float */ 0, -#else - /* nb_long */ 0, - /* nb_float */ 0, - /* nb_oct */ 0, - /* nb_hex */ 0, -#endif - - /* nb_inplace_add */ 0, - /* nb_inplace_subtract */ 0, - /* nb_inplace_multiply */ 0, -#ifndef IS_PY3K - /* nb_inplace_div */ 0, -#endif - /* nb_inplace_remainder */ 0, - /* nb_inplace_power */ 0, - /* nb_inplace_lshift */ 0, - /* nb_inplace_rshift */ 0, - /* nb_inplace_and */ 0, - /* nb_inplace_xor */ 0, - /* nb_inplace_or */ 0, - - /* nb_floor_divide */ 0, - /* nb_true_divide */ 0, - /* nb_inplace_floor_divide */ 0, - /* nb_inplace_true_divide */ 0, - - /* nb_index */ 0 -}; - static Py_ssize_t SbkVoidPtrObject_length(PyObject *v) { SbkVoidPtrObject *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v); @@ -235,19 +180,6 @@ static Py_ssize_t SbkVoidPtrObject_length(PyObject *v) return sbkObject->size; } -static PySequenceMethods SbkVoidPtrObjectAsSequence = { - /* sq_length */ SbkVoidPtrObject_length, - /* sq_concat */ 0, - /* sq_repeat */ 0, - /* sq_item */ 0, - /* sq_slice */ 0, - /* sq_ass_item */ 0, - /* sq_ass_slice */ 0, - /* sq_contains */ 0, - /* sq_inplace_concat */ 0, - /* sq_inplace_repeat */ 0 -}; - static const char trueString[] = "True" ; static const char falseString[] = "False" ; @@ -257,7 +189,7 @@ PyObject *SbkVoidPtrObject_repr(PyObject *v) SbkVoidPtrObject *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v); PyObject *s = PyBytes_FromFormat("%s(%p, %zd, %s)", - Py_TYPE(sbkObject)->tp_name, + PepType((Py_TYPE(sbkObject)))->tp_name, sbkObject->cptr, sbkObject->size, sbkObject->isWritable ? trueString : falseString); @@ -269,7 +201,7 @@ PyObject *SbkVoidPtrObject_str(PyObject *v) { SbkVoidPtrObject *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v); PyObject *s = PyBytes_FromFormat("%s(Address %p, Size %zd, isWritable %s)", - Py_TYPE(sbkObject)->tp_name, + PepType((Py_TYPE(sbkObject)))->tp_name, sbkObject->cptr, sbkObject->size, sbkObject->isWritable ? trueString : falseString); @@ -279,61 +211,35 @@ PyObject *SbkVoidPtrObject_str(PyObject *v) // Void pointer type definition. -PyTypeObject SbkVoidPtrType = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) /*ob_size*/ - "VoidPtr", /*tp_name*/ - sizeof(SbkVoidPtrObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - SbkVoidPtrObject_repr, /*tp_repr*/ - &SbkVoidPtrObjectAsNumber, /*tp_as_number*/ - &SbkVoidPtrObjectAsSequence, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - SbkVoidPtrObject_str, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "Void pointer wrapper", /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - SbkVoidPtrObject_richcmp, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - 0, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - SbkVoidPtrObject_init, /*tp_init*/ - 0, /*tp_alloc*/ - SbkVoidPtrObject_new, /*tp_new*/ - 0, /*tp_free*/ - 0, /*tp_is_gc*/ - 0, /*tp_bases*/ - 0, /*tp_mro*/ - 0, /*tp_cache*/ - 0, /*tp_subclasses*/ - 0, /*tp_weaklist*/ - 0, /*tp_del*/ - 0, /*tp_version_tag*/ -#if PY_MAJOR_VERSION > 3 || PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 4 - 0 /*tp_finalize*/ -#endif +static PyType_Slot SbkVoidPtrType_slots[] = { + {Py_tp_repr, (void *)SbkVoidPtrObject_repr}, + {Py_nb_int, (void *)SbkVoidPtrObject_int}, + {Py_sq_length, (void *)SbkVoidPtrObject_length}, + {Py_tp_str, (void *)SbkVoidPtrObject_str}, + {Py_tp_richcompare, (void *)SbkVoidPtrObject_richcmp}, + {Py_tp_init, (void *)SbkVoidPtrObject_init}, + {Py_tp_new, (void *)SbkVoidPtrObject_new}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} }; +static PyType_Spec SbkVoidPtrType_spec = { + "shiboken2.libshiboken.VoidPtr", + sizeof(SbkVoidPtrObject), + 0, + Py_TPFLAGS_DEFAULT, + SbkVoidPtrType_slots, +}; + } +PyTypeObject *SbkVoidPtrTypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) + type = (PyTypeObject *)PyType_FromSpec(&SbkVoidPtrType_spec); + return type; +} namespace VoidPtr { @@ -341,7 +247,7 @@ static int voidPointerInitialized = false; void init() { - if (PyType_Ready(reinterpret_cast<PyTypeObject *>(&SbkVoidPtrType)) < 0) + if (PyType_Ready(reinterpret_cast<PyTypeObject *>(SbkVoidPtrTypeF())) < 0) Py_FatalError("[libshiboken] Failed to initialize Shiboken.VoidPtr type."); else voidPointerInitialized = true; @@ -350,9 +256,9 @@ void init() void addVoidPtrToModule(PyObject *module) { if (voidPointerInitialized) { - Py_INCREF(&SbkVoidPtrType); - PyModule_AddObject(module, SbkVoidPtrType.tp_name, - reinterpret_cast<PyObject *>(&SbkVoidPtrType)); + Py_INCREF(SbkVoidPtrTypeF()); + PyModule_AddObject(module, PepType_GetNameStr(SbkVoidPtrTypeF()), + reinterpret_cast<PyObject *>(SbkVoidPtrTypeF())); } } @@ -361,7 +267,7 @@ static PyObject *createVoidPtr(void *cppIn, Py_ssize_t size = 0, bool isWritable if (!cppIn) Py_RETURN_NONE; - SbkVoidPtrObject *result = PyObject_NEW(SbkVoidPtrObject, &SbkVoidPtrType); + SbkVoidPtrObject *result = PyObject_New(SbkVoidPtrObject, SbkVoidPtrTypeF()); if (!result) Py_RETURN_NONE; @@ -434,7 +340,7 @@ static PythonToCppFunc PythonBufferToCppIsConvertible(PyObject *pyIn) SbkConverter *createConverter() { - SbkConverter *converter = Shiboken::Conversions::createConverter(&SbkVoidPtrType, toPython); + SbkConverter *converter = Shiboken::Conversions::createConverter(SbkVoidPtrTypeF(), toPython); Shiboken::Conversions::addPythonToCppValueConversion(converter, VoidPtrToCpp, VoidPtrToCppIsConvertible); diff --git a/sources/shiboken2/libshiboken/voidptr.h b/sources/shiboken2/libshiboken/voidptr.h index 240895df8..e74c1045e 100644 --- a/sources/shiboken2/libshiboken/voidptr.h +++ b/sources/shiboken2/libshiboken/voidptr.h @@ -40,7 +40,7 @@ #ifndef VOIDPTR_H #define VOIDPTR_H -#include <Python.h> +#include "sbkpython.h" #include "shibokenmacros.h" #include "sbkconverter.h" @@ -48,7 +48,7 @@ extern "C" { // Void pointer type declaration. -extern LIBSHIBOKEN_API PyTypeObject SbkVoidPtrType; +extern LIBSHIBOKEN_API PyTypeObject *SbkVoidPtrTypeF(void); } // extern "C" diff --git a/sources/shiboken2/tests/minimalbinding/CMakeLists.txt b/sources/shiboken2/tests/minimalbinding/CMakeLists.txt index 7edb0290a..b8b6417d1 100644 --- a/sources/shiboken2/tests/minimalbinding/CMakeLists.txt +++ b/sources/shiboken2/tests/minimalbinding/CMakeLists.txt @@ -26,7 +26,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} ${SBK_PYTHON_INCLUDE_DIR} ${libminimal_SOURCE_DIR} - ${libshiboken_SOURCE_DIR}) + ${libshiboken_SOURCE_DIR} + ${libshiboken_BINARY_DIR}) add_library(minimal MODULE ${minimal_SRC}) set_property(TARGET minimal PROPERTY PREFIX "") set_property(TARGET minimal PROPERTY OUTPUT_NAME "minimal${PYTHON_EXTENSION_SUFFIX}") diff --git a/sources/shiboken2/tests/otherbinding/CMakeLists.txt b/sources/shiboken2/tests/otherbinding/CMakeLists.txt index 7d4dd5b55..186766b41 100644 --- a/sources/shiboken2/tests/otherbinding/CMakeLists.txt +++ b/sources/shiboken2/tests/otherbinding/CMakeLists.txt @@ -32,7 +32,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${libsample_SOURCE_DIR}/.. ${sample_BINARY_DIR} ${sample_BINARY_DIR}/sample - ${libshiboken_SOURCE_DIR}) + ${libshiboken_SOURCE_DIR} + ${libshiboken_BINARY_DIR}) add_library(other MODULE ${other_SRC}) set_property(TARGET other PROPERTY PREFIX "") set_property(TARGET other PROPERTY OUTPUT_NAME "other${PYTHON_EXTENSION_SUFFIX}") diff --git a/sources/shiboken2/tests/samplebinding/CMakeLists.txt b/sources/shiboken2/tests/samplebinding/CMakeLists.txt index 78ddfca0a..32117e44a 100644 --- a/sources/shiboken2/tests/samplebinding/CMakeLists.txt +++ b/sources/shiboken2/tests/samplebinding/CMakeLists.txt @@ -136,7 +136,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} ${SBK_PYTHON_INCLUDE_DIR} ${libsample_SOURCE_DIR} - ${libshiboken_SOURCE_DIR}) + ${libshiboken_SOURCE_DIR} + ${libshiboken_BINARY_DIR}) add_library(sample MODULE ${sample_SRC}) set_property(TARGET sample PROPERTY PREFIX "") set_property(TARGET sample PROPERTY OUTPUT_NAME "sample${PYTHON_EXTENSION_SUFFIX}") diff --git a/sources/shiboken2/tests/samplebinding/bytearray_bufferprotocol.cpp b/sources/shiboken2/tests/samplebinding/bytearray_bufferprotocol.cpp index 8f01b4a0a..322387088 100644 --- a/sources/shiboken2/tests/samplebinding/bytearray_bufferprotocol.cpp +++ b/sources/shiboken2/tests/samplebinding/bytearray_bufferprotocol.cpp @@ -33,7 +33,7 @@ extern "C" { static Py_ssize_t SbkByteArray_segcountproc(PyObject* self, Py_ssize_t* lenp) { if (lenp) - *lenp = self->ob_type->tp_as_sequence->sq_length(self); + *lenp = Py_TYPE(self)->tp_as_sequence->sq_length(self); return 1; } static Py_ssize_t SbkByteArray_readbufferproc(PyObject* self, Py_ssize_t segment, void** ptrptr) diff --git a/sources/shiboken2/tests/samplebinding/namespace_test.py b/sources/shiboken2/tests/samplebinding/namespace_test.py index a5065c7a6..5fcdab974 100644 --- a/sources/shiboken2/tests/samplebinding/namespace_test.py +++ b/sources/shiboken2/tests/samplebinding/namespace_test.py @@ -33,12 +33,7 @@ import unittest from sample import * -from py3kcompat import IS_PY3K -if IS_PY3K: - TYPE_STR = "class" -else: - TYPE_STR = "type" class TestEnumUnderNamespace(unittest.TestCase): def testInvisibleNamespace(self): @@ -59,11 +54,16 @@ class TestClassesUnderNamespace(unittest.TestCase): self.assertEqual(res, 4) def testTpNames(self): - self.assertEqual(str(SampleNamespace.SomeClass), "<%s 'sample.SampleNamespace.SomeClass'>"%TYPE_STR) - self.assertEqual(str(SampleNamespace.SomeClass.ProtectedEnum), "<%s 'sample.SampleNamespace.SomeClass.ProtectedEnum'>"%TYPE_STR) - self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum), "<%s 'sample.SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum'>"%TYPE_STR) - self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough), "<%s 'sample.SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough'>"%TYPE_STR) - self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum), "<%s 'sample.SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum'>"%TYPE_STR) + self.assertEqual(str(SampleNamespace.SomeClass), + "<class 'sample.SampleNamespace.SomeClass'>") + self.assertEqual(str(SampleNamespace.SomeClass.ProtectedEnum), + "<class 'sample.SampleNamespace.SomeClass.ProtectedEnum'>") + self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum), + "<class 'sample.SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum'>") + self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough), + "<class 'sample.SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough'>") + self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum), + "<class 'sample.SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum'>") if __name__ == '__main__': unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml index 3cc80860d..5f0a9206b 100644 --- a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml +++ b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml @@ -1666,7 +1666,7 @@ Tested in InjectCodeTest.testTypeNativeBeginning_TypeTargetBeginning: --> <inject-code class="target" position="beginning"> - %PYTHONTYPEOBJECT.tp_str = InjectCode_tpstr; + PepType(&%PYTHONTYPEOBJECT)->tp_str = InjectCode_tpstr; </inject-code> <!-- Tested in InjectCodeTest.testFunctionTargetBeginning_FunctionTargetEnd --> @@ -2178,7 +2178,7 @@ </add-function> <add-function signature="__repr__" return-type="PyObject*"> <inject-code class="target" position="beginning"> - ByteArray b(((PyObject*)%PYSELF)->ob_type->tp_name); + ByteArray b(PepType(Py_TYPE(%PYSELF))->tp_name); PyObject* aux = Shiboken::String::fromStringAndSize(%CPPSELF.data(), %CPPSELF.size()); if (PyUnicode_CheckExact(aux)) { PyObject* tmp = PyUnicode_AsASCIIString(aux); diff --git a/sources/shiboken2/tests/smartbinding/CMakeLists.txt b/sources/shiboken2/tests/smartbinding/CMakeLists.txt index aab2121d3..faaa797b6 100644 --- a/sources/shiboken2/tests/smartbinding/CMakeLists.txt +++ b/sources/shiboken2/tests/smartbinding/CMakeLists.txt @@ -27,7 +27,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} ${SBK_PYTHON_INCLUDE_DIR} ${libsmart_SOURCE_DIR} - ${libshiboken_SOURCE_DIR}) + ${libshiboken_SOURCE_DIR} + ${libshiboken_BINARY_DIR}) add_library(smart MODULE ${smart_SRC}) set_property(TARGET smart PROPERTY PREFIX "") set_property(TARGET smart PROPERTY OUTPUT_NAME "smart${PYTHON_EXTENSION_SUFFIX}") |