X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fpython%2Fm5%2FSimObject.py;h=dca7d4095d34e008707f969dcd07aca4f767fe8b;hb=d00aa3658498968f7dc2b586347771734af0d24a;hp=97cf6d09688939fe6eb9689b9e7659b405d178fc;hpb=fa21127a646b8d2a61fe412728762250ca38ecd2;p=gem5.git diff --git a/src/python/m5/SimObject.py b/src/python/m5/SimObject.py index 97cf6d096..dca7d4095 100644 --- a/src/python/m5/SimObject.py +++ b/src/python/m5/SimObject.py @@ -44,6 +44,10 @@ # Andreas Sandberg from __future__ import print_function +from __future__ import absolute_import +import six +if six.PY3: + long = int import sys from types import FunctionType, MethodType, ModuleType @@ -168,10 +172,6 @@ def createCxxConfigDirectoryEntryFile(code, name, simobj, is_header): code('#include "base/str.hh"') code('#include "cxx_config/${name}.hh"') - if simobj._ports.values() != []: - code('#include "mem/mem_object.hh"') - code('#include "mem/port.hh"') - code() code('${member_prefix}DirectoryEntry::DirectoryEntry()'); code('{') @@ -411,6 +411,7 @@ class MetaSimObject(type): 'cxx_extra_bases' : list, 'cxx_exports' : list, 'cxx_param_exports' : list, + 'cxx_template_params' : list, } # Attributes that can be set any time keywords = { 'check' : FunctionType } @@ -450,6 +451,8 @@ class MetaSimObject(type): value_dict['cxx_exports'] += cxx_exports if 'cxx_param_exports' not in value_dict: value_dict['cxx_param_exports'] = [] + if 'cxx_template_params' not in value_dict: + value_dict['cxx_template_params'] = [] cls_dict['_value_dict'] = value_dict cls = super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict) if 'type' in value_dict: @@ -534,7 +537,7 @@ class MetaSimObject(type): cls._new_port(key, val) # init-time-only keywords - elif cls.init_keywords.has_key(key): + elif key in cls.init_keywords: cls._set_keyword(key, val, cls.init_keywords[key]) # default: use normal path (ends up in __setattr__) @@ -613,11 +616,11 @@ class MetaSimObject(type): type.__setattr__(cls, attr, value) return - if cls.keywords.has_key(attr): + if attr in cls.keywords: cls._set_keyword(attr, value, cls.keywords[attr]) return - if cls._ports.has_key(attr): + if attr in cls._ports: cls._cls_get_port_ref(attr).connect(value) return @@ -652,10 +655,10 @@ class MetaSimObject(type): if attr == 'cxx_namespaces': return cls.cxx_class_path[:-1] - if cls._values.has_key(attr): + if attr in cls._values: return cls._values[attr] - if cls._children.has_key(attr): + if attr in cls._children: return cls._children[attr] raise AttributeError( @@ -681,7 +684,7 @@ class MetaSimObject(type): # the object itself, not including inherited params (which # will also be inherited from the base class's param struct # here). Sort the params based on their key - params = map(lambda (k, v): v, sorted(cls._params.local.items())) + params = map(lambda k_v: k_v[1], sorted(cls._params.local.items())) ports = cls._ports.local code('''#include "pybind11/pybind11.h" @@ -726,7 +729,7 @@ module_init(py::module &m_internal) for k, v in sorted(cls._params.local.items()) ] + [ PyBindProperty("port_%s_connection_count" % port.name) - for port in ports.itervalues() + for port in ports.values() ] for exp in param_exports: exp.export(code, "%sParams" % cls) @@ -769,6 +772,7 @@ module_init(py::module &m_internal) code('static EmbeddedPyBind embed_obj("${0}", module_init, "${1}");', cls, cls._base.type if cls._base else "") + _warned_about_nested_templates = False # Generate the C++ declaration (.hh file) for this SimObject's # param struct. Called from src/SConscript. @@ -777,7 +781,7 @@ module_init(py::module &m_internal) # the object itself, not including inherited params (which # will also be inherited from the base class's param struct # here). Sort the params based on their key - params = map(lambda (k, v): v, sorted(cls._params.local.items())) + params = map(lambda k_v: k_v[1], sorted(cls._params.local.items())) ports = cls._ports.local try: ptypes = [p.ptype for p in params] @@ -786,7 +790,78 @@ module_init(py::module &m_internal) print(params) raise - class_path = cls._value_dict['cxx_class'].split('::') + class CxxClass(object): + def __init__(self, sig, template_params=[]): + # Split the signature into its constituent parts. This could + # potentially be done with regular expressions, but + # it's simple enough to pick appart a class signature + # manually. + parts = sig.split('<', 1) + base = parts[0] + t_args = [] + if len(parts) > 1: + # The signature had template arguments. + text = parts[1].rstrip(' \t\n>') + arg = '' + # Keep track of nesting to avoid splitting on ","s embedded + # in the arguments themselves. + depth = 0 + for c in text: + if c == '<': + depth = depth + 1 + if depth > 0 and not \ + self._warned_about_nested_templates: + self._warned_about_nested_templates = True + print('Nested template argument in cxx_class.' + ' This feature is largely untested and ' + ' may not work.') + elif c == '>': + depth = depth - 1 + elif c == ',' and depth == 0: + t_args.append(arg.strip()) + arg = '' + else: + arg = arg + c + if arg: + t_args.append(arg.strip()) + # Split the non-template part on :: boundaries. + class_path = base.split('::') + + # The namespaces are everything except the last part of the + # class path. + self.namespaces = class_path[:-1] + # And the class name is the last part. + self.name = class_path[-1] + + self.template_params = template_params + self.template_arguments = [] + # Iterate through the template arguments and their values. This + # will likely break if parameter packs are used. + for arg, param in zip(t_args, template_params): + type_keys = ('class', 'typename') + # If a parameter is a type, parse it recursively. Otherwise + # assume it's a constant, and store it verbatim. + if any(param.strip().startswith(kw) for kw in type_keys): + self.template_arguments.append(CxxClass(arg)) + else: + self.template_arguments.append(arg) + + def declare(self, code): + # First declare any template argument types. + for arg in self.template_arguments: + if isinstance(arg, CxxClass): + arg.declare(code) + # Re-open the target namespace. + for ns in self.namespaces: + code('namespace $ns {') + # If this is a class template... + if self.template_params: + code('template <${{", ".join(self.template_params)}}>') + # The actual class declaration. + code('class ${{self.name}};') + # Close the target namespaces. + for ns in reversed(self.namespaces): + code('} // namespace $ns') code('''\ #ifndef __PARAMS__${cls}__ @@ -802,18 +877,16 @@ module_init(py::module &m_internal) if cls == SimObject: code('''#include ''') + cxx_class = CxxClass(cls._value_dict['cxx_class'], + cls._value_dict['cxx_template_params']) + # A forward class declaration is sufficient since we are just # declaring a pointer. - for ns in class_path[:-1]: - code('namespace $ns {') - code('class $0;', class_path[-1]) - for ns in reversed(class_path[:-1]): - code('} // namespace $ns') - code() + cxx_class.declare(code) for param in params: param.cxx_predecls(code) - for port in ports.itervalues(): + for port in ports.values(): port.cxx_predecls(code) code() @@ -846,7 +919,7 @@ module_init(py::module &m_internal) for param in params: param.cxx_decl(code) - for port in ports.itervalues(): + for port in ports.values(): port.cxx_decl(code) code.dedent() @@ -875,9 +948,10 @@ def cxxMethod(*args, **kwargs): """Decorator to export C++ functions to Python""" def decorate(func): - name = func.func_name + name = func.__name__ override = kwargs.get("override", False) cxx_name = kwargs.get("cxx_name", name) + return_value_policy = kwargs.get("return_value_policy", None) args, varargs, keywords, defaults = inspect.getargspec(func) if varargs or keywords: @@ -886,7 +960,8 @@ def cxxMethod(*args, **kwargs): # Create tuples of (argument, default) if defaults: - args = args[:-len(defaults)] + zip(args[-len(defaults):], defaults) + args = args[:-len(defaults)] + \ + list(zip(args[-len(defaults):], defaults)) # Don't include self in the argument list to PyBind args = args[1:] @@ -901,7 +976,8 @@ def cxxMethod(*args, **kwargs): return func(self, *args, **kwargs) f = py_call if override else cxx_call - f.__pybind = PyBindMethod(name, cxx_name=cxx_name, args=args) + f.__pybind = PyBindMethod(name, cxx_name=cxx_name, args=args, + return_value_policy=return_value_policy) return f @@ -1118,7 +1194,7 @@ class SimObject(object): # Do children before parameter values so that children that # are also param values get cloned properly. self._children = {} - for key,val in ancestor._children.iteritems(): + for key,val in ancestor._children.items(): self.add_child(key, val(_memo=memo_dict)) # Inherit parameter values from class using multidict so @@ -1127,7 +1203,7 @@ class SimObject(object): self._values = multidict(ancestor._values) self._hr_values = multidict(ancestor._hr_values) # clone SimObject-valued parameters - for key,val in ancestor._values.iteritems(): + for key,val in ancestor._values.items(): val = tryAsSimObjectOrVector(val) if val is not None: self._values[key] = val(_memo=memo_dict) @@ -1135,10 +1211,10 @@ class SimObject(object): # clone port references. no need to use a multidict here # since we will be creating new references for all ports. self._port_refs = {} - for key,val in ancestor._port_refs.iteritems(): + for key,val in ancestor._port_refs.items(): self._port_refs[key] = val.clone(self, memo_dict) # apply attribute assignments from keyword args, if any - for key,val in kwargs.iteritems(): + for key,val in kwargs.items(): setattr(self, key, val) # "Clone" the current instance by creating another instance of @@ -1158,7 +1234,7 @@ class SimObject(object): # create a new dict and use that. memo_dict = {} kwargs['_memo'] = memo_dict - elif memo_dict.has_key(self): + elif self in memo_dict: # clone already done & memoized return memo_dict[self] return self.__class__(_ancestor = self, **kwargs) @@ -1174,13 +1250,13 @@ class SimObject(object): return ref def __getattr__(self, attr): - if self._ports.has_key(attr): + if attr in self._ports: return self._get_port_ref(attr) - if self._values.has_key(attr): + if attr in self._values: return self._values[attr] - if self._children.has_key(attr): + if attr in self._children: return self._children[attr] # If the attribute exists on the C++ object, transparently @@ -1206,7 +1282,7 @@ class SimObject(object): object.__setattr__(self, attr, value) return - if self._ports.has_key(attr): + if attr in self._ports: # set up port connection self._get_port_ref(attr).connect(value) return @@ -1294,7 +1370,7 @@ class SimObject(object): if child.has_parent(): warn("add_child('%s'): child '%s' already has parent", name, child.get_name()) - if self._children.has_key(name): + if name in self._children: # This code path had an undiscovered bug that would make it fail # at runtime. It had been here for a long time and was only # exposed by a buggy script. Changes here will probably not be @@ -1310,7 +1386,7 @@ class SimObject(object): # that when we instantiate all the parameter objects we're still # inside the configuration hierarchy. def adoptOrphanParams(self): - for key,val in self._values.iteritems(): + for key,val in self._values.items(): if not isSimObjectVector(val) and isSimObjectSequence(val): # need to convert raw SimObject sequences to # SimObjectVector class so we can call has_parent() @@ -1345,7 +1421,7 @@ class SimObject(object): return self, True found_obj = None - for child in self._children.itervalues(): + for child in self._children.values(): visited = False if hasattr(child, '_visited'): visited = getattr(child, '_visited') @@ -1357,7 +1433,7 @@ class SimObject(object): (found_obj.path, child.path)) found_obj = child # search param space - for pname,pdesc in self._params.iteritems(): + for pname,pdesc in self._params.items(): if issubclass(pdesc.ptype, ptype): match_obj = self._values[pname] if found_obj != None and found_obj != match_obj: @@ -1370,7 +1446,7 @@ class SimObject(object): def find_all(self, ptype): all = {} # search children - for child in self._children.itervalues(): + for child in self._children.values(): # a child could be a list, so ensure we visit each item if isinstance(child, list): children = child @@ -1386,7 +1462,7 @@ class SimObject(object): child_all, done = child.find_all(ptype) all.update(dict(zip(child_all, [done] * len(child_all)))) # search param space - for pname,pdesc in self._params.iteritems(): + for pname,pdesc in self._params.items(): if issubclass(pdesc.ptype, ptype): match_obj = self._values[pname] if not isproxy(match_obj) and not isNullPointer(match_obj): @@ -1399,7 +1475,7 @@ class SimObject(object): return self def unproxyParams(self): - for param in self._params.iterkeys(): + for param in self._params.keys(): value = self._values.get(param) if value != None and isproxy(value): try: @@ -1412,7 +1488,7 @@ class SimObject(object): # Unproxy ports in sorted order so that 'append' operations on # vector ports are done in a deterministic fashion. - port_names = self._ports.keys() + port_names = list(self._ports.keys()) port_names.sort() for port_name in port_names: port = self._port_refs.get(port_name) @@ -1489,7 +1565,7 @@ class SimObject(object): cc_params = cc_params_struct() cc_params.name = str(self) - param_names = self._params.keys() + param_names = list(self._params.keys()) param_names.sort() for param in param_names: value = self._values.get(param) @@ -1513,7 +1589,7 @@ class SimObject(object): else: setattr(cc_params, param, value) - port_names = self._ports.keys() + port_names = list(self._ports.keys()) port_names.sort() for port_name in port_names: port = self._port_refs.get(port_name, None) @@ -1550,7 +1626,7 @@ class SimObject(object): # The order of the dict is implementation dependent, so sort # it based on the key (name) to ensure the order is the same # on all hosts - for (name, child) in sorted(self._children.iteritems()): + for (name, child) in sorted(self._children.items()): for obj in child.descendants(): yield obj @@ -1562,12 +1638,16 @@ class SimObject(object): def getValue(self): return self.getCCObject() + @cxxMethod(return_value_policy="reference") + def getPort(self, if_name, idx): + pass + # Create C++ port connections corresponding to the connections in # _port_refs def connectPorts(self): # Sort the ports based on their attribute name to ensure the # order is the same on all hosts - for (attr, portRef) in sorted(self._port_refs.iteritems()): + for (attr, portRef) in sorted(self._port_refs.items()): portRef.ccConnect() # Default function for generating the device structure. @@ -1577,7 +1657,7 @@ class SimObject(object): yield # make this function a (null) generator def recurseDeviceTree(self, state): - for child in self._children.itervalues(): + for child in self._children.values(): for item in child: # For looping over SimObjectVectors for dt in item.generateDeviceTree(state): yield dt