| Class | Ruva::VM::ClassPoolManager |
| In: |
lib/ruva/class_pool.rb
|
| Parent: | Object |
Used by the VM to manage the runtime class pool, handle class loading, register and remove classloaders, and maintain information about initiating class-loaders.
| class_loaders | [R] | |
| class_pool | [R] |
The class pool has the format:
{ 'int/ernal/ClassName' => Ruva::VM::Class }
|
| initiating_loader_table | [R] |
The initiating_loader_table has the format:
{ 'int/ernal/ClassName' => Ruva::VM::ClassLoader }
|
| loaded_library_table | [R] |
The loaded_library_table has the format:
{ 'path/to/filename.rb' => true, ... }
|
| rev_initiating_loader_table | [R] |
The rev_initiating_loader_table has the format:
{ Ruva::VM::ClassLoader => [ 'int/ernal/ClassName1', 'int/ernal/ClassName2', ... ]
It helps with removing a loader‘s classes. |
| vm | [RW] |
# File lib/ruva/class_pool.rb, line 39
39: def initialize(vm, class_loaders = [Ruva::VM::ClassLoader.new(nil, *(Ruva::RUVA_RUNTIME + ['.']))],
40: class_pool = {}, initiating_loader_table = {}, loaded_library_table = {})
41: @vm, @class_loaders, @class_pool, @initiating_loader_table, @loaded_library_table =
42: vm, class_loaders, class_pool, initiating_loader_table, loaded_library_table
43:
44: yield self if block_given?
45:
46: @rev_initiating_loader_table = Hash[*initiating_loader_table.map { |k,v| [v,k] }.flatten]
47: end
Manually add a class to the class pool
# File lib/ruva/class_pool.rb, line 102
102: def add_class(loader, clz)
103: raise DuplicateClassDefError, "Class with name #{clz.name} is already loaded" if class_pool.include?(clz.name)
104:
105: initiating_loader_table[clz.name] = loader
106: (rev_initiating_loader_table[loader] ||= []) << clz.name
107:
108: class_pool[clz.name] = clz
109: end
This is the top-level method used by the VM to obtain Class instances. This will return the requested class from the pool if found. Otherwise, it will invoke the classloader search to attempt to find the specified class.
When a class is loaded, a new frame is pushed to run it‘s <clinit>, if it has one.
The supplied name must be in internal format. Returns the found class, or raises a VMError if the class cannot be found.
# File lib/ruva/class_pool.rb, line 79
79: def find_class(class_name)
80: # TODO this'll have to be changed later. Probably have to just make
81: # object subclasses at runtime...
82: class_name = 'java/lang/Object' if class_name[0,1] == '['
83:
84: nmod = vm.natives
85:
86: # TODO bug here, classloaders that delegate and find the class that
87: # way will still be registered as the initiating loader for that class.
88:
89: unless clz = class_pool[class_name]
90: if loader = class_loaders.find { |l| clz = l.load_class(class_name, nmod) }
91: # bit of wierdness, we have to add _before_ we link, in case we're
92: # linking either java/lang/String or java/lang/Class. Otherwise,
93: # the linking causes them to be reloaded ad infinitum.
94: link_class(add_class(loader, clz))
95: end
96: end
97:
98: clz
99: end
This is the top-level method used by the VM to load ‘native’ (ruby) libraries for implementation of native Java methods. This will return the either true or false depending on whether the library could be loaded.
Currently, it expects classpath management to happen back in Java (it‘s how Classpath works) and so doesn‘t do any kind of processing on the name - it expects it‘s already a full path.
See Ruva::VM::Runtime::Native
# File lib/ruva/class_pool.rb, line 120
120: def load_library(name, loader = nil)
121: if loaded_library_table[name]
122: true # TODO is this the right behaviour?
123: else
124: nmod = vm.natives
125:
126: loaders = ((loader && [loader]) or class_loaders)
127: loaded_library_table[name] = true
128: if loaders.any? { |l| l.load_library(name, nmod) }
129: true
130: else
131: loaded_library_table[name] = false
132: false
133: end
134: end
135: end
Register the specified Ruva::VM::ClassLoader for use by the VM.
# File lib/ruva/class_pool.rb, line 50
50: def register_classloader(loader)
51: class_loaders << loader
52: end
You probably shouldn‘t do this, but then again it‘ll just get loaded again if it‘s referenced after you remove it… Normally, classes go away only when their loaders go away.
Returns the removed class.
# File lib/ruva/class_pool.rb, line 142
142: def remove_class(clz)
143: initating_loader_table.delete(clz.name)
144: rev_initating_loader_table.delete(clz.name)
145:
146: class_pool.delete(clz.name)
147: end
Remove the specified Ruva::VM::ClassLoader from the list of registered loaders, along with any classes loaded by it. You really ought to call this if you‘re removing a loader, or it‘ll end in tears, I‘d wager.
Guv‘nor.
# File lib/ruva/class_pool.rb, line 59
59: def remove_classloader(loader)
60: if classes = rev_initiating_loader_table.delete(loader)
61: classes.each do |class_name|
62: initiating_loader_table.delete(class_name)
63: class_pool.delete(class_name)
64: end
65: end
66:
67: nil
68: end
This goes through the constant pool, finding all the unlinked const objectrefs, and links them with the correct runtime class.
# File lib/ruva/class_pool.rb, line 153
153: def link_class(clz)
154: # sometimes (if class contains constclassrefs to itself) linking will
155: # cause infinite recursion unless we check and set this *before* doing
156: # the linkage.
157: unless clz.linked?
158: clz.linked = true
159:
160: clz.pool.each do |entry|
161: if entry.is_a?(VM::Types::ConstStringRef) || entry.is_a?(VM::Types::ConstClassRef)
162: entry.link(vm)
163: end
164: end
165: end
166:
167: clz
168: end