Title: [683] trunk: Initial check-in of the source for the rcov java port.
Revision
683
Author
kofno
Date
2007-08-08 00:02:46 -0400 (Wed, 08 Aug 2007)

Log Message

Initial check-in of the source for the rcov java port.

Added Paths


Diff

Added: trunk/rcov4jr/README.txt (0 => 683)


--- trunk/rcov4jr/README.txt	                        (rev 0)
+++ trunk/rcov4jr/README.txt	2007-08-08 04:02:46 UTC (rev 683)
@@ -0,0 +1,7 @@
+This gem provides JRuby support for Rcov.
+
+Right now, this project can only be built from JRuby.
+
+There seems to be problem getting this to work when it's installed as a gem
+
+The tests are part of rcov's package. Use rcov-0.8.0.2.

Added: trunk/rcov4jr/Rakefile.rb (0 => 683)


--- trunk/rcov4jr/Rakefile.rb	                        (rev 0)
+++ trunk/rcov4jr/Rakefile.rb	2007-08-08 04:02:46 UTC (rev 683)
@@ -0,0 +1,81 @@
+# rcovrt4j: This builds a JRuby extension for Rcov. 
+# 
+# Compiles java and makes rcov service jar. It will
+# also package it as a gem for release into the wild.
+require 'rake'
+require 'rubygems'
+require 'rake/gempackagetask'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+GEM_NAME='rcov4jr'
+GEM_VERSION='0.0.1'
+
+def java_classpath_arg
+  begin
+    require 'java'
+    classpath = java.lang.System.getProperty('java.class.path')
+  rescue LoadError
+  end
+
+  unless classpath
+    classpath = FileList["#{ENV['JRUBY_HOME']}/lib/*.jar"].join(File::PATH_SEPARATOR)
+  end
+
+  classpath ? "-cp #{classpath}" : ""
+end
+
+def compile_java
+  mkdir_p "java/classes"
+  sh "javac -g -target 1.4 -source 1.4 -d java/classes #{java_classpath_arg} #{FileList['java/src/**/*.java'].join(' ')}"
+end
+
+def make_jar
+  require 'fileutils'
+  lib = File.join(File.dirname(__FILE__), 'lib')
+  FileUtils.mkdir(lib) unless File.exists? lib
+  sh "jar cf lib/rcovrt.jar -C java/classes/ ."
+end
+
+file 'lib/rcovrt.jar' => FileList["java/src/*.java"] do
+  compile_java
+  make_jar
+end
+
+spec = Gem::Specification.new do |s|
+  s.platform = "java"
+  s.summary  = "Java implementation of Rcov's native extension."
+  s.name     = GEM_NAME
+  s.version  = GEM_VERSION
+  s.require_path = 'lib'
+  s.files    = FileList['Rakefile.rb', 'README.txt', 'lib/rcovrt.jar']
+  s.description = "Java extension to make rcov run on JRuby"
+  #s.add_dependency 'rcov', '>= 0.8.0.2'
+  s.author   = 'Ryan Bell'
+  s.email    = '[EMAIL PROTECTED]'
+  s.homepage = 'http://rubyforge.org/projects/jruby-extras'
+  s.has_rdoc = true
+end
+
+Rake::GemPackageTask.new(spec).define
+
+Rake::RDocTask.new do |t|
+  t.main = 'README.txt'
+  t.rdoc_files.include 'README.txt'
+end
+
+desc "Install the gem file #{GEM_NAME}-#{GEM_VERSION}-java.gem"
+task :install_gem do
+  gem = File.join(File.dirname(__FILE__), 'pkg', "#{GEM_NAME}-#{GEM_VERSION}-java.gem")
+  ruby '-S', 'gem', 'install', gem
+end
+
+desc "Uninstall the gem #{GEM_NAME}"
+task :uninstall_gem do
+  ruby '-S', 'gem', 'uninstall', GEM_NAME
+end
+
+desc "Create the Java extension."
+task :compile => ['lib/rcovrt.jar']
+task :gem => [:compile]
+task :install_gem => [:gem]

Added: trunk/rcov4jr/java/src/CallsiteHook.java (0 => 683)


--- trunk/rcov4jr/java/src/CallsiteHook.java	                        (rev 0)
+++ trunk/rcov4jr/java/src/CallsiteHook.java	2007-08-08 04:02:46 UTC (rev 683)
@@ -0,0 +1,129 @@
+import jregex.Matcher;
+import jregex.Pattern;
+
+import org.jruby.Ruby;
+import org.jruby.RubyArray;
+import org.jruby.RubyHash;
+import org.jruby.RubySymbol;
+import org.jruby.runtime.Frame;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+public class CallsiteHook implements RcovHook {
+
+    private static CallsiteHook callsiteHook;
+
+    public static CallsiteHook getCallsiteHook() {
+        if (callsiteHook == null) {
+            callsiteHook = new CallsiteHook();
+        }
+        return callsiteHook;
+    }
+
+    private boolean active;
+    private RubyHash defsites;
+    private RubyHash callsites;
+    private Pattern backtracePattern;
+
+    private CallsiteHook() {
+        super();
+        backtracePattern = new Pattern("^([^:]*):(\\d+)(:in `(.*)')?$");
+    }
+
+    public boolean isActive() {
+        return active;
+    }
+
+    public boolean isInterestedInEvent(int event) {
+        return event == RUBY_EVENT_CALL;
+    }
+
+    public RubyArray getCallsiteInfo(Ruby runtime) {
+        RubyArray info = runtime.newArray();
+        info.add(getCallsites(runtime));
+        info.add(getDefsites(runtime));
+        return info;
+    }
+
+    public void setActive(boolean active) {
+        this.active = active;
+    }
+
+    public RubyHash resetDefsites() {
+        defsites.clear();
+        return defsites;
+    }
+
+    public void event(ThreadContext context, int event, String file, int line,
+            String name, IRubyObject type) {
+        RubyArray currentMethod = context.getRuntime().newArray();
+        currentMethod.add(context.getFrameKlazz());
+        currentMethod.add(context.getRuntime().newSymbol(name));
+
+        RubyArray fileLoc = context.getRuntime().newArray();
+        fileLoc.add(file);
+        fileLoc.add(Long.valueOf(line));
+        
+        RubyHash defsites = getDefsites(context.getRuntime());
+        defsites.put(currentMethod, fileLoc);
+
+        RubyHash callsites = getCallsites(context.getRuntime());
+        if (!callsites.containsKey(currentMethod)) {
+            callsites.put(currentMethod, RubyHash.newHash(context.getRuntime()));
+        }
+        RubyHash hash = (RubyHash) callsites.get(currentMethod);
+
+        RubyArray callerArray = customBacktrace(context);
+        if (!hash.containsKey(callerArray)) {
+            hash.put(callerArray, Long.valueOf(0));
+        }
+        Long count = (Long) hash.get(callerArray);
+        long itCount = count.longValue() + 1L;
+        hash.put(callerArray, Long.valueOf(itCount));
+    }
+
+    private RubyArray customBacktrace(ThreadContext context) {
+        Frame[] frames = context.createBacktrace(1, false);
+        RubyArray backtrace = (RubyArray) ThreadContext
+                .createBacktraceFromFrames(context.getRuntime(), frames);
+
+        RubyArray ary = context.getRuntime().newArray();        
+        ary.add(frames[frames.length - 1].getKlazz());
+        ary.addAll(formatBacktrace(context.getRuntime(), (String) backtrace.get(1)));
+
+        return context.getRuntime().newArray((IRubyObject) ary);
+    }
+
+    private RubyArray formatBacktrace(Ruby runtime, String backtrace) {
+        Matcher matcher = backtracePattern.matcher(backtrace);
+
+        RubyArray ary = runtime.newArray();
+        if (matcher.matches()) {
+            String method = matcher.group(4);
+            String file = matcher.group(1);
+            String line = matcher.group(2);
+            Long lineNum = (line == null ? Long.valueOf(0) : Long.valueOf(line));
+
+            ary.add((method == null ? runtime.getNil() : runtime
+                    .newSymbol(method)));
+            ary.add(file);
+            ary.add(lineNum);
+        }
+        return ary;
+    }
+
+    private RubyHash getCallsites(Ruby runtime) {
+        if (this.callsites == null) {
+            this.callsites = RubyHash.newHash(runtime);
+        }
+        return this.callsites;
+    }
+
+    private RubyHash getDefsites(Ruby runtime) {
+        if (this.defsites == null) {
+            this.defsites = RubyHash.newHash(runtime);
+        }
+        return this.defsites;
+    }
+
+}

Added: trunk/rcov4jr/java/src/CoverageHook.java (0 => 683)


--- trunk/rcov4jr/java/src/CoverageHook.java	                        (rev 0)
+++ trunk/rcov4jr/java/src/CoverageHook.java	2007-08-08 04:02:46 UTC (rev 683)
@@ -0,0 +1,104 @@
+import org.jruby.Ruby;
+import org.jruby.RubyArray;
+import org.jruby.RubyHash;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+
+public class CoverageHook implements RcovHook {
+
+    private static CoverageHook hook;
+
+    public static CoverageHook getCoverageHook() {
+        if (hook == null) {
+            hook = new CoverageHook();
+        }
+        return hook;
+    }
+
+    private boolean active;
+    private RubyHash cover;
+    
+    private CoverageHook() {
+        super();
+    }
+
+    public boolean isActive() {
+        return active;
+    }
+
+    public void setActive(boolean active) {
+        this.active = active;
+    }
+
+    public void event(ThreadContext context, int event, String file, int line,
+            String name, IRubyObject type) {
+        
+        // Make sure that we have SCRIPT_LINES__ and it's a hash
+        RubyHash scriptLines = getScriptLines(context.getRuntime());
+        if (scriptLines == null || !scriptLines.containsKey(file)) {
+            return;
+        }
+        
+        // make sure the file's source lines are in SCRIPT_LINES__
+        RubyHash cover = getCover(context.getRuntime());
+        RubyArray lines = (RubyArray) scriptLines.get(file);
+        if (lines == null || cover == null){
+            return;
+        }
+        
+        // make sure file's counts are in COVER and set to zero
+        RubyArray counts = (RubyArray) cover.get(file);
+        if (counts == null) {
+            RubyArray ary = context.getRuntime().newArray();
+            for (int i = 0; i < lines.size(); i++) {
+                ary.add(Long.valueOf(0));
+            }
+            cover.put(file, ary);
+            counts = ary;
+        }
+        
+        // update counts in COVER
+        Long count = (Long) counts.get(line);
+        if (count == null) {
+            System.out.println("Null count in " + file + ":" + line + ":" + name);
+            count = Long.valueOf(0);
+        }
+        count = Long.valueOf(count.longValue() + 1);
+        counts.set(line , count);
+    }
+
+    public boolean isInterestedInEvent(int event) {
+//        return (event != RUBY_EVENT_C_CALL &&
+//                event != RUBY_EVENT_C_RETURN &&
+//                event != RUBY_EVENT_CLASS);
+        return event == RUBY_EVENT_CALL || event == RUBY_EVENT_LINE;
+    }
+    
+    /**
+     * Returns the COVER hash, setting up the COVER constant if necessary.
+     * @param runtime
+     * @return
+     */
+    public RubyHash getCover(Ruby runtime) {
+        if (cover == null) {
+            cover = RubyHash.newHash(runtime);
+        }
+        return cover;
+    }
+    
+    public RubyHash getScriptLines(Ruby runtime) {
+        IRubyObject scriptLines = runtime.getObject().getConstantAt("SCRIPT_LINES__");
+        if (scriptLines instanceof RubyHash) {
+            return (RubyHash) scriptLines;
+        } else {
+            return null;
+        }
+    }
+
+    public IRubyObject resetCoverage(Ruby runtime) {
+        getCover(runtime).clear();
+        return runtime.getNil();
+    }
+
+}

Added: trunk/rcov4jr/java/src/RcovHook.java (0 => 683)


--- trunk/rcov4jr/java/src/RcovHook.java	                        (rev 0)
+++ trunk/rcov4jr/java/src/RcovHook.java	2007-08-08 04:02:46 UTC (rev 683)
@@ -0,0 +1,11 @@
+import org.jruby.runtime.EventHook;
+
+
+public interface RcovHook extends EventHook {
+
+    /** returns true if the hook is set */
+    boolean isActive();
+    
+    /** used to mark the hook set or unset */
+    void setActive(boolean active);
+}

Added: trunk/rcov4jr/java/src/RcovrtService.java (0 => 683)


--- trunk/rcov4jr/java/src/RcovrtService.java	                        (rev 0)
+++ trunk/rcov4jr/java/src/RcovrtService.java	2007-08-08 04:02:46 UTC (rev 683)
@@ -0,0 +1,121 @@
+import org.jruby.Ruby;
+import org.jruby.RubyArray;
+import org.jruby.RubyFixnum;
+import org.jruby.RubyHash;
+import org.jruby.RubyModule;
+import org.jruby.RubySymbol;
+import org.jruby.exceptions.RaiseException;
+import org.jruby.runtime.CallbackFactory;
+import org.jruby.runtime.builtin.IRubyObject;
+import org.jruby.runtime.load.BasicLibraryService;
+
+public class RcovrtService implements BasicLibraryService {
+
+    public boolean basicLoad(Ruby runtime) {
+        RubyModule rcov = runtime.getModule("Rcov");
+        if (rcov == null) {
+            rcov = runtime.defineModule("Rcov");
+        }
+        RubyModule rcov__ = (RubyModule) rcov.getConstant("RCOV__");
+        if (rcov__ == null) {
+            rcov__ = rcov.defineModuleUnder("RCOV__");
+        }
+        IRubyObject sl = runtime.getObject().getConstantAt("SCRIPT_LINES__");
+        if (sl == null)
+            runtime.getObject().setConstant("SCRIPT_LINES__", RubyHash.newHash(runtime));
+
+        CallbackFactory rcovrt_cb = runtime
+                .callbackFactory(RcovrtService.class);
+        rcov__.getMetaClass().defineMethod("ABI", rcovrt_cb.getFastSingletonMethod("getAbi"));
+        rcov__.getMetaClass().defineMethod("generate_callsite_info", rcovrt_cb.getFastSingletonMethod("generateCallsiteInfo"));
+        rcov__.getMetaClass().defineMethod("install_callsite_hook", rcovrt_cb.getFastSingletonMethod("installCallsiteHook"));
+        rcov__.getMetaClass().defineMethod("remove_callsite_hook", rcovrt_cb.getFastSingletonMethod("removeCallsiteHook"));
+        rcov__.getMetaClass().defineMethod("generate_coverage_info", rcovrt_cb.getFastSingletonMethod("generateCoverageInfo"));
+        rcov__.getMetaClass().defineMethod("install_coverage_hook", rcovrt_cb.getFastSingletonMethod("installCoverageHook"));
+        rcov__.getMetaClass().defineMethod("remove_coverage_hook", rcovrt_cb.getFastSingletonMethod("removeCoverageHook"));
+        rcov__.getMetaClass().defineMethod("reset_coverage", rcovrt_cb.getFastSingletonMethod("resetCoverage"));
+        rcov__.getMetaClass().defineMethod("reset_callsite", rcovrt_cb.getFastSingletonMethod("resetCallsite"));
+
+        return true;
+    }
+
+    public static IRubyObject resetCallsite(IRubyObject recv) {
+        CallsiteHook hook = CallsiteHook.getCallsiteHook();
+        if (hook.isActive()) {
+            throw RaiseException.createNativeRaiseException(
+                    recv.getRuntime(),
+                    new RuntimeException("Cannot reset the callsite info in the middle of a traced run."));
+        }
+        return hook.resetDefsites();
+    }
+
+    public static IRubyObject resetCoverage(IRubyObject recv) {
+        CoverageHook hook = CoverageHook.getCoverageHook();
+        if (hook.isActive()) {
+            throw RaiseException.createNativeRaiseException(
+                    recv.getRuntime(),
+                    new RuntimeException("Cannot reset the coverage info in the middle of a traced run."));
+        }
+        return hook.resetCoverage(recv.getRuntime());
+    }
+
+    public static IRubyObject removeCoverageHook(IRubyObject recv) {
+        return removeRcovHook(recv, CoverageHook.getCoverageHook());
+    }
+
+    public static IRubyObject installCoverageHook(IRubyObject recv) {
+        return installRcovHook(recv, CoverageHook.getCoverageHook());
+    }
+
+    public static IRubyObject generateCoverageInfo(IRubyObject recv) {
+        IRubyObject cover = CoverageHook.getCoverageHook().getCover(recv.getRuntime()).dup();
+        RubyModule rcov__ = (RubyModule) recv.getRuntime().getModule("Rcov").getConstant("RCOV__");
+        if (rcov__.const_defined(RubySymbol.newSymbol(recv.getRuntime(), "COVER")).isTrue()) {
+            rcov__.remove_const(recv.getRuntime().newString("COVER"));
+        } 
+        rcov__.defineConstant("COVER", cover);
+        
+        return cover;
+    }
+
+    public static IRubyObject removeCallsiteHook(IRubyObject recv) {
+        return removeRcovHook(recv, CallsiteHook.getCallsiteHook());
+    }
+
+    public static IRubyObject installCallsiteHook(IRubyObject recv) {
+        return installRcovHook(recv, CallsiteHook.getCallsiteHook());
+    }
+
+    public static IRubyObject generateCallsiteInfo(IRubyObject recv) {
+        return CallsiteHook.getCallsiteHook().getCallsiteInfo(recv.getRuntime()).dup();
+    }
+
+    public static IRubyObject getAbi(IRubyObject recv) {
+        RubyArray ary = recv.getRuntime().newArray();
+        ary.add(RubyFixnum.int2fix(recv.getRuntime(), 2L));
+        ary.add(RubyFixnum.int2fix(recv.getRuntime(), 0L));
+        ary.add(RubyFixnum.int2fix(recv.getRuntime(), 0L));
+        return ary;
+    }
+    
+    private static IRubyObject removeRcovHook(IRubyObject recv, RcovHook hook) {
+        if (!hook.isActive()) {
+            hook.setActive(true);
+            recv.getRuntime().addEventHook(hook);
+            return recv.getRuntime().getTrue();
+        } else {
+            return recv.getRuntime().getFalse();
+        }
+    }
+    
+    private static IRubyObject installRcovHook(IRubyObject recv, RcovHook hook) {
+        if (!hook.isActive()) {
+            hook.setActive(true);
+            recv.getRuntime().addEventHook(hook);
+            return recv.getRuntime().getTrue();
+        } else {
+            return recv.getRuntime().getFalse();
+        }
+    }
+
+}
_______________________________________________
Jruby-extras-devel mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/jruby-extras-devel

Reply via email to