| Class | Ruva::VM::Class |
| In: |
lib/ruva/class.rb
lib/ruva/class_loader.rb |
| Parent: | Object |
A Class holds the internal runtime representation of a resolved Java class (see also: Ruva::VM::Class::Reader::UnresolvedClass). Instances of this class are normally produced by the Ruva::VM::ClassLoader, although this class is a visitor - it can be passed to the accept method of an UnresolvedClass instance.
INSTANCES MUST NOT BE SHARED BETWEEN VMs!
| ACC_PUBLIC | = | 0x0001 |
| ACC_PRIVATE | = | 0x0002 |
| ACC_PROTECTED | = | 0x0004 |
| ACC_FINAL | = | 0x0010 |
| ACC_SUPER | = | 0x0020 |
| ACC_INTERFACE | = | 0x0200 |
| ACC_ABSTRACT | = | 0x0400 |
| ACC_SYNTHETIC | = | 0x1000 |
| ACC_ANNOTATION | = | 0x2000 |
| ACC_ENUM | = | 0x4000 |
| HUMAN_DESC_RE | = | /^(\[)?(B|C|D|F|I|J|L|S|V|Z)(?:([^;]+)?)/ |
| AnnotationEnum | = | Struct.new :name, :desc, :value |
| LineNumber | = | Struct.new :line, :start_pc |
| LocalVariable | = | Struct.new :name, :desc, :signature, :start_ofs, :end_ofs, :index |
| Exception | = | Struct.new :start_pc, :end_pc, :handler_pc |
| InnerClass | = | Struct.new :access, :name, :outer, :inner |
| OuterClass | = | Struct.new :owner, :name, :desc |
| initialized | -> | initialized? |
| linked | -> | linked? |
| inspect | -> | full_inspect |
| access | [RW] | |
| annotations | [RW] | |
| attrs | [RW] | |
| field_lookup | [RW] | |
| fields | [RW] | |
| initialized | [RW] | Has class been initialized? (<clinit> run) |
| inner_classes | [RW] | |
| interfaces | [RW] | |
| linked | [RW] | Has class been linked into the runtime? |
| method_lookup | [RW] | |
| methods | [RW] | |
| name | [RW] | |
| outer_class | [RW] | |
| pool | [RW] | |
| signature | [RW] | |
| source | [RW] | |
| super_name | [RW] | |
| ver_maj | [RW] | |
| ver_min | [RW] |
# File lib/ruva/class.rb, line 101
101: def human_access_class(e)
102: (basic_human_access(e) + "#{'final ' if e.final?}#{'abstract ' if e.abstract?}" +
103: if e.interface?
104: 'interface'
105: elsif e.annotation?
106: '@interface'
107: elsif e.enum?
108: 'enum'
109: else
110: 'class'
111: end)
112: end
# File lib/ruva/class.rb, line 114
114: def human_access_field(e)
115: (basic_human_access(e) + "#{'volatile ' if e.volatile?}#{'transient ' if e.transient?}")
116: end
# File lib/ruva/class.rb, line 118
118: def human_access_method(e)
119: (basic_human_access(e) + "#{'final ' if e.final?}#{'abstract ' if e.abstract?}#{'native ' if e.native?}" +
120: "#{'synchronized ' if e.synchronized?}#{'bridge ' if e.bridge?}" +
121: "#{'varargs ' if e.varargs?}#{'strictfp ' if e.strict?}#{'synthetic ' if e.synthetic?}")
122: end
Maps an array of descriptors to human-readable format.
# File lib/ruva/class.rb, line 97
97: def human_argdescs(argdescs)
98: argdescs.map { |e| human_desc(e) }
99: end
Helper method that gives a human-readable version of a type descriptor
# File lib/ruva/class.rb, line 59
59: def human_desc(desc)
60: if desc =~ HUMAN_DESC_RE
61: ret = case $2
62: when 'L'
63: $3.tr('/', '.')
64: when 'B'
65: 'byte'
66: when 'C'
67: 'char'
68: when 'D'
69: 'double'
70: when 'F'
71: 'float'
72: when 'I'
73: 'int'
74: when 'J'
75: 'long'
76: when 'S'
77: 'short'
78: when 'V'
79: 'void'
80: when 'Z'
81: 'boolean'
82: else
83: desc # invalid descriptor
84: end
85:
86: if $1
87: ret + '[]'
88: else
89: ret
90: end
91: else
92: desc
93: end
94: end
# File lib/ruva/class.rb, line 438
438: def initialize(ver_maj = nil, ver_min = nil, access = nil, name = nil, signature = nil, super_name = nil, interfaces = [])
439: self.ver_maj, self.ver_min, self.access, self.name, self.signature, self.super_name, self.interfaces =
440: ver_maj, ver_min, access, name, signature, super_name, interfaces
441:
442: # start the runtime pool with the class reference itself.
443: # 'proper', and stops us having to subtract one from all the cpool indices.
444: @annotations, @fields, @methods, @attrs, @inner_classes, @pool = [], [], [], [], [], [self]
445: @field_lookup, @method_lookup = {}, {}
446: @initialized = false
447: @linked = false
448: @natives = nil
449: end
Obtains the class of the specified primitive type
# File lib/ruva/class.rb, line 29
29: def of_primitive(type)
30: case type
31: when 'B'
32: @byte_class ||= new(49, 0, ACC_PUBLIC | ACC_FINAL, 'byte', 'B', nil)
33: when 'C'
34: @char_class ||= new(49, 0, ACC_PUBLIC | ACC_FINAL, 'char', 'C', nil)
35: when 'D'
36: @double_class ||= new(49, 0, ACC_PUBLIC | ACC_FINAL, 'double', 'D', nil)
37: when 'F'
38: @float_class ||= new(49, 0, ACC_PUBLIC | ACC_FINAL, 'float', 'F', nil)
39: when 'I'
40: @int_class ||= new(49, 0, ACC_PUBLIC | ACC_FINAL, 'int', 'I', nil)
41: when 'J'
42: @long_class ||= new(49, 0, ACC_PUBLIC | ACC_FINAL, 'long', 'J', nil)
43: when 'S'
44: @short_class ||= new(49, 0, ACC_PUBLIC | ACC_FINAL, 'short', 'S', nil)
45: when 'V'
46: @void_class ||= new(49, 0, ACC_PUBLIC | ACC_FINAL, 'void', 'V', nil)
47: when 'Z'
48: @boolean_class ||= new(49, 0, ACC_PUBLIC | ACC_FINAL, 'boolean', 'Z', nil)
49: else
50: raise VM::TypeError, "Invalid primitive type #{type}"
51: end
52: end
# File lib/ruva/class.rb, line 539
539: def ==(other)
540: other.is_a?(self.class) && name == other.name
541: end
# File lib/ruva/class.rb, line 463
463: def natives(nmod)
464: @natives ||= begin
465: name.split('/').map { |e| e[0,1].upcase + e[1..-1] }.inject(nmod) { |mod, sm|
466: mod.const_get(sm)
467: }
468: rescue NameError
469: nil
470: end
471: end
# File lib/ruva/class.rb, line 459
459: def natives=(native_mod)
460: @natives = native_mod
461: end
CLASSVISITOR
# File lib/ruva/class.rb, line 452
452: def visit(ver_maj, ver_min, access, name, signature, super_name, interfaces)
453: initialize(ver_maj, ver_min, access, name, signature, super_name, interfaces)
454: end
Visit an annotation. Should return an Annotation visitor to suit.
# File lib/ruva/class.rb, line 477
477: def visit_annotation(desc, visible)
478: annotations << a = Annotation.new(desc, visible)
479: a
480: end
Visit a non=standard attribute
# File lib/ruva/class.rb, line 483
483: def visit_attribute(attr)
484: attrs << attr
485: end
Visit a constant pool entry.
# File lib/ruva/class.rb, line 488
488: def visit_cpool_entry(orig_pool, data, type)
489:
490: case type
491: when :class
492: pool << VM::Types::ConstClassRef.new(nil, {}, orig_pool[data[:name_index] - 1].data)
493: when :field, :method, :if_method
494: pool << { :class => orig_pool[orig_pool[data[:class_index] - 1].data[:name_index] - 1].data,
495: :name => orig_pool[orig_pool[data[:name_type_index] - 1].data[:name_index] - 1].data,
496: :desc => orig_pool[orig_pool[data[:name_type_index] - 1].data[:desc_index] - 1].data }
497: when :string
498: pool << VM::Types::ConstStringRef.new(nil, {}, orig_pool[data[:string_index] - 1].data)
499: when :int, :long, :float, :double, :utf8
500: # TODO : don't add stuff we don't need (e.g. utf8s we already resolved out).
501: pool << data
502: when :name_type
503: # not needed, we resolved 'em out. Add a nil to keep the indexes right.
504: pool << nil
505: when :empty
506: # internal type, signifies we need a space in the pool following a cat2 type
507: pool << nil
508: end
509: end
should return a FieldVisitor
# File lib/ruva/class.rb, line 512
512: def visit_field(access, name, desc, signature, value)
513: fields << f = Field.new(access, name, desc, signature, value)
514: field_lookup[name+desc] = fields.length - 1
515: f
516: end
should return a MethodVisitor
# File lib/ruva/class.rb, line 519
519: def visit_method(access, name, desc, signature, throws)
520: methods << m = Method.new(self, access, name, desc, signature, throws)
521: method_lookup[name+desc] = methods.length - 1
522: m
523: end