Class ExecutionEnvironment

java.lang.Object
gw.internal.gosu.parser.ExecutionEnvironment
All Implemented Interfaces:
IExecutionEnvironment

public class ExecutionEnvironment extends Object implements IExecutionEnvironment
  • Field Details

    • DEFAULT_PROJECT

      private static final IProject DEFAULT_PROJECT
    • INSTANCES

      private static final Map<Object,ExecutionEnvironment> INSTANCES
    • THE_ONE

      private static ExecutionEnvironment THE_ONE
    • CLASS_REDEFINER_THREAD

      public static final String CLASS_REDEFINER_THREAD
      See Also:
    • SPECIAL_CLASSES

      private static final List<String> SPECIAL_CLASSES
      "Special" java classes that will be used to locate "special" JARs which should be included in the classpath. This is a replacement to old SPECIAL_FILES variable.
    • _project

      private IProject _project
    • _modules

      private List<IModule> _modules
    • _defaultModule

      private IModule _defaultModule
    • _jreModule

      private IModule _jreModule
    • _rootModule

      private IModule _rootModule
    • _discretePackages

      private String[] _discretePackages
    • _state

      private TypeSystemState _state
    • counter

      private int counter
      Detect whether or not the jdwp agent is alive in this process, if so start a thread that wakes up every N seconds and checks to see if the ReloadClassesIndicator Java class has been redefined by a debugger. If so, it reloads Gosu classes that have changed.

      Why, you ask? Well since Gosu classes are not compiled to disk, the IDE hosting Gosu can't simply send the bytes in a conventional JDI redefineClasses() call. Yet it somehow needs to at least inform Gosu's type system in the target process that Gosu classes have changed. The JVMTI doesn't offer much help; there's no way to field an arbitrary call from the JDWP client, or for the client to send an arbitrary message. Nor is it possible to leverage the JVMTI's ability to handle method invocation etc. because the target thread must be suspended at a breakpoint, which is not necessarily the case during compilation, and certainly isn't the case for a thread dedicated to fielding such a call. What to do?

      We can leverage redefineClasses() after all. The idea is for the IDE compiler to redefine a class (via asm) designated as the "ReloadClassIndicator". This class lives inside Gosu's type system. It has a single method: public static long timestamp() and returns a literal value. If the target process is being debugged (jdwp agent detection), a thread in the target process starts immediately and waits a few seconds before calling the timestamp() method, it does this in a forever loop. If the timestamp value changes, we assume the IDE redefined the class with a new value to indicate classes have changed. In turn we find and reload changed classes. What could be more straight forward?

      An alternative approach would be for the IDE to establish an additional line of communication with the target process e.g., socket, memory, whatever. But that is messy (requires config on user's end) and error prone. One debug socket is plenty.

      Improvements to this strategy include supplying not only an indication that stuff has changed, but also the names of the classes that have changed. This would releive the target process from having to keep track timestamps on all loaded classes. This could be implemented by having the class return an array of names. An even better improvement would be to include not just the names, but also the source of the classes. This would enable the debuger to modify in memory the classes during a remote debugging session.

  • Constructor Details

    • ExecutionEnvironment

      private ExecutionEnvironment(IProject project)
  • Method Details