I started working with Asm this week. After playing with it for a bit, it seemed obvious that JRuby would be a sweet spot for Asm code; very often, you need to implement only a small fraction of the interfaces that Asm uses.
Here’s my first JRuby effort with Asm. It’s straightforward and doesn’t do much yet – just outputs the contents of the .class files given on the command line. Here’s the JRuby:
require 'java' require 'asm-3.3.1' require 'pp' # This lets me type org.objectweb.asm::... instead of Java::OrgObjectwebAsm::... def org Java::Org end # This lets me use ClassReader without typing out org.objectweb.asm::ClassReader java_import org.objectweb.asm::ClassReader # Ruby supports mixins. Both visitor classes (class and method) use this method_missing # call. # # The generic visitor just prints information for any call to a visitor* method. module GenericVisitor def method_missing *args if args.first.to_s =~ /visit.*/ puts "In type: #{self.class} call to " + args.to_s else super end end end class SampleMethodVisitor include org.objectweb.asm::MethodVisitor include GenericVisitor end class SampleClassVisitor include org.objectweb.asm::ClassVisitor include GenericVisitor # we need to keep a copy of our method visitor def initialize args @method_visitor = args[:method_visitor] end def visit_method *args # The output has methods seperated with an easy-to-see string puts "visit method " + args.to_s + "================================" # Asm wants ClassVisitor#visitMethod to return a method visitor @method_visitor end end # Loop through each .class file given on the command line ARGV.each do |classfile| puts " ---------------- Reading file #{classfile}" f = java.io.File.new classfile fis = java.io.FileInputStream.new f class_reader = ClassReader.new fis v = SampleClassVisitor.new method_visitor: SampleMethodVisitor.new class_reader.accept v, 0 puts end
And here’s the output:
---------------- Reading file /Users/james/experimements/AsmSample/bin/com/restphone/classSignature/SampleOne.class In type: SampleClassVisitor call to [:visit, 50, 33, "com/restphone/classSignature/SampleOne", nil, "java/lang/Object", #<#<Class:0x12690ed81>:0x28b53b32>] In type: SampleClassVisitor call to [:visitSource, "SampleOne.java", nil] In type: SampleClassVisitor call to [:visitField, 9, "x", "Ljava/lang/Integer;", nil, nil] visit method [8, "<clinit>", "()V", nil, nil]================================ In type: SampleMethodVisitor call to [:visitCode] In type: SampleMethodVisitor call to [:visitLabel, #<Java::OrgObjectwebAsm::Label:0x236954e1>] In type: SampleMethodVisitor call to [:visitLineNumber, 4, #<Java::OrgObjectwebAsm::Label:0x236954e1>] In type: SampleMethodVisitor call to [:visitFieldInsn, 178, "com/restphone/classSignature/SampleTwo", "y", "Ljava/lang/Integer;"] In type: SampleMethodVisitor call to [:visitFieldInsn, 179, "com/restphone/classSignature/SampleOne", "x", "Ljava/lang/Integer;"] In type: SampleMethodVisitor call to [:visitLabel, #<Java::OrgObjectwebAsm::Label:0x643f58bb>] In type: SampleMethodVisitor call to [:visitLineNumber, 3, #<Java::OrgObjectwebAsm::Label:0x643f58bb>] In type: SampleMethodVisitor call to [:visitInsn, 177] In type: SampleMethodVisitor call to [:visitMaxs, 1, 0] In type: SampleMethodVisitor call to [:visitEnd] visit method [1, "<init>", "()V", nil, nil]================================ In type: SampleMethodVisitor call to [:visitCode] In type: SampleMethodVisitor call to [:visitLabel, #<Java::OrgObjectwebAsm::Label:0x1d7aaa0e>] In type: SampleMethodVisitor call to [:visitLineNumber, 3, #<Java::OrgObjectwebAsm::Label:0x1d7aaa0e>] In type: SampleMethodVisitor call to [:visitVarInsn, 25, 0] In type: SampleMethodVisitor call to [:visitMethodInsn, 183, "java/lang/Object", "<init>", "()V"] In type: SampleMethodVisitor call to [:visitInsn, 177] In type: SampleMethodVisitor call to [:visitLabel, #<Java::OrgObjectwebAsm::Label:0x13ad9b0f>] In type: SampleMethodVisitor call to [:visitLocalVariable, "this", "Lcom/restphone/classSignature/SampleOne;", nil, #<Java::OrgObjectwebAsm::Label:0x1d7aaa0e>, #<Java::OrgObjectwebAsm::Label:0x13ad9b0f>, 0] In type: SampleMethodVisitor call to [:visitMaxs, 1, 1] In type: SampleMethodVisitor call to [:visitEnd] visit method [1, "doubleTheValue", "(Ljava/lang/Integer;)Ljava/lang/Integer;", nil, nil]================================ In type: SampleMethodVisitor call to [:visitCode] In type: SampleMethodVisitor call to [:visitLabel, #<Java::OrgObjectwebAsm::Label:0x9eae15f>] In type: SampleMethodVisitor call to [:visitLineNumber, 7, #<Java::OrgObjectwebAsm::Label:0x9eae15f>] In type: SampleMethodVisitor call to [:visitVarInsn, 25, 1] In type: SampleMethodVisitor call to [:visitMethodInsn, 182, "java/lang/Integer", "intValue", "()I"] In type: SampleMethodVisitor call to [:visitInsn, 5] In type: SampleMethodVisitor call to [:visitInsn, 104] In type: SampleMethodVisitor call to [:visitMethodInsn, 184, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;"] In type: SampleMethodVisitor call to [:visitInsn, 176] In type: SampleMethodVisitor call to [:visitLabel, #<Java::OrgObjectwebAsm::Label:0x2569a1c5>] In type: SampleMethodVisitor call to [:visitLocalVariable, "this", "Lcom/restphone/classSignature/SampleOne;", nil, #<Java::OrgObjectwebAsm::Label:0x9eae15f>, #<Java::OrgObjectwebAsm::Label:0x2569a1c5>, 0] In type: SampleMethodVisitor call to [:visitLocalVariable, "x", "Ljava/lang/Integer;", nil, #<Java::OrgObjectwebAsm::Label:0x9eae15f>, #<Java::OrgObjectwebAsm::Label:0x2569a1c5>, 1] In type: SampleMethodVisitor call to [:visitMaxs, 2, 2] In type: SampleMethodVisitor call to [:visitEnd] In type: SampleClassVisitor call to [:visitEnd]
Incidentally, I used my new Eclipse plugin to send the current selection through a filter to html-escape the text. Check it out on github.
No comments:
Post a Comment