proxy.py revision 3109
13101Sstever@eecs.umich.edu# Copyright (c) 2004-2006 The Regents of The University of Michigan 23101Sstever@eecs.umich.edu# All rights reserved. 33101Sstever@eecs.umich.edu# 43101Sstever@eecs.umich.edu# Redistribution and use in source and binary forms, with or without 53101Sstever@eecs.umich.edu# modification, are permitted provided that the following conditions are 63101Sstever@eecs.umich.edu# met: redistributions of source code must retain the above copyright 73101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer; 83101Sstever@eecs.umich.edu# redistributions in binary form must reproduce the above copyright 93101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the 103101Sstever@eecs.umich.edu# documentation and/or other materials provided with the distribution; 113101Sstever@eecs.umich.edu# neither the name of the copyright holders nor the names of its 123101Sstever@eecs.umich.edu# contributors may be used to endorse or promote products derived from 133101Sstever@eecs.umich.edu# this software without specific prior written permission. 143101Sstever@eecs.umich.edu# 153101Sstever@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 163101Sstever@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 173101Sstever@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 183101Sstever@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 193101Sstever@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 203101Sstever@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 213101Sstever@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 223101Sstever@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 233101Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 243101Sstever@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 253101Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 263101Sstever@eecs.umich.edu# 273101Sstever@eecs.umich.edu# Authors: Steve Reinhardt 283101Sstever@eecs.umich.edu# Nathan Binkert 293101Sstever@eecs.umich.edu 303101Sstever@eecs.umich.edu##################################################################### 313101Sstever@eecs.umich.edu# 323101Sstever@eecs.umich.edu# Proxy object support. 333101Sstever@eecs.umich.edu# 343101Sstever@eecs.umich.edu##################################################################### 353101Sstever@eecs.umich.edu 363101Sstever@eecs.umich.educlass BaseProxy(object): 373101Sstever@eecs.umich.edu def __init__(self, search_self, search_up): 383101Sstever@eecs.umich.edu self._search_self = search_self 393101Sstever@eecs.umich.edu self._search_up = search_up 403101Sstever@eecs.umich.edu self._multiplier = None 413101Sstever@eecs.umich.edu 423109Sstever@eecs.umich.edu def __str__(self): 433109Sstever@eecs.umich.edu if self._search_self and not self._search_up: 443109Sstever@eecs.umich.edu s = 'Self' 453109Sstever@eecs.umich.edu elif not self._search_self and self._search_up: 463109Sstever@eecs.umich.edu s = 'Parent' 473109Sstever@eecs.umich.edu else: 483109Sstever@eecs.umich.edu s = 'ConfusedProxy' 493109Sstever@eecs.umich.edu return s + '.' + self.path() 503109Sstever@eecs.umich.edu 513101Sstever@eecs.umich.edu def __setattr__(self, attr, value): 523101Sstever@eecs.umich.edu if not attr.startswith('_'): 533105Sstever@eecs.umich.edu raise AttributeError, \ 543105Sstever@eecs.umich.edu "cannot set attribute '%s' on proxy object" % attr 553101Sstever@eecs.umich.edu super(BaseProxy, self).__setattr__(attr, value) 563101Sstever@eecs.umich.edu 573101Sstever@eecs.umich.edu # support multiplying proxies by constants 583101Sstever@eecs.umich.edu def __mul__(self, other): 593101Sstever@eecs.umich.edu if not isinstance(other, (int, long, float)): 603101Sstever@eecs.umich.edu raise TypeError, "Proxy multiplier must be integer" 613101Sstever@eecs.umich.edu if self._multiplier == None: 623101Sstever@eecs.umich.edu self._multiplier = other 633101Sstever@eecs.umich.edu else: 643101Sstever@eecs.umich.edu # support chained multipliers 653101Sstever@eecs.umich.edu self._multiplier *= other 663101Sstever@eecs.umich.edu return self 673101Sstever@eecs.umich.edu 683101Sstever@eecs.umich.edu __rmul__ = __mul__ 693101Sstever@eecs.umich.edu 703101Sstever@eecs.umich.edu def _mulcheck(self, result): 713101Sstever@eecs.umich.edu if self._multiplier == None: 723101Sstever@eecs.umich.edu return result 733101Sstever@eecs.umich.edu return result * self._multiplier 743101Sstever@eecs.umich.edu 753101Sstever@eecs.umich.edu def unproxy(self, base): 763101Sstever@eecs.umich.edu obj = base 773101Sstever@eecs.umich.edu done = False 783101Sstever@eecs.umich.edu 793101Sstever@eecs.umich.edu if self._search_self: 803101Sstever@eecs.umich.edu result, done = self.find(obj) 813101Sstever@eecs.umich.edu 823101Sstever@eecs.umich.edu if self._search_up: 833101Sstever@eecs.umich.edu while not done: 843101Sstever@eecs.umich.edu obj = obj._parent 853101Sstever@eecs.umich.edu if not obj: 863101Sstever@eecs.umich.edu break 873101Sstever@eecs.umich.edu result, done = self.find(obj) 883101Sstever@eecs.umich.edu 893101Sstever@eecs.umich.edu if not done: 903101Sstever@eecs.umich.edu raise AttributeError, \ 913101Sstever@eecs.umich.edu "Can't resolve proxy '%s' of type '%s' from '%s'" % \ 923101Sstever@eecs.umich.edu (self.path(), self._pdesc.ptype_str, base.path()) 933101Sstever@eecs.umich.edu 943101Sstever@eecs.umich.edu if isinstance(result, BaseProxy): 953101Sstever@eecs.umich.edu if result == self: 963101Sstever@eecs.umich.edu raise RuntimeError, "Cycle in unproxy" 973101Sstever@eecs.umich.edu result = result.unproxy(obj) 983101Sstever@eecs.umich.edu 993101Sstever@eecs.umich.edu return self._mulcheck(result) 1003101Sstever@eecs.umich.edu 1013101Sstever@eecs.umich.edu def getindex(obj, index): 1023101Sstever@eecs.umich.edu if index == None: 1033101Sstever@eecs.umich.edu return obj 1043101Sstever@eecs.umich.edu try: 1053101Sstever@eecs.umich.edu obj = obj[index] 1063101Sstever@eecs.umich.edu except TypeError: 1073101Sstever@eecs.umich.edu if index != 0: 1083101Sstever@eecs.umich.edu raise 1093101Sstever@eecs.umich.edu # if index is 0 and item is not subscriptable, just 1103101Sstever@eecs.umich.edu # use item itself (so cpu[0] works on uniprocessors) 1113101Sstever@eecs.umich.edu return obj 1123101Sstever@eecs.umich.edu getindex = staticmethod(getindex) 1133101Sstever@eecs.umich.edu 1143109Sstever@eecs.umich.edu # This method should be called once the proxy is assigned to a 1153109Sstever@eecs.umich.edu # particular parameter or port to set the expected type of the 1163109Sstever@eecs.umich.edu # resolved proxy 1173101Sstever@eecs.umich.edu def set_param_desc(self, pdesc): 1183101Sstever@eecs.umich.edu self._pdesc = pdesc 1193101Sstever@eecs.umich.edu 1203101Sstever@eecs.umich.educlass AttrProxy(BaseProxy): 1213101Sstever@eecs.umich.edu def __init__(self, search_self, search_up, attr): 1223101Sstever@eecs.umich.edu super(AttrProxy, self).__init__(search_self, search_up) 1233101Sstever@eecs.umich.edu self._attr = attr 1243101Sstever@eecs.umich.edu self._modifiers = [] 1253101Sstever@eecs.umich.edu 1263101Sstever@eecs.umich.edu def __getattr__(self, attr): 1273101Sstever@eecs.umich.edu # python uses __bases__ internally for inheritance 1283101Sstever@eecs.umich.edu if attr.startswith('_'): 1293101Sstever@eecs.umich.edu return super(AttrProxy, self).__getattr__(self, attr) 1303101Sstever@eecs.umich.edu if hasattr(self, '_pdesc'): 1313101Sstever@eecs.umich.edu raise AttributeError, "Attribute reference on bound proxy" 1323101Sstever@eecs.umich.edu self._modifiers.append(attr) 1333101Sstever@eecs.umich.edu return self 1343101Sstever@eecs.umich.edu 1353101Sstever@eecs.umich.edu # support indexing on proxies (e.g., Self.cpu[0]) 1363101Sstever@eecs.umich.edu def __getitem__(self, key): 1373101Sstever@eecs.umich.edu if not isinstance(key, int): 1383101Sstever@eecs.umich.edu raise TypeError, "Proxy object requires integer index" 1393101Sstever@eecs.umich.edu self._modifiers.append(key) 1403101Sstever@eecs.umich.edu return self 1413101Sstever@eecs.umich.edu 1423101Sstever@eecs.umich.edu def find(self, obj): 1433101Sstever@eecs.umich.edu try: 1443101Sstever@eecs.umich.edu val = getattr(obj, self._attr) 1453101Sstever@eecs.umich.edu except: 1463101Sstever@eecs.umich.edu return None, False 1473101Sstever@eecs.umich.edu while isproxy(val): 1483101Sstever@eecs.umich.edu val = val.unproxy(obj) 1493101Sstever@eecs.umich.edu for m in self._modifiers: 1503101Sstever@eecs.umich.edu if isinstance(m, str): 1513101Sstever@eecs.umich.edu val = getattr(val, m) 1523101Sstever@eecs.umich.edu elif isinstance(m, int): 1533101Sstever@eecs.umich.edu val = val[m] 1543101Sstever@eecs.umich.edu else: 1553101Sstever@eecs.umich.edu assert("Item must be string or integer") 1563101Sstever@eecs.umich.edu while isproxy(val): 1573101Sstever@eecs.umich.edu val = val.unproxy(obj) 1583101Sstever@eecs.umich.edu return val, True 1593101Sstever@eecs.umich.edu 1603101Sstever@eecs.umich.edu def path(self): 1613101Sstever@eecs.umich.edu p = self._attr 1623101Sstever@eecs.umich.edu for m in self._modifiers: 1633101Sstever@eecs.umich.edu if isinstance(m, str): 1643101Sstever@eecs.umich.edu p += '.%s' % m 1653101Sstever@eecs.umich.edu elif isinstance(m, int): 1663101Sstever@eecs.umich.edu p += '[%d]' % m 1673101Sstever@eecs.umich.edu else: 1683101Sstever@eecs.umich.edu assert("Item must be string or integer") 1693101Sstever@eecs.umich.edu return p 1703101Sstever@eecs.umich.edu 1713101Sstever@eecs.umich.educlass AnyProxy(BaseProxy): 1723101Sstever@eecs.umich.edu def find(self, obj): 1733101Sstever@eecs.umich.edu return obj.find_any(self._pdesc.ptype) 1743101Sstever@eecs.umich.edu 1753101Sstever@eecs.umich.edu def path(self): 1763101Sstever@eecs.umich.edu return 'any' 1773101Sstever@eecs.umich.edu 1783101Sstever@eecs.umich.edudef isproxy(obj): 1793101Sstever@eecs.umich.edu if isinstance(obj, (BaseProxy, params.EthernetAddr)): 1803101Sstever@eecs.umich.edu return True 1813101Sstever@eecs.umich.edu elif isinstance(obj, (list, tuple)): 1823101Sstever@eecs.umich.edu for v in obj: 1833101Sstever@eecs.umich.edu if isproxy(v): 1843101Sstever@eecs.umich.edu return True 1853101Sstever@eecs.umich.edu return False 1863101Sstever@eecs.umich.edu 1873101Sstever@eecs.umich.educlass ProxyFactory(object): 1883101Sstever@eecs.umich.edu def __init__(self, search_self, search_up): 1893101Sstever@eecs.umich.edu self.search_self = search_self 1903101Sstever@eecs.umich.edu self.search_up = search_up 1913101Sstever@eecs.umich.edu 1923101Sstever@eecs.umich.edu def __getattr__(self, attr): 1933101Sstever@eecs.umich.edu if attr == 'any': 1943101Sstever@eecs.umich.edu return AnyProxy(self.search_self, self.search_up) 1953101Sstever@eecs.umich.edu else: 1963101Sstever@eecs.umich.edu return AttrProxy(self.search_self, self.search_up, attr) 1973101Sstever@eecs.umich.edu 1983101Sstever@eecs.umich.edu# global objects for handling proxies 1993101Sstever@eecs.umich.eduParent = ProxyFactory(search_self = False, search_up = True) 2003101Sstever@eecs.umich.eduSelf = ProxyFactory(search_self = True, search_up = False) 2013101Sstever@eecs.umich.edu 2023101Sstever@eecs.umich.edu# limit exports on 'from proxy import *' 2033101Sstever@eecs.umich.edu__all__ = ['Parent', 'Self'] 2043101Sstever@eecs.umich.edu 2053101Sstever@eecs.umich.edu# see comment on imports at end of __init__.py. 2063101Sstever@eecs.umich.eduimport params # for EthernetAddr 207