15

My question is: is it possible (in ANY way) to analyze and modify call stack (both content of frames and stack content) in runtime?

I'm looking for any possibility - low-level, unsafe or internal API, possibility to write C extension, etc. Only constraint: it should be usable in standard runtime, without debugging or profiling mode. This is the point where I'm doing research "is it possible at all?", not "is it good idea?".

I'd like to gather all local data from a frame, store it somewhere, and then remove that frame from stack, with possibility of restoring it later. Effectively that gives us continuations in JVM, and they will allow fast async frameworks (like gevents from python) and generator constructs (like those from python) to come up.

This may look like repeated question, but I've only found questions that were answered with "use Thread.currentThread().getStackTrace()" or "that should be done with debugging tools". There was similiar question to mine, but it was only answered in context of what asking guy wanted to do (work on async computations), while I need more general (java-stack oriented) answer. This question is similiar too, but as before, it is focused on parallelization, and answers are focused on that too.

I repeat: this is research step in process of coming up with new language feature proposal. I don't wanna risk corrupting anything in JVM - I'm looking for possibility, then I'm gonna analyse possible risks and look out for them. I know that manipulating stack by hand is ugly, but so is creating instances with ommiting consrtuctor - and it is basis for objenesis. Dirty hacks may be dirty, but they may help introducing something cool.

PS. I know that Quasar and Lightwolf exist, but, as above, those are concurrency-focused frameworks.

EDIT

Little clarification: I'm looking for something that will be compatible with future JVM and libraries versions. Preferably we're talking about something that is considered stable public API, but if the solution lies in something internal, yet almost standard or becoming standard after being internal (like sun.misc.Unsafe) - that will do too. If it is doable by C-extension using only C JVM API - that's ok. If that is doable with bytecode manipulation - that's ok too (I think that MAY be possible with ASM).

Community
  • 1
  • 1
Filip Malczak
  • 3,124
  • 24
  • 44
  • 1
    I haven't used it, but maybe you can do something with the [JVM Tool Interface](http://docs.oracle.com/javase/8/docs/platform/jvmti/jvmti.html). It has some [functions to work with stack frames](http://docs.oracle.com/javase/8/docs/platform/jvmti/jvmti.html#stack). – Jesper May 09 '15 at 10:10
  • Thanks! That looked promising, but unfortunately, it only allows popping frame (without even providing it after pop) and getting some primitive frame information. That's not enough to store and restore full execution context. – Filip Malczak May 09 '15 at 11:05
  • 1
    I'm afraid you can't do with stack more than JVMTI allows. JVM support would be required to do what you want. Even if you happen to successfully manipulate stack using direct memory access, the next JVM update may easily break this. – apangin May 09 '15 at 12:58
  • I'm gonna add little clarification about future compability, to avoid comments and answers warning me about JVM updates ;) Still, maybe someone knows something... – Filip Malczak May 09 '15 at 13:05
  • 1
    *"why it was decided to disallow it"* - It wasn't. Neither it was decided to *allow* it. The motivation for manipulating stack directly is not clear. If you want continuations in Java, there are [other ways](http://stackoverflow.com/questions/1456083/continuations-in-java) to achieve this. – apangin May 12 '15 at 11:24
  • Motivation shouldn't be the case here. Also, I didn't ask if it was possible, but how is it possible and if it isn't then why not? – Filip Malczak May 17 '15 at 11:52
  • imo, this would a piece of serious low level runtime functionality that no one had a use for. so let us now if you decide to implement it. – MarianP May 18 '15 at 12:56
  • @MarianP There's a really nice use: help revert JVM to a past state by manipulating the stack frames and the stack's contents. – mljrg Jun 07 '17 at 10:17

2 Answers2

6

I think there is a way achieving what you want using JVMTI.

Although you cannot directly do what you want (as stated in a comment above), you may instrument/redefine methods (or entire classes) at run time. So you could just define every method to call another method directly to "restore execution context" and as soon as you have the stack you want, redefine them with your original code.

For example: lets say you want to restore a stack where just A called B and B called C. When A is loaded, change the code to directly call B. As soon as B is loaded, redefine it to directly call C; Call the topmost method (A); As soon as C gets called (which should be very fast now), redefine A and B to their original code.

If there are multiple threads involved and parameter values that must be restored, it gets a little more complicated, but still doable with JVMTI. However, this would then be worth another question ;-).

Hope this helps. Feel free to contact me or comment if you need clarification on anything.

EDIT: Although I think it IS doable, I also think this is a lot (!!!) of work, especially when you want to restore parameters, local variables, and calling contexts (like this pointers, held locks, ...).

EDIT as requested: Assume the same stack as above (A calling B calling C). Although A, B, and C have arbitrary code inside them, just redfine them like this:

void A() { B(); } void B() { C(); } void C() { redefine(); }

As soon as you reach the redefine method, redefine all classes with their original code. Then you have the stack you want.

loonytune
  • 1,775
  • 11
  • 22
  • If I get it right: you want to modify method/class at class loading to wrap it up with some additional code? That is overcomplicating, I can easily add poor mans aspect in at least 3 different ways. My problem lies in storing and restoring context - all local variables and parameters, instruction counter ("where in methods body are we?", program counter but for single thread), etc. – Filip Malczak May 17 '15 at 09:41
  • no not wrapping it, just define it completely new in order to reproduce the stack you want to have. Then as soon as you have the stack, you redefine all methods with their original code and let them continue. That way you will also be able to restore parameters and this pointers (by a serialization method of your choice) and locks (just require them manually by adding a monitor enter). I don't see a chance yet to restore the topmost frame into any bytecode position but the first one though. – loonytune May 17 '15 at 20:51
  • Frankly, I still cannot see that. How is class loading connected to execution stack? – Filip Malczak May 18 '15 at 09:32
  • Because you can modify the code to create the stack you want. Let me give you an example: Assume the same stack as above (A calling B calling C). Although A, B, and C have arbitrary code inside them, just redfine them like this:

    void A() { B(); } void B() { C(); } void C() { redefine(); }

    As soon as you reach the redefine method, redefine all classes with their original code. Then you have the stack you want.

    – loonytune May 18 '15 at 11:22
  • Oh, I see now. That... well, that makes sense, though it really is hell lot of work. Anyway - enjoy, you've probably just got a bounty ;) – Filip Malczak May 18 '15 at 17:44
  • PS. Please, edit your answer so it contains comment above. If anyone will be looking for something like this again, it will be easier for him to find proper result ;) – Filip Malczak May 18 '15 at 17:45
  • That's what I meant in the end of my answer: Although I think it IS doable, it will be a LOT OF WORK. – loonytune May 19 '15 at 06:55
-3

Not sure in this tool, but you can check http://en.wikipedia.org/wiki/GNU_Debugger.

GDB offers extensive facilities for tracing and altering the execution of computer programs. The user can monitor and modify the values of programs' internal variables, and even call functions independently of the program's normal behavior.

Stan
  • 1,410
  • 10
  • 14
  • 3
    I know what debugger is. I specifically stated that I'm looking for a possibility to do this without any special mode. – Filip Malczak May 11 '15 at 21:16