arch-arm, dev-arm: Remove Python 2 compatibility code
[gem5.git] / src / sim / init.cc
index f2395eec4f82f3c85006a165f30ede31cac48bc6..73d4dbd703e76619abdfc3f0bef1f4cde5e5f4b2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 ARM Limited
+ * Copyright (c) 2012, 2017 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -37,8 +37,6 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
  */
 
 #include <Python.h>
 #include <iostream>
 #include <list>
 #include <string>
+#include <vector>
 
+#include "base/compiler.hh"
 #include "base/cprintf.hh"
-#include "base/misc.hh"
+#include "base/logging.hh"
 #include "base/types.hh"
 #include "config/have_protobuf.hh"
+#include "python/pybind11/pybind.hh"
 #include "sim/async.hh"
 #include "sim/core.hh"
 
@@ -65,6 +66,7 @@
 #endif
 
 using namespace std;
+namespace py = pybind11;
 
 // The python library is totally messed up with respect to constness,
 // so make a simple macro to make life a little easier
@@ -125,8 +127,7 @@ EmbeddedPython::addModule() const
 }
 
 /*
- * Load and initialize all of the python parts of M5, including Swig
- * and the embedded module importer.
+ * Load and initialize all of the python parts of M5.
  */
 int
 EmbeddedPython::initAll()
@@ -150,52 +151,102 @@ EmbeddedPython::initAll()
     return 0;
 }
 
-EmbeddedSwig::EmbeddedSwig(void (*init_func)(), const string& _context)
-    : initFunc(init_func), context(_context)
+EmbeddedPyBind::EmbeddedPyBind(const char *_name,
+                               void (*init_func)(py::module &),
+                               const char *_base)
+    : initFunc(init_func), registered(false), name(_name), base(_base)
 {
-    getList().push_back(this);
+    getMap()[_name] = this;
 }
 
-list<EmbeddedSwig *> &
-EmbeddedSwig::getList()
+EmbeddedPyBind::EmbeddedPyBind(const char *_name,
+                               void (*init_func)(py::module &))
+    : initFunc(init_func), registered(false), name(_name), base("")
 {
-    static list<EmbeddedSwig *> the_list;
-    return the_list;
+    getMap()[_name] = this;
 }
 
 void
-EmbeddedSwig::initAll()
+EmbeddedPyBind::init(py::module &m)
 {
-    char* old_context = _Py_PackageContext;
-    // initialize SWIG modules. initFunc() is autogenerated and calls
-    // all of the individual swig initialization functions.
-    for (auto i : getList()) {
-        // to ensure that the loaded modules are placed in the right
-        // package we have to be a bit unorthodox and directly
-        // manipulate the package context since swig simply calls
-        // Py_InitModule with nothing but the module name of the
-        // wrapper
-        char* cstr = new char[i->context.size() + 1];
-        strcpy(cstr, i->context.c_str());
-        _Py_PackageContext = cstr;
-        i->initFunc();
-        delete[] cstr;
+    if (!registered) {
+        initFunc(m);
+        registered = true;
+    } else {
+        cprintf("Warning: %s already registered.\n", name);
     }
-    _Py_PackageContext = old_context;
 }
 
-int
-initM5Python()
+bool
+EmbeddedPyBind::depsReady() const
+{
+    return base.empty() || getMap()[base]->registered;
+}
+
+std::map<std::string, EmbeddedPyBind *> &
+EmbeddedPyBind::getMap()
+{
+    static std::map<std::string, EmbeddedPyBind *> objs;
+    return objs;
+}
+
+#if PY_MAJOR_VERSION >= 3
+PyObject *
+#else
+void
+#endif
+EmbeddedPyBind::initAll()
+{
+    std::list<EmbeddedPyBind *> pending;
+
+    py::module m_m5 = py::module("_m5");
+    m_m5.attr("__package__") = py::cast("_m5");
+
+    pybind_init_core(m_m5);
+    pybind_init_debug(m_m5);
+
+    pybind_init_event(m_m5);
+    pybind_init_stats(m_m5);
+
+    for (auto &kv : getMap()) {
+        auto &obj = kv.second;
+        if (obj->base.empty()) {
+            obj->init(m_m5);
+        } else {
+            pending.push_back(obj);
+        }
+    }
+
+    while (!pending.empty()) {
+        for (auto it = pending.begin(); it != pending.end(); ) {
+            EmbeddedPyBind &obj = **it;
+            if (obj.depsReady()) {
+                obj.init(m_m5);
+                it = pending.erase(it);
+            } else {
+                ++it;
+            }
+        }
+    }
+
+#if PY_MAJOR_VERSION >= 3
+    return m_m5.ptr();
+#endif
+}
+
+void
+registerNativeModules()
 {
-    EmbeddedSwig::initAll();
-    return EmbeddedPython::initAll();
+    auto result = PyImport_AppendInittab("_m5", EmbeddedPyBind::initAll);
+    if (result == -1)
+        panic("Failed to add _m5 to Python's inittab\n");
 }
 
 /*
  * Make the commands array weak so that they can be overridden (used
  * by unit tests to specify a different python main function.
  */
-const char * __attribute__((weak)) m5MainCommands[] = {
+M5_WEAK const char *m5MainCommands[] = {
     "import m5",
     "m5.main()",
     0 // sentinel is required
@@ -206,7 +257,7 @@ const char * __attribute__((weak)) m5MainCommands[] = {
  * main function.
  */
 int
-m5Main(int argc, char **argv)
+m5Main(int argc, char **_argv)
 {
 #if HAVE_PROTOBUF
     // Verify that the version of the protobuf library that we linked
@@ -215,6 +266,23 @@ m5Main(int argc, char **argv)
     GOOGLE_PROTOBUF_VERIFY_VERSION;
 #endif
 
+
+#if PY_MAJOR_VERSION >= 3
+    typedef std::unique_ptr<wchar_t[], decltype(&PyMem_RawFree)> WArgUPtr;
+    std::vector<WArgUPtr> v_argv;
+    std::vector<wchar_t *> vp_argv;
+    v_argv.reserve(argc);
+    vp_argv.reserve(argc);
+    for (int i = 0; i < argc; i++) {
+        v_argv.emplace_back(Py_DecodeLocale(_argv[i], NULL), &PyMem_RawFree);
+        vp_argv.emplace_back(v_argv.back().get());
+    }
+
+    wchar_t **argv = vp_argv.data();
+#else
+    char **argv = _argv;
+#endif
+
     PySys_SetArgv(argc, argv);
 
     // We have to set things up in the special __main__ module
@@ -246,10 +314,3 @@ m5Main(int argc, char **argv)
 
     return 0;
 }
-
-PyMODINIT_FUNC
-initm5(void)
-{
-    initM5Python();
-    PyImport_ImportModule(PyCC("m5"));
-}