30d29
< from __future__ import generators
34c33
< panic = m5.panic
---
> from m5 import panic
139a139,145
> def isSimObjectClass(value):
> try:
> return issubclass(value, SimObject)
> except TypeError:
> # happens if value is not a class at all
> return False
>
149a156,165
> def isSimObjClassSequence(value):
> if not isinstance(value, (list, tuple)):
> return False
>
> for val in value:
> if not isNullPointer(val) and not isSimObjectClass(val):
> return False
>
> return True
>
173,181c189,202
< # Copy "private" attributes (including special methods such as __new__)
< # to the official dict. Everything else goes in _init_dict to be
< # filtered in __init__.
< cls_dict = {}
< for key,val in dict.items():
< if key.startswith('_'):
< cls_dict[key] = val
< del dict[key]
< cls_dict['_init_dict'] = dict
---
> if dict.has_key('_init_dict'):
> # must have been called from makeSubclass() rather than
> # via Python class declaration; bypass filtering process.
> cls_dict = dict
> else:
> # Copy "private" attributes (including special methods
> # such as __new__) to the official dict. Everything else
> # goes in _init_dict to be filtered in __init__.
> cls_dict = {}
> for key,val in dict.items():
> if key.startswith('_'):
> cls_dict[key] = val
> del dict[key]
> cls_dict['_init_dict'] = dict
184c205
< # initialization
---
> # subclass initialization
185a207,208
> # calls type.__init__()... I think that's a no-op, but leave
> # it here just in case it's not.
199a223,224
> # the only time the following is not true is when we define
> # the SimObject class itself
204,220c229
< # If your parent has a value in it that's a config node, clone
< # it. Do this now so if we update any of the values'
< # attributes we are updating the clone and not the original.
< for key,val in base._values.iteritems():
<
< # don't clone if (1) we're about to overwrite it with
< # a local setting or (2) we've already cloned a copy
< # from an earlier (more derived) base
< if cls._init_dict.has_key(key) or cls._values.has_key(key):
< continue
<
< if isSimObject(val):
< cls._values[key] = val()
< elif isSimObjSequence(val) and len(val):
< cls._values[key] = [ v() for v in val ]
<
< # now process remaining _init_dict items
---
> # now process the _init_dict items
236a246,272
> # Pull the deep-copy memoization dict out of the class dict if
> # it's there...
> memo = cls.__dict__.get('_memo', {})
>
> # Handle SimObject values
> for key,val in cls._values.iteritems():
> # SimObject instances need to be promoted to classes.
> # Existing classes should not have any instance values, so
> # these can only occur at the lowest level dict (the
> # parameters just being set in this class definition).
> if isSimObject(val):
> assert(val == cls._values.local[key])
> cls._values[key] = val.makeClass(memo)
> elif isSimObjSequence(val) and len(val):
> assert(val == cls._values.local[key])
> cls._values[key] = [ v.makeClass(memo) for v in val ]
> # SimObject classes need to be subclassed so that
> # parameters that get set at this level only affect this
> # level and derivatives.
> elif isSimObjectClass(val):
> assert(not cls._values.local.has_key(key))
> cls._values[key] = val.makeSubclass({}, memo)
> elif isSimObjClassSequence(val) and len(val):
> assert(not cls._values.local.has_key(key))
> cls._values[key] = [ v.makeSubclass({}, memo) for v in val ]
>
>
286a323,338
> # Create a subclass of this class. Basically a function interface
> # to the standard Python class definition mechanism, primarily for
> # internal use. 'memo' dict param supports "deep copy" (really
> # "deep subclass") operations... within a given operation,
> # multiple references to a class should result in a single
> # subclass object with multiple references to it (as opposed to
> # mutiple unique subclasses).
> def makeSubclass(cls, init_dict, memo = {}):
> subcls = memo.get(cls)
> if not subcls:
> name = cls.__name__ + '_' + str(cls._anon_subclass_counter)
> cls._anon_subclass_counter += 1
> subcls = MetaSimObject(name, (cls,),
> { '_init_dict': init_dict, '_memo': memo })
> return subcls
>
295c347,388
< def __init__(self, _value_parent = None, **kwargs):
---
> # __new__ operator allocates new instances of the class. We
> # override it here just to support "deep instantiation" operation
> # via the _memo dict. When recursively instantiating an object
> # hierarchy we want to make sure that each class is instantiated
> # only once, and that if there are multiple references to the same
> # original class, we end up with the corresponding instantiated
> # references all pointing to the same instance.
> def __new__(cls, _memo = None, **kwargs):
> if _memo is not None and _memo.has_key(cls):
> # return previously instantiated object
> assert(len(kwargs) == 0)
> return _memo[cls]
> else:
> # Need a new one... if it needs to be memoized, this will
> # happen in __init__. We defer the insertion until then
> # so __init__ can use the memo dict to tell whether or not
> # to perform the initialization.
> return super(SimObject, cls).__new__(cls, **kwargs)
>
> # Initialize new instance previously allocated by __new__. For
> # objects with SimObject-valued params, we need to recursively
> # instantiate the classes represented by those param values as
> # well (in a consistent "deep copy"-style fashion; see comment
> # above).
> def __init__(self, _memo = None, **kwargs):
> if _memo is not None:
> # We're inside a "deep instantiation"
> assert(isinstance(_memo, dict))
> assert(len(kwargs) == 0)
> if _memo.has_key(self.__class__):
> # __new__ returned an existing, already initialized
> # instance, so there's nothing to do here
> assert(_memo[self.__class__] == self)
> return
> # no pre-existing object, so remember this one here
> _memo[self.__class__] = self
> else:
> # This is a new top-level instantiation... don't memoize
> # this objcet, but prepare to memoize any recursively
> # instantiated objects.
> _memo = {}
>
297,309c390,401
< if _value_parent and type(_value_parent) != type(self):
< # this was called as a type conversion rather than a clone
< raise TypeError, "Cannot convert %s to %s" % \
< (_value_parent.__class__.__name__, self.__class__.__name__)
< if not _value_parent:
< _value_parent = self.__class__
< # clone values
< self._values = multidict(_value_parent._values)
< for key,val in _value_parent._values.iteritems():
< if isSimObject(val):
< setattr(self, key, val())
< elif isSimObjSequence(val) and len(val):
< setattr(self, key, [ v() for v in val ])
---
> # Inherit parameter values from class using multidict so
> # individual value settings can be overridden.
> self._values = multidict(self.__class__._values)
> # For SimObject-valued parameters, the class should have
> # classes (not instances) for the values. We need to
> # instantiate these classes rather than just inheriting the
> # class object.
> for key,val in self.__class__._values.iteritems():
> if isSimObjectClass(val):
> setattr(self, key, val(_memo))
> elif isSimObjClassSequence(val) and len(val):
> setattr(self, key, [ v(_memo) for v in val ])
313a406,415
> # Use this instance as a template to create a new class.
> def makeClass(self, memo = {}):
> cls = memo.get(self)
> if not cls:
> cls = self.__class__.makeSubclass(self._values.local)
> memo[self] = cls
> return cls
>
> # Direct instantiation of instances (cloning) is no longer
> # allowed; must generate class from instance first.
315c417,418
< return self.__class__(_value_parent = self, **kwargs)
---
> raise TypeError, "cannot instantiate SimObject; "\
> "use makeClass() to make class first"
1072c1175,1178
< return self.addr
---
> if hasattr(self, 'addr'):
> return self.addr
> else:
> return "NextEthernetAddr (unresolved)"