07 Aug, 2009, Silenus wrote in the 1st comment:
Votes: 0
I am curious if anyone knows how this feature is typically implemented in the JVM since I have a similar feature in my server. The question is how is it possible if you hotswap some object x for extant objects to update w.r.t. the new program swapped in. Doe java allow the interface of the hotswapped to change completely? This would at first blush to me seem to entail a bit of a performance hit since you could not guarantee that the type required by an overloaded operator is the correct one (or does java not have many of these?).

Thanks in advance.
07 Aug, 2009, Kintar wrote in the 2nd comment:
Votes: 0
The JVM seriously limits what you can actually hotswap. You can add fields or methods to a class, or change the implementation of a method, but you can't change the signatures of methods, the types of fields, or (if I'm remembering correctly) remove fields or methods from an already defined class.

Basically, anything beyond replacing the actual instructions that a method executes takes a lot of deep magic. It's an issue that I've just managed to successfully solve in my component system engine by judicious use of swappable class loaders, runtime bytecode generation, and dynamic proxies. The hotswap features of the JVM were pretty much useless for the things I'm trying to do.
07 Aug, 2009, David Haley wrote in the 3rd comment:
Votes: 0
Hotswapping is not meant to be high-performance, and not all JVMs support it. And as Kintar said, you can't just arbitrarily change things willy-nilly; the restrictions make the problem somewhat saner.

Hotswapping isn't meant to be a full dynamic class reloading feature. It's more of a debugging tool for changing a method's implementation so that you can continue running without having to restart the entire program.
07 Aug, 2009, Kintar wrote in the 4th comment:
Votes: 0
P.S: I think IBM's JVM implementation allows class schema alterations (method signatures, etc.), but I've yet to see someone actually USE their implementation for anything other than piddling around and playing.
07 Aug, 2009, Silenus wrote in the 5th comment:
Votes: 0
You mean jikes?

From your description Kintar it seems a little restrictive compared to what LPC supports but full dynamic stuff in LPC is substantially slower because of added runtime checks.

DH. If the description Kintar mentioned is correct there should be no real change to the "linking" phases (perhaps functions might have to insert extra branch always if the method implementation is updated and the new code is larger than the required space to hold it).

I guess I was hoping for more since I could then use it to solve an existing problem with my server design but the description given is like the conservative stuff I have already figured out for my system.

Thanks both.
07 Aug, 2009, Kintar wrote in the 6th comment:
Votes: 0
Silenus; what exactly are you trying to do? If you give an example of the behavior you're looking for, I might be able to make some suggestions, as I just finished implementing a completely dynamic type system on top of Java for my MUD engine. (Thanks to a few helpful prods from David Haley, actually. :biggrin:)

I've basically got a system where you can define game-object types (weapon, container, room, etc.) in a simple DSL. Each component field is statically typed to either another component (game-object type) or to one of a select set of Java types, like String, int, float, etc. At any point while the system is running, you can alter the component definition to add or remove fields, or change field types, and the system will automatically generate new bytecode to support your new fields and reload the type into the classloader that the behavior system (user script container) uses.

Does that make any sense without a five-page explanation? :thinking:
07 Aug, 2009, Silenus wrote in the 7th comment:
Votes: 0
I am trying to implement a system which is similar in some ways to LPC which supports rather full dynamism in terms of linking policies since in principle call points are not linked at all and resolved entirely at runtime via hash table lookups and at the same time benefit from the performance of a more conservative system (faster in principle as well) using virtual function pointers. LPC drivers implement this in place recompilation of code differently depending on the driver. the DGD driver attempts to propagate recompiles to all inheritables and likewise updates the clones. FluffOS and LDMud dont do this- i.e. if something you inherit is updated you still use an old version of the program but allow for recompilation of objects and any call to outside functions to so called "blueprint" objects like the master object or efuns object call the new code automatically.

The thing I have been trying to figure out is how to implement a system with full dynamism of one of these two types without entailing very large lookup costs.
07 Aug, 2009, David Haley wrote in the 8th comment:
Votes: 0
You can always cache the lookups. Objects have pointers to a class, you ask the class for some member, it does some stuff, caches that lookup, and if the class is reloaded, the cache is wiped.

It is very difficult to mix very high performance and total dynamism.
07 Aug, 2009, Silenus wrote in the 9th comment:
Votes: 0
Thanks David. The caching strategy did occur to me but I was wondering if a broadcast to methods with relevant call sites on a code change (of affected methods) would be also a meaningful alternative (once you have something along the lines of the java hotswap implementation with a few twists). Obviously two things may occur. The code may not compile or the code will continue working. I am wondering if it maybe a viable strategy to replace these methods with a stub method which generates a runtime error (reporting the call site target has changed whenever these methods are called) either always or if an attempted recompile fails.
07 Aug, 2009, David Haley wrote in the 10th comment:
Votes: 0
If something doesn't compile, I would say that you shouldn't change anything at all in the actual loaded classes. Why would you want to introduce broken code into a running system?
07 Aug, 2009, Silenus wrote in the 11th comment:
Votes: 0
Wont this always be a problem in the case of if you in place recompile something? i.e. assuming even if you cache and clear the cache. the new function ptr looked up may be of the wrong type resulting in a runtime error. Essentially making the calling code in a sense invalid. Wouldnt replacing the caller be quite similar to have a runtime check in the caller type checking the callee?
07 Aug, 2009, David Haley wrote in the 12th comment:
Votes: 0
Don't "load" the new type until it is completely compiled – in other words, code that doesn't compile is a no-op.

I'm not sure why you're talking about what the calling code is doing since it would be going through a central cache, which takes care of returning the correct address.

If you don't like the cache, you can recompile everything that refers to the function, I suppose, but frankly I think that's overkill. I would implement it first, benchmark it, and decide if you need to improve it further. Chances are that you will not need to.
07 Aug, 2009, Silenus wrote in the 13th comment:
Votes: 0
Well the case I am thinking about is something along these lines-

int foo() { return … ; }


string foo() { return … ; }

(assuming there are no ad hoc polymorphic overloads). Assuming the new version (string foo()) compiles and you do a cache address lookup which resolves to string foo() wouldn't this case incorrect behavior in the caller unless the central cache + call hook had some clever code to determine the possible expect types and check if the new signature conformed to this? Or am I missing something?
07 Aug, 2009, David Haley wrote in the 14th comment:
Votes: 0
How do you expect to solve what are perhaps unsolvable problems? What would you expect to happen in this instance, even in the most ideal world possible?

Dynamism doesn't mean that you can magically change everything and have things still work. If you replace a function that returns an integer with one that returns a string, then everybody who expected an integer will get problems.

I guess I'm not sure what the constraints you're placing on your system are, so it's pretty hard to say anything more meaningful.
07 Aug, 2009, Silenus wrote in the 15th comment:
Votes: 0
Thanks David. I guess that LPC does cope with cases like this to some extent through the use of type tags and runtime checking. I am basically trying to emulate this behavior without the overhead and the only solution that seems like it fits the bill might be recompiling the callers in some manner to toss out exceptions if the new return type of the callee does not match. Yeah probably what I am talking about is a bit unclear :-). It's pretty unclear in my mind as well…
07 Aug, 2009, David Haley wrote in the 16th comment:
Votes: 0
I think you need to start with defining fairly clearly what the semantics here are. For example, what exactly can be reloaded at runtime, what can change, and what is supposed to happen when things change. If you can't define it in English, thinking about implementation is futile. :wink: