Unfortunately I cannot disagree with what you stated. Obviously I missed some details of the JVM spec (Admittedly I did not read it from beginning to end ;-) ). Thanks alot for these valuable explanations.
Although none of the mentioned cases ever occured until now in my environment, it is not guaranteed that this cannot not happen at some future point of time.
Nevertheless I'm still wondering about the full consequences of the sections you cited. Particualrly, wouldn't the first citation mean, that I can never wrap an exception handler around code that has not been compiled with a surrounding exception handler, i. e. I could solely nest new exception handlers in existing (since compilaiton) ones? Otherwise it would be in general impossible to modify the code in a way that guarantees that there are no uninitialized class instances in local variables without risking to break the intended logic.
If this is really true, I'm in trouble, since I cannot think of any other way to create something like try-finally on the bytecode level.
Cheers,
Volker.
Peter Schneider wrote:
Hi,Hi
I'm forwarding a mail regarding bytecode
instrumentation, more specifically "encapsulating a
method body in a try-finally block" through dynamic
instrumentation. I'm forwarding it to the archiving
list for two reasons: first, it will help others who
wants to know about it & second, for experts who can
correct us in case there is some thing wrong in it.
I have read the proposed modification, but i have to remark that this
won't work that easily.
The critical point is, that bytecode has to fullfill strict constraints.
Or the verifier will reject it.
[...]
As you correctly stated there are two ways to exit a method on the bytcode level: by explicitly returningcode
or by throwing an exception. In BCEL you can cope with the second one easily by adding a new exception handler that encloses the critical
section. You can do so by calling MethodGen.addExceptionHandler(...). The last parameter to this method takes the type of exceptionSimply try catch the whole method body isn't possible in general,
to be caught by this handler. To accept any type, simply use null. At the target of the exception handler you
have to jump to your finally block.
if the method stores unitialized objects in local variables this
strategy will fail.
(JVMSPEC)# There must never be an uninitialized class instance on the
operand stack or in a local variable when any backwards branch is taken.
There must never be an uninitialized class instance in a local variable
in code protected by an exception handler. However, an uninitialized
class instance may be on the operand stack in code protected by an
exception handler. When an exception is thrown, the contents of the
operand stack are discarded.
Secondly you have to insert code before each return instruction in the method code, which is slightly more complicated. I did so by utilizing the Visitor facility of BCEL. A convenient way is to sublcass org.apache.bcel.generic.EmptyVisitor and overwrite all visit* methods that handle return instructions, e.g. visitRETURN, visitARETURN, etc.Again it's not that simple, If you use a nice compiler this will work,
For example in my code the visitDRETURN (for double values) looks like the following:
//double has a word size of 2
public void visitDRETURN(DRETURN obj) {
if (max - offset < 2) max += (2 - max + offset);
//store away return value on the stack
code.insert(handle, new DSTORE(offset + 1));
code.insert(handle, new JSR(finallyClause));
code.insert(handle, new DLOAD(offset + 1));
}
but there is no guarantee that the stack will contain a single item when
returning.
If some stack items are discarded through return, then this simple jump
will lead to a constraint violation. This only happens with compilers that optimize, and the sun compiler
even produces dead code, so you don't have to fear it will ever produce
something like that.
(JVMSPEC)# If an instruction can be executed along several different
execution paths, the operand stack must have the same depth (�3.6.2)
prior to the execution of the instruction, regardless of the path taken.
--
To unsubscribe, e-mail: <mailto:bcel-user-unsubscribe@;jakarta.apache.org>
For additional commands, e-mail: <mailto:bcel-user-help@;jakarta.apache.org>
-- To unsubscribe, e-mail: <mailto:bcel-user-unsubscribe@;jakarta.apache.org> For additional commands, e-mail: <mailto:bcel-user-help@;jakarta.apache.org>
