init.cc revision 12334
12623SN/A/*
22623SN/A * Copyright (c) 2012, 2017 ARM Limited
32623SN/A * All rights reserved
42623SN/A *
52623SN/A * The license below extends only to copyright in the software and shall
62623SN/A * not be construed as granting a license to any other intellectual
72623SN/A * property including but not limited to intellectual property relating
82623SN/A * to a hardware implementation of the functionality of the software
92623SN/A * licensed hereunder.  You may use the software subject to the license
102623SN/A * terms below provided that you ensure that this notice is replicated
112623SN/A * unmodified and in its entirety in all distributions of the software,
122623SN/A * modified or unmodified, in source code or in binary form.
132623SN/A *
142623SN/A * Copyright (c) 2000-2005 The Regents of The University of Michigan
152623SN/A * Copyright (c) 2008 The Hewlett-Packard Development Company
162623SN/A * All rights reserved.
172623SN/A *
182623SN/A * Redistribution and use in source and binary forms, with or without
192623SN/A * modification, are permitted provided that the following conditions are
202623SN/A * met: redistributions of source code must retain the above copyright
212623SN/A * notice, this list of conditions and the following disclaimer;
222623SN/A * redistributions in binary form must reproduce the above copyright
232623SN/A * notice, this list of conditions and the following disclaimer in the
242623SN/A * documentation and/or other materials provided with the distribution;
252623SN/A * neither the name of the copyright holders nor the names of its
262623SN/A * contributors may be used to endorse or promote products derived from
272665Ssaidi@eecs.umich.edu * this software without specific prior written permission.
282665Ssaidi@eecs.umich.edu *
292623SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
302623SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
312623SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
322623SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
332623SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
342623SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
352623SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
362623SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
372623SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
382623SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
392623SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
402623SN/A *
412623SN/A * Authors: Nathan Binkert
422623SN/A */
432623SN/A
442623SN/A#include <Python.h>
452623SN/A
462623SN/A#include "sim/init.hh"
472623SN/A
482623SN/A#include <marshal.h>
492623SN/A#include <zlib.h>
502623SN/A
512623SN/A#include <iostream>
522623SN/A#include <list>
532623SN/A#include <string>
542623SN/A
552623SN/A#include "base/cprintf.hh"
562623SN/A#include "base/logging.hh"
572623SN/A#include "base/types.hh"
582623SN/A#include "config/have_protobuf.hh"
592623SN/A#include "python/pybind11/pybind.hh"
602623SN/A#include "sim/async.hh"
612623SN/A#include "sim/core.hh"
622623SN/A
632623SN/A#if HAVE_PROTOBUF
642623SN/A#include <google/protobuf/stubs/common.h>
652623SN/A
662623SN/A#endif
672623SN/A
682623SN/Ausing namespace std;
692623SN/Anamespace py = pybind11;
702623SN/A
712623SN/A// The python library is totally messed up with respect to constness,
722623SN/A// so make a simple macro to make life a little easier
732623SN/A#define PyCC(x) (const_cast<char *>(x))
742623SN/A
752623SN/AEmbeddedPython *EmbeddedPython::importer = NULL;
762623SN/APyObject *EmbeddedPython::importerModule = NULL;
772623SN/AEmbeddedPython::EmbeddedPython(const char *filename, const char *abspath,
782623SN/A    const char *modpath, const unsigned char *code, int zlen, int len)
792623SN/A    : filename(filename), abspath(abspath), modpath(modpath), code(code),
802623SN/A      zlen(zlen), len(len)
812623SN/A{
822623SN/A    // if we've added the importer keep track of it because we need it
832630SN/A    // to bootstrap.
842623SN/A    if (string(modpath) == string("importer"))
852623SN/A        importer = this;
862623SN/A    else
872623SN/A        getList().push_back(this);
882623SN/A}
892623SN/A
902630SN/Alist<EmbeddedPython *> &
912623SN/AEmbeddedPython::getList()
922623SN/A{
932623SN/A    static list<EmbeddedPython *> the_list;
942623SN/A    return the_list;
952623SN/A}
962623SN/A
972630SN/A/*
982623SN/A * Uncompress and unmarshal the code object stored in the
992623SN/A * EmbeddedPython
1002623SN/A */
1012623SN/APyObject *
1022623SN/AEmbeddedPython::getCode() const
1032623SN/A{
1042623SN/A    Bytef marshalled[len];
1052626SN/A    uLongf unzlen = len;
1062626SN/A    int ret = uncompress(marshalled, &unzlen, (const Bytef *)code, zlen);
1072626SN/A    if (ret != Z_OK)
1082623SN/A        panic("Could not uncompress code: %s\n", zError(ret));
1092623SN/A    assert(unzlen == (uLongf)len);
1102623SN/A
1112657Ssaidi@eecs.umich.edu    return PyMarshal_ReadObjectFromString((char *)marshalled, len);
1122623SN/A}
1132623SN/A
1142623SN/Abool
1152623SN/AEmbeddedPython::addModule() const
1162623SN/A{
1172623SN/A    PyObject *code = getCode();
1182623SN/A    PyObject *result = PyObject_CallMethod(importerModule, PyCC("add_module"),
1192623SN/A        PyCC("sssO"), filename, abspath, modpath, code);
1202623SN/A    if (!result) {
1212640Sstever@eecs.umich.edu        PyErr_Print();
1222623SN/A        return false;
1232623SN/A    }
1242623SN/A
1252663Sstever@eecs.umich.edu    Py_DECREF(result);
1262663Sstever@eecs.umich.edu    return true;
1272641Sstever@eecs.umich.edu}
1282623SN/A
1292623SN/A/*
1302663Sstever@eecs.umich.edu * Load and initialize all of the python parts of M5.
1312641Sstever@eecs.umich.edu */
1322641Sstever@eecs.umich.eduint
1332623SN/AEmbeddedPython::initAll()
1342623SN/A{
1352663Sstever@eecs.umich.edu    // Load the importer module
1362641Sstever@eecs.umich.edu    PyObject *code = importer->getCode();
1372641Sstever@eecs.umich.edu    importerModule = PyImport_ExecCodeModule(PyCC("importer"), code);
1382623SN/A    if (!importerModule) {
1392623SN/A        PyErr_Print();
1402623SN/A        return 1;
1412623SN/A    }
1422623SN/A
1432623SN/A    // Load the rest of the embedded python files into the embedded
1442623SN/A    // python importer
1452623SN/A    list<EmbeddedPython *>::iterator i = getList().begin();
1462623SN/A    list<EmbeddedPython *>::iterator end = getList().end();
1472623SN/A    for (; i != end; ++i)
1482623SN/A        if (!(*i)->addModule())
1492623SN/A            return 1;
1502623SN/A
1512623SN/A    return 0;
1522623SN/A}
1532623SN/A
1542623SN/AEmbeddedPyBind::EmbeddedPyBind(const char *_name,
1552623SN/A                               void (*init_func)(py::module &),
1562623SN/A                               const char *_base)
1572623SN/A    : initFunc(init_func), registered(false), name(_name), base(_base)
1582623SN/A{
1592623SN/A    getMap()[_name] = this;
1602623SN/A}
1612623SN/A
1622623SN/AEmbeddedPyBind::EmbeddedPyBind(const char *_name,
1632623SN/A                               void (*init_func)(py::module &))
1642623SN/A    : initFunc(init_func), registered(false), name(_name), base("")
1652623SN/A{
1662623SN/A    getMap()[_name] = this;
1672623SN/A}
1682623SN/A
1692623SN/Avoid
1702623SN/AEmbeddedPyBind::init(py::module &m)
1712623SN/A{
1722623SN/A    if (!registered) {
1732623SN/A        initFunc(m);
1742623SN/A        registered = true;
1752623SN/A    } else {
1762623SN/A        cprintf("Warning: %s already registered.\n", name);
1772623SN/A    }
1782623SN/A}
1792623SN/A
1802623SN/Abool
1812623SN/AEmbeddedPyBind::depsReady() const
1822623SN/A{
1832623SN/A    return base.empty() || getMap()[base]->registered;
1842623SN/A}
1852623SN/A
1862623SN/Astd::map<std::string, EmbeddedPyBind *> &
1872623SN/AEmbeddedPyBind::getMap()
1882623SN/A{
1892623SN/A    static std::map<std::string, EmbeddedPyBind *> objs;
1902623SN/A    return objs;
1912623SN/A}
1922623SN/A
1932623SN/Avoid
1942623SN/AEmbeddedPyBind::initAll()
1952623SN/A{
1962623SN/A    std::list<EmbeddedPyBind *> pending;
1972623SN/A
1982623SN/A    py::module m_m5 = py::module("_m5");
1992623SN/A    m_m5.attr("__package__") = py::cast("_m5");
2002623SN/A
2012623SN/A    pybind_init_core(m_m5);
2022623SN/A    pybind_init_debug(m_m5);
2032623SN/A
2042623SN/A    pybind_init_event(m_m5);
2052623SN/A    pybind_init_pyobject(m_m5);
2062623SN/A    pybind_init_stats(m_m5);
2072623SN/A
2082623SN/A    for (auto &kv : getMap()) {
2092623SN/A        auto &obj = kv.second;
2102623SN/A        if (obj->base.empty()) {
2112623SN/A            obj->init(m_m5);
2122623SN/A        } else {
2132623SN/A            pending.push_back(obj);
2142623SN/A        }
2152623SN/A    }
2162623SN/A
2172626SN/A    while (!pending.empty()) {
2182626SN/A        for (auto it = pending.begin(); it != pending.end(); ) {
2192626SN/A            EmbeddedPyBind &obj = **it;
2202626SN/A            if (obj.depsReady()) {
2212626SN/A                obj.init(m_m5);
2222623SN/A                it = pending.erase(it);
2232623SN/A            } else {
2242623SN/A                ++it;
2252623SN/A            }
2262623SN/A        }
2272623SN/A    }
2282623SN/A}
2292623SN/A
2302623SN/Aint
2312623SN/AinitM5Python()
2322663Sstever@eecs.umich.edu{
2332623SN/A    EmbeddedPyBind::initAll();
2342623SN/A    return EmbeddedPython::initAll();
2352623SN/A}
2362623SN/A
2372623SN/A/*
2382623SN/A * Make the commands array weak so that they can be overridden (used
2392623SN/A * by unit tests to specify a different python main function.
2402623SN/A */
2412623SN/Aconst char * __attribute__((weak)) m5MainCommands[] = {
2422623SN/A    "import m5",
2432641Sstever@eecs.umich.edu    "m5.main()",
2442623SN/A    0 // sentinel is required
2452662Sstever@eecs.umich.edu};
2462623SN/A
2472623SN/A/*
2482641Sstever@eecs.umich.edu * Start up the M5 simulator.  This mostly vectors into the python
2492623SN/A * main function.
2502623SN/A */
2512623SN/Aint
2522623SN/Am5Main(int argc, char **argv)
2532623SN/A{
2542623SN/A#if HAVE_PROTOBUF
2552623SN/A    // Verify that the version of the protobuf library that we linked
2562623SN/A    // against is compatible with the version of the headers we
2572623SN/A    // compiled against.
2582623SN/A    GOOGLE_PROTOBUF_VERIFY_VERSION;
2592623SN/A#endif
2602623SN/A
2612623SN/A    PySys_SetArgv(argc, argv);
2622623SN/A
2632623SN/A    // We have to set things up in the special __main__ module
2642623SN/A    PyObject *module = PyImport_AddModule(PyCC("__main__"));
2652623SN/A    if (module == NULL)
2662623SN/A        panic("Could not import __main__");
2672623SN/A    PyObject *dict = PyModule_GetDict(module);
2682623SN/A
2692623SN/A    // import the main m5 module
2702623SN/A    PyObject *result;
2712623SN/A    const char **command = m5MainCommands;
2722623SN/A
2732623SN/A    // evaluate each command in the m5MainCommands array (basically a
2742623SN/A    // bunch of python statements.
2752623SN/A    while (*command) {
2762623SN/A        result = PyRun_String(*command, Py_file_input, dict, dict);
2772623SN/A        if (!result) {
2782623SN/A            PyErr_Print();
2792623SN/A            return 1;
2802623SN/A        }
2812623SN/A        Py_DECREF(result);
2822623SN/A
2832623SN/A        command++;
2842623SN/A    }
2852623SN/A
2862623SN/A#if HAVE_PROTOBUF
2872623SN/A    google::protobuf::ShutdownProtobufLibrary();
2882623SN/A#endif
2892623SN/A
2902623SN/A    return 0;
2912623SN/A}
2922623SN/A
2932623SN/APyMODINIT_FUNC
2942623SN/Ainitm5(void)
2952623SN/A{
2962623SN/A    initM5Python();
2972623SN/A    PyImport_ImportModule(PyCC("m5"));
2982623SN/A}
2992623SN/A