问题
I am writing part of a PHP web application (which will be used in a high school bug finding contest) where the user must find bugs in a given Java program. As a part of this, when the Java program executes, we want to highlight the lines of the source of the Java program where the code has executed. To do this, all we need are the line numbers of the source that have been executed, that is, the code path (or is it called code coverage?). We will highlight the lines in the source file using the line numbers.
We will be using PHP's shell-exec() to execute the Java program and the tool to get the code path (whatever that will be). What is the easiest way of getting the line numbers of code path?
Thank you very much!
Here is a picture that describes what we would like
回答1:
PHP interperts the code, which means it runs over the source each time you run the program. This has the benefit of blowing up as the code is read (which makes line number printouts trivial); however, it often is expensive in other ways, as you cannot optimize deeply (or do any pre-runtime error checking).
Java compiles its code into a JVM assembly language called "bytecode." This means that what is running doesn't generally have access to (or even use) the source code. That said, there are techniques. A compiled Java class has the ability to add "extra data" and one of those "extra data elements" is a line number table, which is an index allowing someone running the assembly to "look up" the line number as the compiler recorded it.
This generally works ok, with the considerations that: compilers often don't mark up every instruction, the source code may not be available, optimization might make certain inner chunks of code not function in ways that facilitate pointing to the input code text.
How code coverage tools "fix" this is that they generally insert into the code (at the assembly level) a large number of commands that effectively act as logging statements to a format that allows the tool to determine which path through the code was actually followed. This is then mapped back through the line number table as best as possible and then used to highlight lines within the original source file.
If you want something with finer resolution (something that can process which portion of a line was executed) then you need to dig deeper. Eventually you might even consider writing your own compiler (or compiler extension) which will store your own custom line number table that overcomes the shortcomings of the current solutions.
Tricks like throwing exceptions (as Shiven has mentioned) and parsing out the line number do work; however, they pollute your code with odd exception processing for items that really aren't exceptional, just to "get the line number". Due to the code clutter and the generally poorer runtime performance of exceptions, I tend to avoid such solutions (but they do work).
Anyway, hopefully this will give you a view as to why it doesn't always work exactly the same way as PHP.
回答2:
Take a look at Cobertura. It computes coverage and stuff like that, and if it doesn't already do it, it should be relatively easy to add the line number collecting to it. There's a very hackish attempt to do that, but that's so slow that you may not be able to use it in production https://bitbucket.org/jowu/myriapod/wiki/Home
回答3:
You could get a linenumber if you compile the program with the -g option, do a printStackTrace(), capture the trace output and extract the linenumber from there.
回答4:
I have never done or seen anything like this but it does seem like an interesting problem. My thought would be to use the java debugger (jdb) to run the code, rather than just the java
command.
You can step through the code line by line (via the step
command in jdb) and each time a line executes its line number is spit out. This would require a little help from the PHP side (it would have to parse the line number as well as execute the next step command) but the line numbers are there. Here is a sample output from a very basic java program.
Java (TestClass.java)
public class TestClass {
public static void main(String[] args) {
System.out.println("foo");
System.out.println("bar");
}
}
jdb (jdb TestClass after running javac TestClass.java
)
Initializing jdb ...
> stop at TestClass:3
Deferring breakpoint TestClass:3.
It will be set after the class is loaded.
> run
run TestClass
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
>
VM Started: Set deferred breakpoint TestClass:3
Breakpoint hit: "thread=main", TestClass.main(), line=3 bci=0
3 System.out.println("foo");
main[1] step
> foo
Step completed: "thread=main", TestClass.main(), line=4 bci=8
4 System.out.println("bar");
main[1] step
> bar
Step completed: "thread=main", TestClass.main(), line=5 bci=16
5 }
main[1] step
>
The application exited
回答5:
Try referring to this link JVMDI
You can try accessing the values of the program counter and then map it onto the lineNumberTable . OR I think JVMDI has a method which can access the line number of the executing code.I'm not sure of the latter,refer the to the link above and hope it helps.
来源:https://stackoverflow.com/questions/10853747/log-line-numbers-of-executed-java-code