Index: src/org/jruby/runtime/ReadonlyGlobalVariable.java =================================================================== --- src/org/jruby/runtime/ReadonlyGlobalVariable.java (revision 8091) +++ src/org/jruby/runtime/ReadonlyGlobalVariable.java (working copy) @@ -34,12 +34,12 @@ public class ReadonlyGlobalVariable extends GlobalVariable { - public ReadonlyGlobalVariable(Ruby runtime, String name, IRubyObject value) { - super(runtime, name, value); + public ReadonlyGlobalVariable(String name, IRubyObject value) { + super(name, value); } @Override public IRubyObject set(IRubyObject value) { - throw runtime.newNameError(name() + " is a read-only variable", name()); + throw Ruby.getCurrentRuntime().newNameError(name() + " is a read-only variable", name()); } } Index: src/org/jruby/runtime/GlobalVariable.java =================================================================== --- src/org/jruby/runtime/GlobalVariable.java (revision 8091) +++ src/org/jruby/runtime/GlobalVariable.java (working copy) @@ -39,7 +39,7 @@ private GlobalVariable other; public Copy(Ruby runtime, String name, GlobalVariable other) { - super(runtime, name, other.get()); + super(name, other.get()); this.other = other; } @@ -54,8 +54,6 @@ } } - protected final Ruby runtime; - protected final String name; private IRubyObject value; @@ -63,10 +61,8 @@ return "$" + name; } - public GlobalVariable(Ruby runtime, String name, IRubyObject value) { + public GlobalVariable(String name, IRubyObject value) { assert name.startsWith("$"); - - this.runtime = runtime; this.name = name; this.value = value; } Index: src/org/jruby/runtime/GlobalVariableAcessor.java =================================================================== --- src/org/jruby/runtime/GlobalVariableAcessor.java (revision 0) +++ src/org/jruby/runtime/GlobalVariableAcessor.java (revision 0) @@ -0,0 +1,24 @@ +package org.jruby.runtime; + +import org.jruby.runtime.IAccessor; +import org.jruby.runtime.GlobalVariable; +import org.jruby.runtime.builtin.IRubyObject; + +/** + * @author Fabio Kung +*/ +public class GlobalVariableAcessor implements IAccessor { + private final GlobalVariable variable; + + public GlobalVariableAcessor(GlobalVariable variable) { + this.variable = variable; + } + + public IRubyObject getValue() { + return variable.get(); + } + + public IRubyObject setValue(IRubyObject newValue) { + return variable.set(newValue); + } +} Index: src/org/jruby/ext/ffi/io/FileDescriptorIO.java =================================================================== --- src/org/jruby/ext/ffi/io/FileDescriptorIO.java (revision 8091) +++ src/org/jruby/ext/ffi/io/FileDescriptorIO.java (working copy) @@ -68,7 +68,7 @@ } catch (InvalidValueException ex) { throw new RuntimeException(ex); } - openFile.setMainStream(new ChannelStream(getRuntime(), + openFile.setMainStream(new ChannelStream( new ChannelDescriptor(Factory.getInstance().newByteChannel(RubyNumeric.fix2int(fd)), getNewFileno(), modes, new java.io.FileDescriptor()))); openFile.setPipeStream(openFile.getMainStream()); Index: src/org/jruby/ext/socket/RubyUNIXSocket.java =================================================================== --- src/org/jruby/ext/socket/RubyUNIXSocket.java (revision 8091) +++ src/org/jruby/ext/socket/RubyUNIXSocket.java (working copy) @@ -311,7 +311,7 @@ protected void init_sock(Ruby runtime) throws Exception { ModeFlags modes = new ModeFlags(ModeFlags.RDWR); - openFile.setMainStream(new ChannelStream(runtime, new ChannelDescriptor(new UnixDomainSocketChannel(fd), getNewFileno(), modes, new java.io.FileDescriptor()))); + openFile.setMainStream(new ChannelStream(new ChannelDescriptor(new UnixDomainSocketChannel(fd), getNewFileno(), modes, new java.io.FileDescriptor()))); openFile.setPipeStream(openFile.getMainStream()); openFile.setMode(modes.getOpenFileFlags()); openFile.getMainStream().setSync(true); Index: src/org/jruby/internal/runtime/GlobalVariables.java =================================================================== --- src/org/jruby/internal/runtime/GlobalVariables.java (revision 8091) +++ src/org/jruby/internal/runtime/GlobalVariables.java (working copy) @@ -47,13 +47,8 @@ * @author jpetersen */ public class GlobalVariables { - private Ruby runtime; private Map globalVariables = new ConcurrentHashMap(); - public GlobalVariables(Ruby runtime) { - this.runtime = runtime; - } - public void define(String name, IAccessor accessor) { assert name != null; assert accessor != null; @@ -89,15 +84,16 @@ assert name.startsWith("$"); assert oldName.startsWith("$"); - if (runtime.getSafeLevel() >= 4) { - throw runtime.newSecurityError("Insecure: can't alias global variable"); + if (Ruby.getCurrentRuntime().getSafeLevel() >= 4) { + throw Ruby.getCurrentRuntime().newSecurityError("Insecure: can't alias global variable"); } GlobalVariable oldVariable = createIfNotDefined(oldName); GlobalVariable variable = (GlobalVariable)globalVariables.get(name); if (variable != null && oldVariable != variable && variable.isTracing()) { - throw new RaiseException(runtime, runtime.getRuntimeError(), "can't alias in tracer", false); + throw new RaiseException(Ruby.getCurrentRuntime(), Ruby.getCurrentRuntime().getRuntimeError(), + "can't alias in tracer", false); } globalVariables.put(name, oldVariable); @@ -111,16 +107,16 @@ if (variable != null) { return variable.getAccessor().getValue(); } - runtime.getWarnings().warning(ID.GLOBAL_NOT_INITIALIZED, "global variable `" + name + "' not initialized", name); - return runtime.getNil(); + Ruby.getCurrentRuntime().getWarnings().warning(ID.GLOBAL_NOT_INITIALIZED, "global variable `" + name + "' not initialized", name); + return Ruby.getCurrentRuntime().getNil(); } public IRubyObject set(String name, IRubyObject value) { assert name != null; assert name.startsWith("$"); - if (runtime.getSafeLevel() >= 4) { - throw runtime.newSecurityError("Insecure: can't change global variable value"); + if (Ruby.getCurrentRuntime().getSafeLevel() >= 4) { + throw Ruby.getCurrentRuntime().newSecurityError("Insecure: can't change global variable value"); } GlobalVariable variable = createIfNotDefined(name); @@ -165,7 +161,7 @@ private GlobalVariable createIfNotDefined(String name) { GlobalVariable variable = (GlobalVariable)globalVariables.get(name); if (variable == null) { - variable = GlobalVariable.newUndefined(runtime, name); + variable = GlobalVariable.newUndefined(Ruby.getCurrentRuntime(), name); globalVariables.put(name, variable); } return variable; Index: src/org/jruby/internal/runtime/RuntimeVariableAccessor.java =================================================================== --- src/org/jruby/internal/runtime/RuntimeVariableAccessor.java (revision 0) +++ src/org/jruby/internal/runtime/RuntimeVariableAccessor.java (revision 0) @@ -0,0 +1,32 @@ +package org.jruby.internal.runtime; + +import org.jruby.runtime.IAccessor; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.Ruby; + +/** + * @author Fabio Kung + */ +public class RuntimeVariableAccessor implements IAccessor { + private final String name; + + public RuntimeVariableAccessor(String name) { + this.name = name; + } + + public RuntimeVariableAccessor(String name, IRubyObject value) { + this.name = name; + setValue(value); + } + + public IRubyObject getValue() { + Ruby runtime = Ruby.getCurrentRuntime(); + return runtime.getRuntimeVariable(this.name); + } + + public IRubyObject setValue(IRubyObject newValue) { + Ruby runtime = Ruby.getCurrentRuntime(); + runtime.setRuntimeVariable(this.name, newValue); + return newValue; + } +} Index: src/org/jruby/RubyArgsFile.java =================================================================== --- src/org/jruby/RubyArgsFile.java (revision 8091) +++ src/org/jruby/RubyArgsFile.java (working copy) @@ -39,6 +39,7 @@ import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.util.ByteList; +import org.jruby.internal.runtime.RuntimeVariableAccessor; public class RubyArgsFile { private static final class ArgsFileData { @@ -106,12 +107,13 @@ runtime.getEnumerable().extend_object(argsFile); - runtime.defineReadonlyVariable("$<", argsFile); + runtime.getGlobalVariables().defineReadonly("$<", new RuntimeVariableAccessor("$<", argsFile)); runtime.defineGlobalConstant("ARGF", argsFile); RubyClass argfClass = argsFile.getMetaClass(); argfClass.defineAnnotatedMethods(RubyArgsFile.class); - runtime.defineReadonlyVariable("$FILENAME", runtime.newString("-")); + runtime.getGlobalVariables().defineReadonly("$FILENAME", + new RuntimeVariableAccessor("$FILENAME", runtime.newString("-"))); } @JRubyMethod(name = {"fileno", "to_i"}) Index: src/org/jruby/RubyFile.java =================================================================== --- src/org/jruby/RubyFile.java (revision 8091) +++ src/org/jruby/RubyFile.java (working copy) @@ -165,7 +165,7 @@ super(runtime, runtime.getFile()); this.path = path; try { - this.openFile.setMainStream(new ChannelStream(runtime, new ChannelDescriptor(Channels.newChannel(in), getNewFileno(), new FileDescriptor()))); + this.openFile.setMainStream(new ChannelStream(new ChannelDescriptor(Channels.newChannel(in), getNewFileno(), new FileDescriptor()))); } catch (InvalidValueException ex) { throw runtime.newErrnoEINVALError(); } Index: src/org/jruby/Ruby.java =================================================================== --- src/org/jruby/Ruby.java (revision 8091) +++ src/org/jruby/Ruby.java (working copy) @@ -110,6 +110,7 @@ import org.jruby.runtime.ObjectSpace; import org.jruby.runtime.RubyEvent; import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.GlobalVariableAcessor; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.encoding.EncodingService; import org.jruby.runtime.load.Library; @@ -122,6 +123,7 @@ import org.jruby.util.JRubyClassLoader; import org.jruby.util.JavaNameMangler; import org.jruby.util.KCode; +import org.jruby.util.RuntimeContainer; import org.jruby.util.SafePropertyAccessor; import org.jruby.util.collections.WeakHashSet; import org.jruby.util.io.ChannelDescriptor; @@ -136,7 +138,7 @@ * multiple instances of each class. This means that in multi-runtime mode * (or really, multi-VM mode, where each JRuby instance is a ruby "VM"), objects * generally can't be transported across runtimes without marshaling. - * + * * This class roots everything that makes the JRuby runtime function, and * provides a number of utility methods for constructing global types and * accessing global runtime structures. @@ -183,16 +185,27 @@ config.setError(err); return newInstance(config); } - + + public static Ruby getCurrentRuntime() { + JRubyClassLoader loader = (JRubyClassLoader) Thread.currentThread().getContextClassLoader(); + while (!(loader instanceof RuntimeContainer)) { + loader = (JRubyClassLoader) loader.getParent(); + } + return ((RuntimeContainer) loader).getRuntime(); + } + /** * Create and initialize a new JRuby runtime. The properties of the * specified RubyInstanceConfig will be used to determine various JRuby * runtime characteristics. - * + * * @param config The configuration to use for the new instance * @see org.jruby.RubyInstanceConfig */ private Ruby(RubyInstanceConfig config) { + Thread currentThread = Thread.currentThread(); + currentThread.setContextClassLoader(new RuntimeContainer(currentThread.getContextClassLoader(), this)); + this.config = config; this.threadService = new ThreadService(this); if(config.isSamplingEnabled()) { @@ -209,18 +222,18 @@ this.beanManager = new BeanManager(this, config.isManagementEnabled()); this.jitCompiler = new JITCompiler(this); this.parserStats = new ParserStats(this); - + this.beanManager.register(new Config(this)); this.beanManager.register(parserStats); this.beanManager.register(new ClassCache(this)); } - + /** * Evaluates a script under the current scope (perhaps the top-level * scope) and returns the result (generally the last value calculated). * This version goes straight into the interpreter, bypassing compilation * and runtime preparation typical to normal script runs. - * + * * @param script The scriptlet to run * @returns The result of the eval */ @@ -229,7 +242,7 @@ DynamicScope currentScope = context.getCurrentScope(); ManyVarsDynamicScope newScope = new ManyVarsDynamicScope(new EvalStaticScope(currentScope.getStaticScope()), currentScope); Node node = parseEval(script, "