Skip to content

Commit

Permalink
First stab at getting transactional constants/classes/modules in plac…
Browse files Browse the repository at this point in the history
…e. Not working quite right yet.
  • Loading branch information
headius committed Aug 20, 2010
1 parent 08d3124 commit 49da36e
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 50 deletions.
1 change: 1 addition & 0 deletions build.xml
Expand Up @@ -307,6 +307,7 @@
<zipfileset src="${build.lib.dir}/joda-time-1.6.1.jar"/>
<zipfileset src="${build.lib.dir}/yydebug.jar"/>
<zipfileset src="${build.lib.dir}/nailgun-0.7.1.jar"/>
<zipfileset src="${build.lib.dir}/clojure.jar"/>
<metainf dir="${base.dir}/spi">
<include name="services/**"/>
</metainf>
Expand Down
Binary file removed build_lib/clj-ds.jar
Binary file not shown.
Binary file added build_lib/clojure.jar
Binary file not shown.
2 changes: 1 addition & 1 deletion nbproject/project.xml
Expand Up @@ -225,7 +225,7 @@
<java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/2">
<compilation-unit>
<package-root>${src.dir}</package-root>
<classpath mode="compile">build_lib/junit.jar:build_lib/jline-0.9.93.jar:build_lib/jna.jar:build_lib/nailgun-0.7.1.jar:build_lib/joni.jar:build_lib/dynalang-0.3.jar:build_lib/invokedynamic.jar:build_lib/jcodings.jar:build_lib/constantine.jar:build_lib/bytelist.jar:build_lib/jffi.jar:build_lib/yydebug.jar:build_lib/bsf.jar:build_lib/jaffl.jar:build_lib/asm-3.2.jar:build_lib/asm-analysis-3.2.jar:build_lib/asm-commons-3.2.jar:build_lib/asm-tree-3.2.jar:build_lib/asm-util-3.2.jar:build_lib/jsr292-mock.jar:build_lib/jgrapht-jdk1.5.jar:build_lib/jnr-netdb.jar:build_lib/jnr-posix.jar:build_lib/joda-time-1.6.1.jar:build_lib/livetribe-jsr223-2.0.6.jar:build_lib/clj-ds.jar</classpath>
<classpath mode="compile">build_lib/junit.jar:build_lib/jline-0.9.93.jar:build_lib/jna.jar:build_lib/nailgun-0.7.1.jar:build_lib/joni.jar:build_lib/dynalang-0.3.jar:build_lib/invokedynamic.jar:build_lib/jcodings.jar:build_lib/constantine.jar:build_lib/bytelist.jar:build_lib/jffi.jar:build_lib/yydebug.jar:build_lib/bsf.jar:build_lib/jaffl.jar:build_lib/asm-3.2.jar:build_lib/asm-analysis-3.2.jar:build_lib/asm-commons-3.2.jar:build_lib/asm-tree-3.2.jar:build_lib/asm-util-3.2.jar:build_lib/jsr292-mock.jar:build_lib/jgrapht-jdk1.5.jar:build_lib/jnr-netdb.jar:build_lib/jnr-posix.jar:build_lib/joda-time-1.6.1.jar:build_lib/livetribe-jsr223-2.0.6.jar:build_lib/clojure.jar</classpath>
<built-to>${jruby.classes.dir}</built-to>
<built-to>${lib.dir}/jruby.jar</built-to>
<javadoc-built-to>docs/api</javadoc-built-to>
Expand Down
20 changes: 15 additions & 5 deletions src/org/jruby/Ruby.java
Expand Up @@ -3206,7 +3206,9 @@ public RaiseException newIllegalSequence(String message) {
}

public RaiseException newNoMethodError(String message, String name, IRubyObject args) {
return new RaiseException(new RubyNoMethodError(this, getNoMethodError(), message, name, args), true);
RaiseException exception = new RaiseException(new RubyNoMethodError(this, getNoMethodError(), message, name, args), true);
exception.preRaise(getCurrentContext());
return exception;
}

public RaiseException newNameError(String message, String name) {
Expand All @@ -3221,20 +3223,26 @@ public RaiseException newNameError(String message, String name, Throwable origEx
if (printWhenVerbose && origException != null && this.isVerbose()) {
origException.printStackTrace(getErrorStream());
}
return new RaiseException(new RubyNameError(

RaiseException exception = new RaiseException(new RubyNameError(
this, getNameError(), message, name), false);
exception.preRaise(getCurrentContext());

return exception;
}

public RaiseException newLocalJumpError(RubyLocalJumpError.Reason reason, IRubyObject exitValue, String message) {
return new RaiseException(new RubyLocalJumpError(this, getLocalJumpError(), message, reason, exitValue), true);
RaiseException exception = new RaiseException(new RubyLocalJumpError(this, getLocalJumpError(), message, reason, exitValue), true);
exception.preRaise(getCurrentContext());
return exception;
}

public RaiseException newLocalJumpErrorNoBlock() {
return newLocalJumpError(RubyLocalJumpError.Reason.NOREASON, getNil(), "no block given");
}

public RaiseException newRedoLocalJumpError() {
return new RaiseException(new RubyLocalJumpError(this, getLocalJumpError(), "unexpected redo", RubyLocalJumpError.Reason.REDO, getNil()), true);
return newLocalJumpError(RubyLocalJumpError.Reason.REDO, getNil(), "unexpected redo");
}

public RaiseException newLoadError(String message) {
Expand All @@ -3258,7 +3266,9 @@ public RaiseException newSystemStackError(String message, StackOverflowError soe
}

public RaiseException newSystemExit(int status) {
return new RaiseException(RubySystemExit.newInstance(this, status));
RaiseException exception = new RaiseException(RubySystemExit.newInstance(this, status));
exception.preRaise(getCurrentContext());
return exception;
}

public RaiseException newIOError(String message) {
Expand Down
4 changes: 3 additions & 1 deletion src/org/jruby/RubyKernel.java
Expand Up @@ -267,7 +267,9 @@ private static IRubyObject methodMissing(ThreadContext context, IRubyObject recv
exArgs = new IRubyObject[]{msg, symbol};
}

throw new RaiseException((RubyException)exc.newInstance(context, exArgs, Block.NULL_BLOCK));
RaiseException exception = new RaiseException((RubyException)exc.newInstance(context, exArgs, Block.NULL_BLOCK));
exception.preRaise(context);
throw exception;
}

@JRubyMethod(name = "open", required = 1, optional = 2, frame = true, module = true, visibility = PRIVATE)
Expand Down
131 changes: 105 additions & 26 deletions src/org/jruby/RubyModule.java
Expand Up @@ -37,6 +37,11 @@
***** END LICENSE BLOCK *****/
package org.jruby;

import clojure.lang.APersistentMap;
import clojure.lang.IPersistentMap;
import clojure.lang.LockingTransaction;
import clojure.lang.PersistentHashMap;
import clojure.lang.Ref;
import static org.jruby.anno.FrameField.VISIBILITY;
import static org.jruby.runtime.Visibility.MODULE_FUNCTION;
import static org.jruby.runtime.Visibility.PRIVATE;
Expand All @@ -55,6 +60,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;

import org.jruby.anno.JRubyClass;
Expand Down Expand Up @@ -182,11 +188,15 @@ public boolean isInstance(IRubyObject object) {
}

public Map<String, IRubyObject> getConstantMap() {
return constants;
return (Map<String, IRubyObject>)constants.deref();
}

public IPersistentMap getPersistentConstants() {
return (IPersistentMap)constants.deref();
}

public synchronized Map<String, IRubyObject> getConstantMapForWrite() {
return constants == Collections.EMPTY_MAP ? constants = new ConcurrentHashMap<String, IRubyObject>(4, 0.9f, 1) : constants;
return (Map<String, IRubyObject>)constants.deref();
}

public void addIncludingHierarchy(IncludedModuleWrapper hierarchy) {
Expand All @@ -207,6 +217,11 @@ protected RubyModule(Ruby runtime, RubyClass metaClass, boolean objectSpace) {
// if (parent == null) parent = runtime.getObject();
setFlag(USER7_F, !isClass());
generation = runtime.getNextModuleGeneration();
try {
constants = new Ref(PersistentHashMap.EMPTY);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

/** used by MODULE_ALLOCATOR and RubyClass constructors
Expand Down Expand Up @@ -1069,19 +1084,28 @@ public synchronized void defineAliases(List<String> aliases, String oldName) {
}
invalidateCacheDescendants();
}

/** this method should be used only by interpreter or compiler
*
*/
public RubyClass defineOrGetClassUnder(String name, RubyClass superClazz) {
return defineOrGetClassUnder(name, superClazz, null);
}

public interface ModuleCallback {
public void call(RubyModule cls);
}

/** this method should be used only by interpreter or compiler
*
*/
public RubyClass defineOrGetClassUnder(final String name, final RubyClass superClazz, final ModuleCallback body) {
// This method is intended only for defining new classes in Ruby code,
// so it uses the allocator of the specified superclass or default to
// the Object allocator. It should NOT be used to define classes that require a native allocator.

Ruby runtime = getRuntime();
final Ruby runtime = getRuntime();
IRubyObject classObj = getConstantAt(name);
RubyClass clazz;

if (classObj != null) {
if (!(classObj instanceof RubyClass)) throw runtime.newTypeError(name + " is not a class");
clazz = (RubyClass)classObj;
Expand All @@ -1095,26 +1119,48 @@ public RubyClass defineOrGetClassUnder(String name, RubyClass superClazz) {
}

if (runtime.getSafeLevel() >= 4) throw runtime.newTypeError("extending class prohibited");
return clazz;
} else if (classProviders != null && (clazz = searchProvidersForClass(name, superClazz)) != null) {
// reopen a java class
} else {
if (superClazz == null) superClazz = runtime.getObject();
if (superClazz == runtime.getObject() && RubyInstanceConfig.REIFY_RUBY_CLASSES) {
clazz = RubyClass.newClass(runtime, superClazz, name, REIFYING_OBJECT_ALLOCATOR, this, true);
} else {
clazz = RubyClass.newClass(runtime, superClazz, name, superClazz.getAllocator(), this, true);
try {
clazz = (RubyClass)LockingTransaction.runInTransaction(new Callable() {
public Object call() throws Exception {
RubyClass superCls = superClazz;
RubyClass localClazz;
if (superCls == null) superCls = runtime.getObject();
if (superCls == runtime.getObject() && RubyInstanceConfig.REIFY_RUBY_CLASSES) {
localClazz = RubyClass.newClass(runtime, superCls, name, REIFYING_OBJECT_ALLOCATOR, RubyModule.this, true);
} else {
localClazz = RubyClass.newClass(runtime, superCls, name, superCls.getAllocator(), RubyModule.this, true);
}
if (body != null) {
body.call(localClazz);
}
return localClazz;
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}

}
return clazz;
}

/** this method should be used only by interpreter or compiler
*
*/
public RubyModule defineOrGetModuleUnder(String name) {
return defineOrGetModuleUnder(name, null);
}

/** this method should be used only by interpreter or compiler
*
*/
public RubyModule defineOrGetModuleUnder(String name) {
public RubyModule defineOrGetModuleUnder(final String name, final ModuleCallback body) {
// This method is intended only for defining new modules in Ruby code
Ruby runtime = getRuntime();
final Ruby runtime = getRuntime();
IRubyObject moduleObj = getConstantAt(name);
RubyModule module;
if (moduleObj != null) {
Expand All @@ -1124,7 +1170,19 @@ public RubyModule defineOrGetModuleUnder(String name) {
} else if (classProviders != null && (module = searchProvidersForModule(name)) != null) {
// reopen a java module
} else {
module = RubyModule.newModule(runtime, name, this, true);
try {
module = (RubyModule)LockingTransaction.runInTransaction(new Callable() {
public Object call() throws Exception {
RubyModule module = RubyModule.newModule(runtime, name, RubyModule.this, true);
if (body != null) {
body.call(module);
}
return module;
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return module;
}
Expand Down Expand Up @@ -1447,9 +1505,15 @@ public IRubyObject initialize_copy(IRubyObject original) {
return this;
}

public void syncConstants(RubyModule other) {
if (other.getConstantMap() != Collections.EMPTY_MAP) {
getConstantMapForWrite().putAll(other.getConstantMap());
public void syncConstants(final RubyModule other) {
try {
LockingTransaction.runInTransaction(new Callable() {
public Object call() throws Exception {
return constants.set(getPersistentConstants().cons(other.getPersistentConstants()));
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}

Expand Down Expand Up @@ -3082,18 +3146,33 @@ protected IRubyObject constantTableFastFetch(String internedName) {
return getConstantMap().get(internedName);
}

protected IRubyObject constantTableStore(String name, IRubyObject value) {
getConstantMapForWrite().put(name, value);
protected IRubyObject constantTableStore(final String name, final IRubyObject value) {
try {
LockingTransaction.runInTransaction(new Callable() {
public Object call() throws Exception {
return constants.set(((IPersistentMap)constants.deref()).assoc(name, value));
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
return value;
}

protected IRubyObject constantTableFastStore(String internedName, IRubyObject value) {
getConstantMapForWrite().put(internedName, value);
return value;
protected IRubyObject constantTableFastStore(final String internedName, final IRubyObject value) {
return constantTableStore(internedName, value);
}

protected IRubyObject constantTableRemove(String name) {
return getConstantMapForWrite().remove(name);
protected IRubyObject constantTableRemove(final String name) {
try {
return (IRubyObject)LockingTransaction.runInTransaction(new Callable() {
public Object call() throws Exception {
return constants.set(((IPersistentMap)constants.deref()).without(name));
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private static void define(RubyModule module, JavaMethodDescriptor desc, DynamicMethod dynamicMethod) {
Expand Down Expand Up @@ -3182,7 +3261,7 @@ private static void define(RubyModule module, JavaMethodDescriptor desc, Dynamic
// If it is null, then it an anonymous class.
protected String classId;

private volatile Map<String, IRubyObject> constants = Collections.EMPTY_MAP;
private final Ref constants;
private volatile Map<String, DynamicMethod> methods = Collections.EMPTY_MAP;
private Map<String, CacheEntry> cachedMethods = Collections.EMPTY_MAP;
protected int generation;
Expand Down
17 changes: 9 additions & 8 deletions src/org/jruby/ast/ClassNode.java
Expand Up @@ -118,7 +118,7 @@ public List<Node> childNodes() {
}

@Override
public IRubyObject interpret(Ruby runtime, ThreadContext context, IRubyObject self, Block aBlock) {
public IRubyObject interpret(final Ruby runtime, final ThreadContext context, final IRubyObject self, final Block aBlock) {
RubyModule enclosingClass = cpath.getEnclosingModule(runtime, context, self, aBlock);

// TODO: Figure out how this can happen and possibly remove
Expand All @@ -132,14 +132,15 @@ public IRubyObject interpret(Ruby runtime, ThreadContext context, IRubyObject se
superClass = (RubyClass)superObj;
}

boolean definedAlready = enclosingClass.isConstantDefined(cpath.getName());

RubyClass clazz = enclosingClass.defineOrGetClassUnder(cpath.getName(), superClass);

scope.setModule(clazz);
final IRubyObject[] classBodyResult = new IRubyObject[1];
RubyClass clazz = enclosingClass.defineOrGetClassUnder(cpath.getName(), superClass, new RubyModule.ModuleCallback() {
public void call(RubyModule cls) {
scope.setModule(cls);

IRubyObject classBodyResult = ASTInterpreter.evalClassDefinitionBody(runtime, context, scope, bodyNode, clazz, self, aBlock);
classBodyResult[0] = ASTInterpreter.evalClassDefinitionBody(runtime, context, scope, bodyNode, cls, self, aBlock);
}
});

return classBodyResult;
return classBodyResult[0];
}
}
16 changes: 10 additions & 6 deletions src/org/jruby/ast/ModuleNode.java
Expand Up @@ -106,17 +106,21 @@ public List<Node> childNodes() {
}

@Override
public IRubyObject interpret(Ruby runtime, ThreadContext context, IRubyObject self, Block aBlock) {
public IRubyObject interpret(final Ruby runtime, final ThreadContext context, final IRubyObject self, final Block aBlock) {
RubyModule enclosingModule = cpath.getEnclosingModule(runtime, context, self, aBlock);

// TODO: Figure out how this can happen and possibly remove
if (enclosingModule == null) throw runtime.newTypeError("no outer class/module");

String name = cpath.getName();
final IRubyObject[] moduleBodyResult = new IRubyObject[1];
RubyModule module = enclosingModule.defineOrGetModuleUnder(cpath.getName(), new RubyModule.ModuleCallback() {
public void call(RubyModule module) {
scope.setModule(module);

RubyModule module = enclosingModule.defineOrGetModuleUnder(name);
moduleBodyResult[0] = ASTInterpreter.evalClassDefinitionBody(runtime, context, scope, bodyNode, module, self, aBlock);
}
});

scope.setModule(module);

return ASTInterpreter.evalClassDefinitionBody(runtime, context, scope, bodyNode, module, self, aBlock);
return moduleBodyResult[0];
}
}
6 changes: 3 additions & 3 deletions src/org/jruby/embed/ScriptingContainer.java
Expand Up @@ -1463,7 +1463,7 @@ public void setReader(Reader reader) {
RubyIO io = new RubyIO(runtime, istream);
io.getOpenFile().getMainStream().setSync(true);
runtime.defineVariable(new InputGlobalVariable(runtime, "$stdin", io));
runtime.getObject().getConstantMapForWrite().put("STDIN", io);
runtime.getObject().setConstant("STDIN", io);
}

/**
Expand Down Expand Up @@ -1521,7 +1521,7 @@ private void setOutputStream(PrintStream pstream) {
RubyIO io = new RubyIO(runtime, pstream);
io.getOpenFile().getMainStream().setSync(true);
runtime.defineVariable(new OutputGlobalVariable(runtime, "$stdout", io));
runtime.getObject().getConstantMapForWrite().put("STDOUT", io);
runtime.getObject().setConstant("STDOUT", io);
runtime.getGlobalVariables().alias("$>", "$stdout");
runtime.getGlobalVariables().alias("$defout", "$stdout");
}
Expand Down Expand Up @@ -1586,7 +1586,7 @@ private void setErrorStream(PrintStream error) {
RubyIO io = new RubyIO(runtime, error);
io.getOpenFile().getMainStream().setSync(true);
runtime.defineVariable(new OutputGlobalVariable(runtime, "$stderr", io));
runtime.getObject().getConstantMapForWrite().put("STDERR", io);
runtime.getObject().setConstant("STDERR", io);
runtime.getGlobalVariables().alias("$deferr", "$stderr");
}

Expand Down

0 comments on commit 49da36e

Please sign in to comment.