javaclass

Changeset

168:1f3fa26a27e2
2005-02-13 Paul Boddie raw files shortlog changelog graph Attempted to simplify the class loading mechanism by adding instance-level state to remember which classes have been imported so far. Only at the top level will such classes be created and initialised. Added a convenience method to ClassTranslator.
javaclass/bytecode.py (file) javaclass/classhook.py (file)
     1.1 --- a/javaclass/bytecode.py	Sun Feb 13 02:10:43 2005 +0100
     1.2 +++ b/javaclass/bytecode.py	Sun Feb 13 19:10:07 2005 +0100
     1.3 @@ -2326,6 +2326,9 @@
     1.4  
     1.5          return cls
     1.6  
     1.7 +    def get_super_class(self):
     1.8 +        return self.class_file.super_class
     1.9 +
    1.10      def get_base_classes(self, global_names):
    1.11  
    1.12          """
     2.1 --- a/javaclass/classhook.py	Sun Feb 13 02:10:43 2005 +0100
     2.2 +++ b/javaclass/classhook.py	Sun Feb 13 19:10:07 2005 +0100
     2.3 @@ -166,7 +166,6 @@
     2.4          else:
     2.5              archive, archive_path, path = self._get_archive_and_path(dir, name)
     2.6  
     2.7 -        #print "Processing name", name, "in", dir, "producing", path, "within archive", archive
     2.8  
     2.9          if self._find_module_at_path(path, archive):
    2.10              if archive is not None:
    2.11 @@ -204,7 +203,6 @@
    2.12  
    2.13      def _find_module_at_path(self, path, archive):
    2.14          if self.hooks.path_isdir(path, archive):
    2.15 -            #print "Looking in", path, "using archive", archive
    2.16  
    2.17              # Look for classes in the directory.
    2.18  
    2.19 @@ -213,7 +211,6 @@
    2.20  
    2.21              # Otherwise permit importing where directories containing classes exist.
    2.22  
    2.23 -            #print "Filenames are", self.hooks.listdir(path, archive)
    2.24              for filename in self.hooks.listdir(path, archive):
    2.25                  pathname = self.hooks.path_join(path, filename)
    2.26                  result = self._find_module_at_path(pathname, archive)
    2.27 @@ -237,30 +234,29 @@
    2.28          find_module method produces such a list.
    2.29          """
    2.30  
    2.31 -        loaded_module_names = []
    2.32 -        loaded_classes = {}
    2.33 -        main_module = self._load_module(name, stuff, loaded_module_names, loaded_classes)
    2.34 +        module = self._not_java_module(name, stuff)
    2.35 +        if module is not None:
    2.36 +            return module
    2.37 +
    2.38 +        if not hasattr(self, "loaded_classes"):
    2.39 +            self.loaded_classes = {}
    2.40 +            top_level = 1
    2.41 +        else:
    2.42 +            top_level = 0
    2.43 +
    2.44 +        main_module = self._load_module(name, stuff)
    2.45  
    2.46          # Initialise the loaded classes.
    2.47  
    2.48 -        for module, classes in loaded_classes.items():
    2.49 -            self._init_classes(module, classes)
    2.50 +        if top_level:
    2.51 +            self._init_classes()
    2.52 +            self.loaded_classes = {}
    2.53  
    2.54          return main_module
    2.55  
    2.56 -    def _filter_names(self, module_names, loaded_module_names):
    2.57 -        for module_name in loaded_module_names:
    2.58 -            try:
    2.59 -                i = module_names.index(module_name)
    2.60 -                del module_names[i]
    2.61 -            except ValueError:
    2.62 -                pass
    2.63 +    def _not_java_module(self, name, stuff):
    2.64  
    2.65 -    def _load_module(self, name, stuff, loaded_module_names, loaded_classes):
    2.66 -        #print "_load_module", name, loaded_module_names
    2.67 -        loaded_module_names.append(name)
    2.68 -
    2.69 -        # Detect non-Java modules.
    2.70 +        "Detect non-Java modules."
    2.71  
    2.72          for stuff_item in stuff:
    2.73              archive, filename, info = stuff_item
    2.74 @@ -268,6 +264,10 @@
    2.75              if datatype not in (JAVA_PACKAGE, JAVA_ARCHIVE):
    2.76                  return ihooks.ModuleLoader.load_module(self, name, stuff_item)
    2.77  
    2.78 +        return None
    2.79 +
    2.80 +    def _load_module(self, name, stuff):
    2.81 +
    2.82          # Set up the module.
    2.83          # A union of all locations is placed in the module's path.
    2.84  
    2.85 @@ -292,26 +292,22 @@
    2.86  
    2.87              archive, filename, info = stuff_item
    2.88              suffix, mode, datatype = info
    2.89 -            #print "Loading", archive, filename, info
    2.90  
    2.91              # Get the real filename.
    2.92  
    2.93              filename = self._get_path_in_archive(filename)
    2.94 -            #print "Real filename", filename
    2.95  
    2.96              # Load the class files.
    2.97  
    2.98              for class_filename in self.hooks.matching(filename, os.extsep + "class", archive):
    2.99 -                #print "Loading class", class_filename
   2.100                  s = self.hooks.read(class_filename, archive)
   2.101                  class_file = classfile.ClassFile(s)
   2.102                  translator = bytecode.ClassTranslator(class_file)
   2.103 -                classes[str(class_file.this_class.get_name())] = translator
   2.104                  external_names += translator.process(global_names)
   2.105  
   2.106 -        # Record the classes found under the current module.
   2.107 +                # Record the classes found under the current module.
   2.108  
   2.109 -        loaded_classes[module] = classes
   2.110 +                self.loaded_classes[str(class_file.this_class.get_name())] = module, translator
   2.111  
   2.112          # Return modules used by external names.
   2.113  
   2.114 @@ -319,57 +315,12 @@
   2.115  
   2.116          # Repeatedly load classes from referenced modules.
   2.117  
   2.118 -        self._filter_names(external_module_names, loaded_module_names)
   2.119          for module_name in external_module_names:
   2.120 -            if module_name not in loaded_module_names:
   2.121 -
   2.122 -                # Emulate the __import__ function, loading the requested module
   2.123 -                # but returning the top-level module.
   2.124 -
   2.125 -                self._import(module_name, global_names, loaded_module_names, loaded_classes)
   2.126 +            new_module = __import__(module_name, global_names)
   2.127 +            global_names[module_name.split(".")[0]] = new_module
   2.128  
   2.129          return module
   2.130  
   2.131 -    def _import(self, module_name, parent, loaded_module_names, loaded_classes):
   2.132 -
   2.133 -        # Where no Java-based submodules can be found, look for
   2.134 -        # Python modules instead.
   2.135 -
   2.136 -        new_stuff = self.find_module(module_name)
   2.137 -        #print "_", new_stuff
   2.138 -        if not new_stuff:
   2.139 -            new_module = __import__(module_name, parent)
   2.140 -            #print "P", new_module
   2.141 -            parent[module_name.split(".")[0]] = new_module
   2.142 -            return new_module
   2.143 -
   2.144 -        module_name_parts = module_name.split(".")
   2.145 -        path = []
   2.146 -        for module_name_part in module_name_parts:
   2.147 -            path.append(module_name_part)
   2.148 -            path_str = ".".join(path)
   2.149 -            if self.modules_dict().has_key(path_str):
   2.150 -
   2.151 -                # Add submodules to existing modules.
   2.152 -
   2.153 -                new_module = self.modules_dict()[path_str]
   2.154 -                parent = new_module.__dict__
   2.155 -                #print "-", path_str
   2.156 -
   2.157 -            else:
   2.158 -
   2.159 -                # Find submodules.
   2.160 -
   2.161 -                new_stuff = self.find_module(path_str)
   2.162 -                new_module = self._load_module(path_str, new_stuff, loaded_module_names, loaded_classes)
   2.163 -                #print "J", new_module
   2.164 -                #print "+", path_str, new_module
   2.165 -                parent[module_name_part] = new_module
   2.166 -                parent = new_module.__dict__
   2.167 -
   2.168 -        #print "->", new_module.__dict__.keys()
   2.169 -        return new_module
   2.170 -
   2.171      def _get_external_module_names(self, names):
   2.172          groups = self._get_names_grouped_by_module(names)
   2.173          if groups.has_key(""):
   2.174 @@ -391,19 +342,45 @@
   2.175          module_name = ".".join(full_name_parts[:-1])
   2.176          return module_name, class_name
   2.177  
   2.178 -    def _init_classes(self, module, classes):
   2.179 -        global_names = module.__dict__
   2.180 +    def _init_classes(self):
   2.181 +
   2.182 +        # Order the classes according to inheritance.
   2.183 +
   2.184 +        init_order = []
   2.185 +        for class_name, (module, translator) in self.loaded_classes.items():
   2.186 +            super_class = translator.get_super_class()
   2.187 +
   2.188 +            # Insert the super class before any mention of the current class.
   2.189  
   2.190 -        # First, create the classes.
   2.191 +            if super_class is not None:
   2.192 +                super_class_name = str(super_class.get_name())
   2.193 +                if super_class_name not in init_order:
   2.194 +                    if class_name not in init_order:
   2.195 +                        init_order.append(super_class_name)
   2.196 +                    else:
   2.197 +                        index = init_order.index(class_name)
   2.198 +                        init_order.insert(index, super_class_name)
   2.199 +
   2.200 +            if class_name not in init_order:
   2.201 +                init_order.append(class_name)
   2.202 +
   2.203 +        # Create the classes.
   2.204  
   2.205          real_classes = []
   2.206 -        for name, translator in classes.items():
   2.207 -            real_classes.append(translator.get_class(global_names))
   2.208 +        for class_name in init_order:
   2.209 +            try:
   2.210 +                module, translator = self.loaded_classes[class_name]
   2.211 +                global_names = module.__dict__
   2.212 +                real_classes.append((module, translator.get_class(global_names)))
   2.213 +            except KeyError:
   2.214 +                # NOTE: Should be a non-Java class.
   2.215 +                pass
   2.216  
   2.217          # Finally, call __clinit__ methods for all relevant classes.
   2.218  
   2.219 -        for cls in real_classes:
   2.220 +        for module, cls in real_classes:
   2.221              if hasattr(cls, "__clinit__"):
   2.222 +                global_names = module.__dict__
   2.223                  eval(cls.__clinit__.func_code, global_names)
   2.224  
   2.225  ihooks.ModuleImporter(loader=ClassLoader(hooks=ClassHooks())).install()