javaclass

Changeset

82:6379c132fad2
2004-12-09 Paul Boddie raw files shortlog changelog graph Added "return None" for abstract methods. Added comments for various methods and reformatted slightly.
bytecode.py (file)
     1.1 --- a/bytecode.py	Thu Dec 09 02:18:13 2004 +0100
     1.2 +++ b/bytecode.py	Thu Dec 09 19:44:31 2004 +0100
     1.3 @@ -19,6 +19,9 @@
     1.4      "A Python bytecode writer."
     1.5  
     1.6      def __init__(self):
     1.7 +
     1.8 +        "Initialise the writer."
     1.9 +
    1.10          # A stack of loop start instructions corresponding to loop blocks.
    1.11          self.loops = []
    1.12  
    1.13 @@ -61,6 +64,9 @@
    1.14          self.external_names = []
    1.15  
    1.16      def get_output(self):
    1.17 +
    1.18 +        "Return the output of the writer as a string."
    1.19 +
    1.20          output = []
    1.21          for element in self.output:
    1.22              if isinstance(element, LazySubValue):
    1.23 @@ -72,6 +78,12 @@
    1.24          return "".join(output)
    1.25  
    1.26      def get_constants(self):
    1.27 +
    1.28 +        """
    1.29 +        Return a list of constants with ordering significant to the code
    1.30 +        employing them.
    1.31 +        """
    1.32 +
    1.33          l = self._get_list(self._invert(self.constants))
    1.34          result = []
    1.35          for i in l:
    1.36 @@ -85,15 +97,33 @@
    1.37      #    return self._get_list(self._invert(self.globals))
    1.38  
    1.39      def get_names(self):
    1.40 +
    1.41 +        """
    1.42 +        Return a list of names with ordering significant to the code employing
    1.43 +        them.
    1.44 +        """
    1.45 +
    1.46          return self._get_list(self._invert(self.names))
    1.47  
    1.48      def _invert(self, d):
    1.49 +
    1.50 +        """
    1.51 +        Return a new dictionary whose key-to-value mapping is in the inverse of
    1.52 +        that found in 'd'.
    1.53 +        """
    1.54 +
    1.55          inverted = {}
    1.56          for k, v in d.items():
    1.57              inverted[v] = k
    1.58          return inverted
    1.59  
    1.60      def _get_list(self, d):
    1.61 +
    1.62 +        """
    1.63 +        Traverse the dictionary 'd' returning a list whose values appear at the
    1.64 +        position denoted by each value's key in 'd'.
    1.65 +        """
    1.66 +
    1.67          l = []
    1.68          for i in range(0, len(d.keys())):
    1.69              l.append(d[i])
    1.70 @@ -102,17 +132,34 @@
    1.71      # Administrative methods.
    1.72  
    1.73      def update_stack_depth(self, change):
    1.74 +
    1.75 +        """
    1.76 +        Given the stated 'change' in stack depth, update the maximum stack depth
    1.77 +        where appropriate.
    1.78 +        """
    1.79 +
    1.80          self.stack_depth += change
    1.81          if self.stack_depth > self.max_stack_depth:
    1.82              self.max_stack_depth = self.stack_depth
    1.83  
    1.84      def update_locals(self, index):
    1.85 +
    1.86 +        """
    1.87 +        Given the stated 'index' of a local variable, update the maximum local
    1.88 +        variable index where appropriate.
    1.89 +        """
    1.90 +
    1.91          if index > self.max_locals:
    1.92              self.max_locals = index
    1.93  
    1.94      # Special methods.
    1.95  
    1.96      def _write_value(self, value):
    1.97 +
    1.98 +        """
    1.99 +        Write the given 'value' at the current output position.
   1.100 +        """
   1.101 +
   1.102          if isinstance(value, LazyValue):
   1.103              # NOTE: Assume a 16-bit value.
   1.104              self.output.append(value.values[0])
   1.105 @@ -127,6 +174,11 @@
   1.106              raise ValueError, value
   1.107  
   1.108      def _rewrite_value(self, position, value):
   1.109 +
   1.110 +        """
   1.111 +        At the given output 'position', rewrite the given 'value'.
   1.112 +        """
   1.113 +
   1.114          # NOTE: Assume a 16-bit value.
   1.115          if value <= 0xffff:
   1.116              self.output[position] = (value & 0xff)
   1.117 @@ -587,10 +639,22 @@
   1.118      "A generic Java bytecode reader."
   1.119  
   1.120      def __init__(self, class_file):
   1.121 +
   1.122 +        """
   1.123 +        Initialise the reader with a 'class_file' containing essential
   1.124 +        information for any bytecode inspection activity.
   1.125 +        """
   1.126 +
   1.127          self.class_file = class_file
   1.128          self.position_mapping = LazyDict()
   1.129  
   1.130      def process(self, method, program):
   1.131 +
   1.132 +        """
   1.133 +        Process the given 'method' (obtained from the class file), using the
   1.134 +        given 'program' to write translated Python bytecode instructions.
   1.135 +        """
   1.136 +
   1.137          self.java_position = 0
   1.138          self.in_finally = 0
   1.139          self.method = method
   1.140 @@ -602,7 +666,15 @@
   1.141              if isinstance(attribute, classfile.CodeAttributeInfo):
   1.142                  code, exception_table = attribute.code, attribute.exception_table
   1.143                  break
   1.144 +
   1.145 +        # Where no code was found, write a very simple placeholder routine.
   1.146 +        # This is useful for interfaces and abstract classes.
   1.147 +        # NOTE: Assess the correctness of doing this. An exception should really
   1.148 +        # NOTE: be raised instead.
   1.149 +
   1.150          if code is None:
   1.151 +            program.load_const(None)
   1.152 +            program.return_value()
   1.153              return
   1.154  
   1.155          # Produce a structure which permits fast access to exception details.
   1.156 @@ -690,6 +762,14 @@
   1.157              self.java_position = next_java_position
   1.158  
   1.159      def process_bytecode(self, mnemonic, number_of_arguments, code, program):
   1.160 +
   1.161 +        """
   1.162 +        Process a bytecode instruction with the given 'mnemonic' and
   1.163 +        'number_of_arguments'. The 'code' parameter contains the full method
   1.164 +        code so that argument data can be inspected. The 'program' parameter is
   1.165 +        used to produce a Python translation of the instruction.
   1.166 +        """
   1.167 +
   1.168          if number_of_arguments is not None:
   1.169              arguments = []
   1.170              for j in range(0, number_of_arguments):
   1.171 @@ -1888,7 +1968,8 @@
   1.172          # NOTE: The code below should use dictionary-based dispatch for better performance.
   1.173  
   1.174          for method, fn in methods:
   1.175 -            method_is_static = real_method_name != "<init>" and method_is_static or classfile.has_flags(method.access_flags, [classfile.STATIC])
   1.176 +            method_is_static = real_method_name != "<init>" and method_is_static or \
   1.177 +                classfile.has_flags(method.access_flags, [classfile.STATIC])
   1.178  
   1.179              if method_is_static:
   1.180                  program.load_fast(0)                # Stack: arguments
   1.181 @@ -2178,6 +2259,8 @@
   1.182              l.append("_l%s" % i)
   1.183          return l[:nlocals]
   1.184  
   1.185 +# Test functions, useful for tracing generated bytecode operations.
   1.186 +
   1.187  def _map(*args):
   1.188      print args
   1.189      return apply(__builtins__.map, args)