Skip to content

Commit

Permalink
Showing 47 changed files with 535 additions and 237 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@ env:
- JAVA_OPTS="-XX:+TieredCompilation -XX:TieredStopAtLevel=1 -Djruby.cext.enabled=false"
matrix:
- TARGET='-Ptest'
- TARGET='-Pjruby_complete_jar_jruby'
- TARGET='-Prake -Dtask=test:rubicon'
- TARGET='-Prake -Dtask=test:jruby'
- TARGET='-Prake -Dtask=test:mri'
@@ -53,6 +54,7 @@ matrix:
allow_failures:
- env: TARGET='-Pcomplete'
- env: TARGET='-Prake -Dtask=spec:jrubyc'
- env: TARGET='-Pjruby_complete_jar_jruby'
- env: TARGET='-Pj2ee'
- env: TARGET='-Prake -Dtask=spec:profiler'

21 changes: 7 additions & 14 deletions core/src/main/java/org/jruby/truffle/nodes/ReadConstantNode.java
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.source.*;
import com.oracle.truffle.api.frame.*;
import org.jruby.truffle.nodes.core.TruffleDebugNodes;
import org.jruby.truffle.nodes.dispatch.Dispatch;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
import org.jruby.truffle.runtime.*;
@@ -23,24 +24,18 @@
public class ReadConstantNode extends RubyNode {

private final String name;
private final LexicalScope lexicalScope;
@Child protected RubyNode receiver;
@Child protected DispatchHeadNode dispatch;

public ReadConstantNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver) {
public ReadConstantNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, LexicalScope lexicalScope) {
super(context, sourceSection);
this.name = name;
this.lexicalScope = lexicalScope;
this.receiver = receiver;
dispatch = new DispatchHeadNode(context, Dispatch.MissingBehavior.CALL_CONST_MISSING);
}

private LexicalScope getLexicalScope(VirtualFrame frame) {
MethodLike method = RubyArguments.getMethod(frame.getArguments());
if (method != null) {
return method.getSharedMethodInfo().getLexicalScope();
}
return null;
}

@Override
public Object execute(VirtualFrame frame) {
final Object receiverObject = receiver.execute(frame);
@@ -50,8 +45,6 @@ public Object execute(VirtualFrame frame) {
throw new RaiseException(getContext().getCoreLibrary().typeErrorIsNotA(receiverObject.toString(), "class/module", this));
}

LexicalScope lexicalScope = getLexicalScope(frame);

return dispatch.dispatch(
frame,
getContext().getCoreLibrary().getNilObject(),
@@ -97,10 +90,10 @@ public Object isDefined(VirtualFrame frame) {
throw e;
}

LexicalScope lexicalScope = getLexicalScope(frame);
RubyConstant constant = ModuleOperations.lookupConstant(lexicalScope, (RubyModule) receiverObject, name);
RubyModule module = (RubyModule) receiverObject; // TODO(cs): cast
RubyConstant constant = ModuleOperations.lookupConstant(context, lexicalScope, module, name);

if (constant == null) {
if (constant == null || !constant.isVisibleTo(context, lexicalScope, module)) {
return getContext().getCoreLibrary().getNilObject();
} else {
return context.makeString("constant");
Original file line number Diff line number Diff line change
@@ -21,8 +21,7 @@
import java.math.BigInteger;

/**
* Casts a value into a boolean. Works at the language level, so doesn't call any Ruby methods to
* cast non-core or monkey-patched objects.
* Casts a value into a boolean.
*/
@NodeChild(value = "child", type = RubyNode.class)
public abstract class BooleanCastNode extends RubyNode {
@@ -40,6 +39,11 @@ public boolean doNil(@SuppressWarnings("unused") RubyNilClass nil) {
return false;
}

@Specialization
public boolean doFalse(@SuppressWarnings("unused") RubyFalseClass falseObject) {
return false;
}

@Specialization
public boolean doBoolean(boolean value) {
return value;
@@ -65,9 +69,14 @@ public boolean doFloat(double value) {
return true;
}

@Specialization
@Specialization(guards = "neitherNilNorFalse")
public boolean doBasicObject(RubyBasicObject object) {
return object.isTrue();
return true;
}

protected boolean neitherNilNorFalse(RubyBasicObject object) {
return object != getContext().getCoreLibrary().getNilObject() &&
object != getContext().getCoreLibrary().getFalseObject();
}

@Override
32 changes: 31 additions & 1 deletion core/src/main/java/org/jruby/truffle/nodes/core/ClassNodes.java
Original file line number Diff line number Diff line change
@@ -9,13 +9,16 @@
*/
package org.jruby.truffle.nodes.core;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
import org.jruby.truffle.runtime.ModuleOperations;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.UndefinedPlaceholder;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyClass;
import org.jruby.truffle.runtime.core.RubyProc;
import org.jruby.truffle.runtime.core.RubyString;
@@ -26,18 +29,45 @@
@CoreClass(name = "Class")
public abstract class ClassNodes {

@CoreMethod(names = "allocate")
public abstract static class AllocateNode extends CoreMethodNode {

public AllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public AllocateNode(AllocateNode prev) {
super(prev);
}

public abstract RubyBasicObject executeAllocate(VirtualFrame frame, RubyClass rubyClass);

@Specialization
public RubyBasicObject allocate(RubyClass rubyClass) {
if (rubyClass.isSingleton()) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().typeError("can't create instance of singleton class", this));
}
return rubyClass.newInstance(this);
}

}

@CoreMethod(names = "new", needsBlock = true, argumentsAsArray = true)
public abstract static class NewNode extends CoreMethodNode {

@Child protected AllocateNode allocateNode;
@Child protected DispatchHeadNode initialize;

public NewNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
allocateNode = ClassNodesFactory.AllocateNodeFactory.create(context, sourceSection, new RubyNode[]{null});
initialize = DispatchHeadNode.onSelf(context);
}

public NewNode(NewNode prev) {
super(prev);
allocateNode = prev.allocateNode;
initialize = prev.initialize;
}

@@ -52,7 +82,7 @@ public RubyBasicObject newInstance(VirtualFrame frame, RubyClass rubyClass, Obje
}

private RubyBasicObject doNewInstance(VirtualFrame frame, RubyClass rubyClass, Object[] args, RubyProc block) {
final RubyBasicObject instance = rubyClass.newInstance(this);
final RubyBasicObject instance = allocateNode.executeAllocate(frame, rubyClass);
initialize.call(frame, instance, "initialize", block, args);
return instance;
}
Original file line number Diff line number Diff line change
@@ -64,7 +64,7 @@ private static void addMethod(RubyClass rubyObjectClass, MethodDetails methodDet
module = rubyObjectClass;

for (String moduleName : methodDetails.getClassAnnotation().name().split("::")) {
module = (RubyModule) ModuleOperations.lookupConstant(null, module, moduleName).getValue();
module = (RubyModule) ModuleOperations.lookupConstant(context, null, module, moduleName).getValue();
}
}

20 changes: 10 additions & 10 deletions core/src/main/java/org/jruby/truffle/nodes/core/KernelNodes.java
Original file line number Diff line number Diff line change
@@ -1094,23 +1094,23 @@ public MethodsNode(MethodsNode prev) {
}

@Specialization
public RubyArray methods(RubyObject self, boolean includeInherited) {
notDesignedForCompilation();

if (!includeInherited) {
getContext().getRuntime().getWarnings().warn(IRubyWarnings.ID.TRUFFLE, Truffle.getRuntime().getCallerFrame().getCallNode().getEncapsulatingSourceSection().getSource().getName(), Truffle.getRuntime().getCallerFrame().getCallNode().getEncapsulatingSourceSection().getStartLine(), "Object#methods always returns inherited methods at the moment");
}

return methods(self, UndefinedPlaceholder.INSTANCE);
public RubyArray methods(RubyObject self, @SuppressWarnings("unused") UndefinedPlaceholder unused) {
return methods(self, true);
}

@Specialization
public RubyArray methods(RubyObject self, @SuppressWarnings("unused") UndefinedPlaceholder includeInherited) {
public RubyArray methods(RubyObject self, boolean includeInherited) {
notDesignedForCompilation();

final RubyArray array = new RubyArray(self.getContext().getCoreLibrary().getArrayClass());

final Map<String, RubyMethod> methods = ModuleOperations.getAllMethods(self.getMetaClass());
Map<String, RubyMethod> methods;

if (includeInherited) {
methods = ModuleOperations.getAllMethods(self.getMetaClass());
} else {
methods = self.getMetaClass().getMethods();
}

for (RubyMethod method : methods.values()) {
if (method.getVisibility() == Visibility.PUBLIC || method.getVisibility() == Visibility.PROTECTED) {
26 changes: 14 additions & 12 deletions core/src/main/java/org/jruby/truffle/nodes/core/ModuleNodes.java
Original file line number Diff line number Diff line change
@@ -37,6 +37,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@CoreClass(name = "Module")
public abstract class ModuleNodes {
@@ -491,15 +492,15 @@ public ConstDefinedNode(ConstDefinedNode prev) {
public boolean isConstDefined(RubyModule module, RubyString name, @SuppressWarnings("unused") UndefinedPlaceholder inherit) {
notDesignedForCompilation();

return ModuleOperations.lookupConstant(null, module, name.toString()) != null;
return ModuleOperations.lookupConstant(getContext(), null, module, name.toString()) != null;
}

@Specialization
public boolean isConstDefined(RubyModule module, RubyString name, boolean inherit) {
notDesignedForCompilation();

if (inherit) {
return ModuleOperations.lookupConstant(null, module, name.toString()) != null;
return ModuleOperations.lookupConstant(getContext(), null, module, name.toString()) != null;
} else {
return module.getConstants().containsKey(name.toString());
}
@@ -509,7 +510,7 @@ public boolean isConstDefined(RubyModule module, RubyString name, boolean inheri
public boolean isConstDefined(RubyModule module, RubySymbol name, @SuppressWarnings("unused") UndefinedPlaceholder inherit) {
notDesignedForCompilation();

return ModuleOperations.lookupConstant(null, module, name.toString()) != null;
return ModuleOperations.lookupConstant(getContext(), null, module, name.toString()) != null;
}

}
@@ -1112,28 +1113,29 @@ public InstanceMethodsNode(InstanceMethodsNode prev) {
public RubyArray instanceMethods(RubyModule module, UndefinedPlaceholder argument) {
notDesignedForCompilation();

return instanceMethods(module, false);
return instanceMethods(module, true);
}

@Specialization
public RubyArray instanceMethods(RubyModule module, boolean includeAncestors) {
notDesignedForCompilation();

final List<RubyMethod> methods = new ArrayList<>(module.getMethods().values());
Map<String, RubyMethod> methods;

if (includeAncestors) {
for (RubyModule parent : module.parentAncestors()) {
methods.addAll(parent.getMethods().values());
}
methods = ModuleOperations.getAllMethods(module);
} else {
methods = module.getMethods();
}

final RubyArray array = new RubyArray(getContext().getCoreLibrary().getArrayClass());
for (RubyMethod method : methods) {
if (method.getVisibility() != Visibility.PRIVATE){
RubySymbol m = getContext().newSymbol(method.getName());
for (RubyMethod method : methods.values()) {
if (method.getVisibility() != Visibility.PRIVATE && !method.isUndefined()) {
// TODO(CS): shoudln't be using this
array.slowPush(m);
array.slowPush(getContext().newSymbol(method.getName()));
}
}

return array;
}
}
Original file line number Diff line number Diff line change
@@ -60,7 +60,18 @@ protected RubyConstant lookupConstant(
String name,
boolean ignoreVisibility,
Dispatch.DispatchAction dispatchAction) {
return ModuleOperations.lookupConstant(lexicalScope, module, name);
RubyConstant constant = ModuleOperations.lookupConstant(getContext(), lexicalScope, module, name);

// If no constant was found, use #const_missing
if (constant == null) {
return null;
}

if (!ignoreVisibility && !constant.isVisibleTo(getContext(), lexicalScope, module)) {
throw new RaiseException(getContext().getCoreLibrary().nameErrorPrivateConstant(module, name, this));
}

return constant;
}

@CompilerDirectives.SlowPath
Original file line number Diff line number Diff line change
@@ -11,7 +11,6 @@

import com.oracle.truffle.api.source.*;
import com.oracle.truffle.api.frame.*;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import org.jruby.truffle.nodes.*;
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.control.*;
@@ -20,16 +19,12 @@
/**
* Define a new class, or get the existing one of the same name.
*/
public class DefineOrGetClassNode extends RubyNode {
public class DefineOrGetClassNode extends DefineOrGetModuleNode {

private final String name;
@Child protected RubyNode lexicalParentModule;
@Child protected RubyNode superClass;

public DefineOrGetClassNode(RubyContext context, SourceSection sourceSection, String name, RubyNode lexicalParentModule, RubyNode superClass) {
super(context, sourceSection);
this.name = name;
this.lexicalParentModule = lexicalParentModule;
super(context, sourceSection, name, lexicalParentModule);
this.superClass = superClass;
}

@@ -39,17 +34,10 @@ public Object execute(VirtualFrame frame) {

final RubyContext context = getContext();

RubyModule lexicalParentModuleObject;

try {
lexicalParentModuleObject = lexicalParentModule.executeRubyModule(frame);
} catch (UnexpectedResultException e) {
throw new RaiseException(context.getCoreLibrary().typeErrorIsNotA(e.getResult().toString(), "module", this));
}

// Look for a current definition of the class, or create a new one

final RubyConstant constant = lexicalParentModuleObject.getConstants().get(name);
RubyModule lexicalParent = getLexicalParentModule(frame);
final RubyConstant constant = lookupForExistingModule(frame, lexicalParent);

RubyClass definingClass;
RubyClass superClassObject = getRubySuperClass(frame, context);
@@ -60,15 +48,14 @@ public Object execute(VirtualFrame frame) {
} else if (superClassObject instanceof RubyString.RubyStringClass) {
definingClass = new RubyString.RubyStringClass(superClassObject);
} else {
definingClass = new RubyClass(this, lexicalParentModuleObject, superClassObject, name);
definingClass = new RubyClass(lexicalParent, superClassObject, name);
}

lexicalParentModuleObject.setConstant(this, name, definingClass);
lexicalParent.setConstant(this, name, definingClass);
} else {
if (constant.getValue() instanceof RubyClass) {
definingClass = (RubyClass) constant.getValue();
checkSuperClassCompatibility(context, superClassObject, definingClass);

} else {
throw new RaiseException(context.getCoreLibrary().typeErrorIsNotA(constant.getValue().toString(), "class", this));
}
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@
*/
public class DefineOrGetModuleNode extends RubyNode {

private final String name;
protected final String name;
@Child protected RubyNode lexicalParentModule;

public DefineOrGetModuleNode(RubyContext context, SourceSection sourceSection, String name, RubyNode lexicalParentModule) {
@@ -35,35 +35,58 @@ public DefineOrGetModuleNode(RubyContext context, SourceSection sourceSection, S
public Object execute(VirtualFrame frame) {
notDesignedForCompilation();

final RubyContext context = getContext();

// Look for a current definition of the module, or create a new one

RubyModule lexicalParentModuleObject;
RubyModule lexicalParent = getLexicalParentModule(frame);
final RubyConstant constant = lookupForExistingModule(frame, lexicalParent);

RubyModule definingModule;

if (constant == null) {
definingModule = new RubyModule(getContext().getCoreLibrary().getModuleClass(), lexicalParent, name);
lexicalParent.setConstant(this, name, definingModule);
} else {
Object module = constant.getValue();
if (!(module instanceof RubyModule) || !((RubyModule) module).isOnlyAModule()) {
throw new RaiseException(getContext().getCoreLibrary().typeErrorIsNotA(name, "module", this));
}
definingModule = (RubyModule) module;
}

return definingModule;
}

protected RubyModule getLexicalParentModule(VirtualFrame frame) {
RubyModule lexicalParent;

try {
lexicalParentModuleObject = lexicalParentModule.executeRubyModule(frame);
lexicalParent = lexicalParentModule.executeRubyModule(frame);
} catch (UnexpectedResultException e) {
throw new RaiseException(context.getCoreLibrary().typeErrorIsNotA(e.getResult().toString(), "module", this));
throw new RaiseException(getContext().getCoreLibrary().typeErrorIsNotA(e.getResult().toString(), "module", this));
}

final RubyConstant constant = lexicalParentModuleObject.getConstants().get(name);
return lexicalParent;
}

RubyModule definingModule;
protected RubyConstant lookupForExistingModule(VirtualFrame frame, RubyModule lexicalParent) {
RubyConstant constant = lexicalParent.getConstants().get(name);

if (constant == null) {
definingModule = new RubyModule(context.getCoreLibrary().getModuleClass(), lexicalParentModuleObject, name);
lexicalParentModuleObject.setConstant(this, name, definingModule);
} else {
Object constantValue = constant.getValue();
if (!(constantValue instanceof RubyModule) || !((RubyModule) constantValue).isOnlyAModule()) {
throw new RaiseException(context.getCoreLibrary().typeErrorIsNotA(name, "module", this));
final RubyClass objectClass = getContext().getCoreLibrary().getObjectClass();

if (constant == null && lexicalParent == objectClass) {
for (RubyModule included : objectClass.includedModules()) {
constant = included.getConstants().get(name);
if (constant != null) {
break;
}
}
}

definingModule = (RubyModule) constantValue;
if (constant != null && !constant.isVisibleTo(getContext(), LexicalScope.NONE, lexicalParent)) {
throw new RaiseException(getContext().getCoreLibrary().nameErrorPrivateConstant(lexicalParent, name, this));
}

return definingModule;
return constant;
}

}
Original file line number Diff line number Diff line change
@@ -12,6 +12,8 @@
import org.jruby.truffle.runtime.core.RubyModule;

public class LexicalScope {
public static final LexicalScope NONE = null;

private final LexicalScope parent;
private RubyModule liveModule;

Original file line number Diff line number Diff line change
@@ -63,7 +63,7 @@ public static Map<String, RubyConstant> getAllConstants(RubyModule module) {
* @param module The receiver of the constant lookup.
* Identical to lexicalScope.getLiveModule() if there no qualifier (Constant).
*/
public static RubyConstant lookupConstant(LexicalScope lexicalScope, RubyModule module, String name) {
public static RubyConstant lookupConstant(RubyContext context, LexicalScope lexicalScope, RubyModule module, String name) {
CompilerAsserts.neverPartOfCompilation();

RubyConstant constant;
@@ -76,7 +76,6 @@ public static RubyConstant lookupConstant(LexicalScope lexicalScope, RubyModule
}

// Look in lexical scope
final RubyContext context = module.getContext();
final RubyClass objectClass = context.getCoreLibrary().getObjectClass();

if (lexicalScope != null) {
@@ -105,9 +104,9 @@ public static RubyConstant lookupConstant(LexicalScope lexicalScope, RubyModule
}
}

// Look in Object and its ancestors for modules
// Look in Object and its included modules
if (module.isOnlyAModule()) {
for (RubyModule ancestor : objectClass.ancestors()) {
for (RubyModule ancestor : objectClass.selfAndIncludedModules()) {
constant = ancestor.getConstants().get(name);

if (constant != null) {
42 changes: 41 additions & 1 deletion core/src/main/java/org/jruby/truffle/runtime/RubyConstant.java
Original file line number Diff line number Diff line change
@@ -9,12 +9,17 @@
*/
package org.jruby.truffle.runtime;

import org.jruby.truffle.runtime.core.RubyClass;
import org.jruby.truffle.runtime.core.RubyModule;

public class RubyConstant {

private final RubyModule declaringModule;
private final Object value;
private boolean isPrivate;

public RubyConstant(Object value, boolean isPrivate) {
public RubyConstant(RubyModule declaringModule, Object value, boolean isPrivate) {
this.declaringModule = declaringModule;
this.value = value;
this.isPrivate = isPrivate;
}
@@ -31,4 +36,39 @@ public void setPrivate(boolean isPrivate) {
this.isPrivate = isPrivate;
}

public boolean isVisibleTo(RubyContext context, LexicalScope lexicalScope, RubyModule module) {
if (!isPrivate) {
return true;
}

final LexicalScope topLexicalScope = lexicalScope;

// Look in lexical scope
if (lexicalScope != null) {
while (lexicalScope != context.getRootLexicalScope()) {
if (lexicalScope.getLiveModule() == declaringModule) {
return true;
}
lexicalScope = lexicalScope.getParent();
}
}

// Look in included modules
if (module instanceof RubyClass) {
for (RubyModule included : module.includedModules()) {
if (included == declaringModule) {
return true;
}
}
}

// Look in Object if there is no qualifier (just CONST, neither Mod::CONST nor ::CONST).
if (topLexicalScope != null && topLexicalScope.getLiveModule() == module && // This is a guess, we should have that info from AST
context.getCoreLibrary().getObjectClass() == declaringModule) {
return true;
}

return false;
}

}
66 changes: 36 additions & 30 deletions core/src/main/java/org/jruby/truffle/runtime/core/CoreLibrary.java
Original file line number Diff line number Diff line change
@@ -21,7 +21,6 @@
import org.jruby.runtime.Visibility;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.core.ArrayNodes;
import org.jruby.truffle.runtime.DebugOperations;
import org.jruby.truffle.runtime.ModuleOperations;
import org.jruby.truffle.runtime.RubyCallStack;
import org.jruby.truffle.runtime.RubyContext;
@@ -121,70 +120,72 @@ public void initialize() {
// Create the cyclic classes and modules

classClass = new RubyClass.RubyClassClass(context);
basicObjectClass = new RubyClass(null, context, classClass, null, null, "BasicObject");
objectClass = new RubyClass(null, null, basicObjectClass, "Object");
basicObjectClass = RubyClass.createBootClass(context, classClass, "BasicObject");
objectClass = RubyClass.createBootClass(context, classClass, "Object");
moduleClass = new RubyModule.RubyModuleClass(context);

// Close the cycles

moduleClass.unsafeSetLogicalClass(classClass);
classClass.unsafeSetSuperclass(null, moduleClass);
moduleClass.unsafeSetSuperclass(null, objectClass);
classClass.unsafeSetLogicalClass(classClass);
moduleClass.unsafeSetLogicalClass(classClass);

objectClass.unsafeSetSuperclass(basicObjectClass);
moduleClass.unsafeSetSuperclass(objectClass);
classClass.unsafeSetSuperclass(moduleClass);

// Create all other classes and modules

numericClass = new RubyClass(null, null, objectClass, "Numeric");
integerClass = new RubyClass(null, null, numericClass, "Integer");
numericClass = new RubyClass(null, objectClass, "Numeric");
integerClass = new RubyClass(null, numericClass, "Integer");

exceptionClass = new RubyException.RubyExceptionClass(objectClass, "Exception");
standardErrorClass = new RubyException.RubyExceptionClass(exceptionClass, "StandardError");

ioClass = new RubyClass(null, null, objectClass, "IO");
ioClass = new RubyClass(null, objectClass, "IO");

argumentErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "ArgumentError");
arrayClass = new RubyArray.RubyArrayClass(objectClass);
bignumClass = new RubyClass(null, null, integerClass, "Bignum");
bindingClass = new RubyClass(null, null, objectClass, "Binding");
bignumClass = new RubyClass(null, integerClass, "Bignum");
bindingClass = new RubyClass(null, objectClass, "Binding");
comparableModule = new RubyModule(moduleClass, null, "Comparable");
configModule = new RubyModule(moduleClass, null, "Config");
continuationClass = new RubyClass(null, null, objectClass, "Continuation");
dirClass = new RubyClass(null, null, objectClass, "Dir");
continuationClass = new RubyClass(null, objectClass, "Continuation");
dirClass = new RubyClass(null, objectClass, "Dir");
encodingClass = new RubyEncoding.RubyEncodingClass(objectClass);
errnoModule = new RubyModule(moduleClass, null, "Errno");
enumerableModule = new RubyModule(moduleClass, null, "Enumerable");
falseClass = new RubyClass(null, null, objectClass, "FalseClass");
falseClass = new RubyClass(null, objectClass, "FalseClass");
fiberClass = new RubyFiber.RubyFiberClass(objectClass);
fileClass = new RubyClass(null, null, ioClass, "File");
fixnumClass = new RubyClass(null, null, integerClass, "Fixnum");
floatClass = new RubyClass(null, null, numericClass, "Float");
fileClass = new RubyClass(null, ioClass, "File");
fixnumClass = new RubyClass(null, integerClass, "Fixnum");
floatClass = new RubyClass(null, numericClass, "Float");
gcModule = new RubyModule(moduleClass, null, "GC");
hashClass = new RubyHash.RubyHashClass(objectClass);
kernelModule = new RubyModule(moduleClass, null, "Kernel");
loadErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "LoadError");
localJumpErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "LocalJumpError");
matchDataClass = new RubyClass(null, null, objectClass, "MatchData");
matchDataClass = new RubyClass(null, objectClass, "MatchData");
mathModule = new RubyModule(moduleClass, null, "Math");
nameErrorClass = new RubyClass(null, null, standardErrorClass, "NameError");
nilClass = new RubyClass(null, null, objectClass, "NilClass");
nameErrorClass = new RubyClass(null, standardErrorClass, "NameError");
nilClass = new RubyClass(null, objectClass, "NilClass");
noMethodErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "NoMethodError");
objectSpaceModule = new RubyModule(moduleClass, null, "ObjectSpace");
procClass = new RubyProc.RubyProcClass(objectClass);
processClass = new RubyClass(null, null, objectClass, "Process");
rangeClass = new RubyClass(null, null, objectClass, "Range");
processClass = new RubyClass(null, objectClass, "Process");
rangeClass = new RubyClass(null, objectClass, "Range");
rangeErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "RangeError");
regexpClass = new RubyRegexp.RubyRegexpClass(objectClass);
rubyTruffleErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "RubyTruffleError");
runtimeErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "RuntimeError");
signalModule = new RubyModule(moduleClass, null, "Signal");
stringClass = new RubyString.RubyStringClass(objectClass);
symbolClass = new RubyClass(null, null, objectClass, "Symbol");
symbolClass = new RubyClass(null, objectClass, "Symbol");
syntaxErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "SyntaxError");
systemCallErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "SystemCallError");
systemExitClass = new RubyException.RubyExceptionClass(exceptionClass, "SystemExit");
threadClass = new RubyThread.RubyThreadClass(objectClass);
timeClass = new RubyTime.RubyTimeClass(objectClass);
trueClass = new RubyClass(null, null, objectClass, "TrueClass");
trueClass = new RubyClass(null, objectClass, "TrueClass");
truffleModule = new RubyModule(moduleClass, null, "Truffle");
truffleDebugModule = new RubyModule(moduleClass, null, "Debug");
typeErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "TypeError");
@@ -330,12 +331,12 @@ public void initialize() {
fileClass.setConstant(null, "PATH_SEPARATOR", RubyString.fromJavaString(stringClass, File.pathSeparator));
fileClass.setConstant(null, "FNM_SYSCASE", 0);

errnoModule.setConstant(null, "ENOENT", new RubyClass(null, null, systemCallErrorClass, "ENOENT"));
errnoModule.setConstant(null, "EPERM", new RubyClass(null, null, systemCallErrorClass, "EPERM"));
errnoModule.setConstant(null, "ENOTEMPTY", new RubyClass(null, null, systemCallErrorClass, "ENOTEMPTY"));
errnoModule.setConstant(null, "EEXIST", new RubyClass(null, null, systemCallErrorClass, "EEXIST"));
errnoModule.setConstant(null, "EXDEV", new RubyClass(null, null, systemCallErrorClass, "EXDEV"));
errnoModule.setConstant(null, "EACCES", new RubyClass(null, null, systemCallErrorClass, "EACCES"));
errnoModule.setConstant(null, "ENOENT", new RubyClass(null, systemCallErrorClass, "ENOENT"));
errnoModule.setConstant(null, "EPERM", new RubyClass(null, systemCallErrorClass, "EPERM"));
errnoModule.setConstant(null, "ENOTEMPTY", new RubyClass(null, systemCallErrorClass, "ENOTEMPTY"));
errnoModule.setConstant(null, "EEXIST", new RubyClass(null, systemCallErrorClass, "EEXIST"));
errnoModule.setConstant(null, "EXDEV", new RubyClass(null, systemCallErrorClass, "EXDEV"));
errnoModule.setConstant(null, "EACCES", new RubyClass(null, systemCallErrorClass, "EACCES"));

globalVariablesObject.setInstanceVariable("$DEBUG", context.getRuntime().isDebug());
globalVariablesObject.setInstanceVariable("$VERBOSE", context.getRuntime().warningsEnabled() ? context.getRuntime().isVerbose() : nilObject);
@@ -527,6 +528,11 @@ public RubyException nameErrorUninitializedConstant(String name, Node currentNod
return nameError(String.format("uninitialized constant %s", name), currentNode);
}

public RubyException nameErrorPrivateConstant(RubyModule module, String name, Node currentNode) {
CompilerAsserts.neverPartOfCompilation();
return nameError(String.format("private constant %s::%s referenced", module.getName(), name), currentNode);
}

public RubyException nameErrorNoMethod(String name, String object, Node currentNode) {
CompilerAsserts.neverPartOfCompilation();
return nameError(String.format("undefined method `%s' for %s", name, object), currentNode);
Original file line number Diff line number Diff line change
@@ -15,8 +15,6 @@
import org.jruby.truffle.nodes.core.ArrayAllocationSite;
import org.jruby.truffle.runtime.subsystems.ObjectSpaceManager;
import org.jruby.truffle.runtime.util.ArrayUtils;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.util.cli.Options;

import java.util.Arrays;
@@ -31,7 +29,7 @@ public final class RubyArray extends RubyObject {
public static class RubyArrayClass extends RubyClass {

public RubyArrayClass(RubyClass objectClass) {
super(null, null, objectClass, "Array");
super(null, objectClass, "Array");
}

@Override
Original file line number Diff line number Diff line change
@@ -69,8 +69,8 @@ public RubyClass getSingletonClass(Node currentNode) {

final RubyClass logicalClass = metaClass;

metaClass = new RubyClass(currentNode, null, logicalClass,
String.format("#<Class:#<%s:0x%x>>", logicalClass.getName(), getObjectID()), true);
metaClass = RubyClass.createSingletonClassOfObject(getContext(), logicalClass,
String.format("#<Class:#<%s:0x%x>>", logicalClass.getName(), getObjectID()));

return metaClass;
}
@@ -161,10 +161,6 @@ public boolean hasPrivateLayout() {
return hasPrivateLayout;
}

public boolean isTrue() {
return true;
}

public void visitObjectGraph(ObjectSpaceManager.ObjectGraphVisitor visitor) {
if (visitor.visit(this)) {
metaClass.visitObjectGraph(visitor);
Original file line number Diff line number Diff line change
@@ -66,4 +66,8 @@ public boolean equals(Object obj) {
return true;
}

@Override
public boolean hasNoSingleton() {
return true;
}
}
57 changes: 36 additions & 21 deletions core/src/main/java/org/jruby/truffle/runtime/core/RubyClass.java
Original file line number Diff line number Diff line change
@@ -36,41 +36,44 @@ public class RubyClass extends RubyModule {
public static class RubyClassClass extends RubyClass {

public RubyClassClass(RubyContext context) {
super(null, context, null, null, null, "Class");
super(context, null, null, null, "Class", false);
}

@Override
public RubyBasicObject newInstance(RubyNode currentNode) {
return new RubyClass(null, null, getContext().getCoreLibrary().getObjectClass(), "(unnamed class)");
return new RubyClass(null, getContext().getCoreLibrary().getObjectClass(), "(unnamed class)");
}

}

public RubyClass(Node currentNode, RubyModule lexicalParent, RubyClass superclass, String name) {
this(currentNode, lexicalParent, superclass, name, false);
/**
* This constructor supports initialization and solves boot-order problems and should not
* normally be used from outside this class.
*/
public static RubyClass createBootClass(RubyContext context, RubyClass classClass,String name) {
return new RubyClass(context, classClass, null, null, name, false);
}

public RubyClass(Node currentNode, RubyModule lexicalParent, RubyClass superclass, String name, boolean isSingleton) {
this(currentNode, superclass.getContext(), superclass.getContext().getCoreLibrary().getClassClass(), lexicalParent, superclass, name);
this.isSingleton = isSingleton;
public RubyClass(RubyModule lexicalParent, RubyClass superclass, String name) {
this(superclass.getContext(), superclass.getContext().getCoreLibrary().getClassClass(), lexicalParent, superclass, name, false);
// Always create a class singleton class for normal classes for consistency.
ensureSingletonConsistency();
}

// TODO(CS): Why am I doing this? Why does it break if I don't?
if (!isSingleton) {
getSingletonClass(currentNode);
}
protected static RubyClass createSingletonClassOfObject(RubyContext context, RubyClass superclass, String name) {
// We also need to create the singleton class of a singleton class for proper lookup and consistency.
// See rb_singleton_class() documentation in MRI.
return new RubyClass(context, context.getCoreLibrary().getClassClass(), null, superclass, name, true).ensureSingletonConsistency();
}

/**
* This constructor supports initialization and solves boot-order problems and should not
* normally be used from outside this class.
*/
public RubyClass(Node currentNode, RubyContext context, RubyClass classClass, RubyModule lexicalParent, RubyClass superclass, String name) {
protected RubyClass(RubyContext context, RubyClass classClass, RubyModule lexicalParent, RubyClass superclass, String name, boolean isSingleton) {
super(context, classClass, lexicalParent, name);
this.isSingleton = isSingleton;

if (superclass == null) {
objectLayoutForInstances = ObjectLayout.EMPTY;
} else {
unsafeSetSuperclass(currentNode, superclass);
unsafeSetSuperclass(superclass);
}
}

@@ -82,11 +85,22 @@ public void initCopy(RubyModule other) {
this.objectLayoutForInstances = otherClass.objectLayoutForInstances;
}

private RubyClass ensureSingletonConsistency() {
createOneSingletonClass();
return this;
}

@Override
public RubyClass getSingletonClass(Node currentNode) {
// We also need to create the singleton class of a singleton class for proper lookup and consistency.
// See rb_singleton_class() documentation in MRI.
return createOneSingletonClass().ensureSingletonConsistency();
}

private RubyClass createOneSingletonClass() {
CompilerAsserts.neverPartOfCompilation();

if (hasClassAsSingleton() || metaClass.isSingleton()) {
if (metaClass.isSingleton()) {
return metaClass;
}

@@ -95,10 +109,11 @@ public RubyClass getSingletonClass(Node currentNode) {
if (getSuperClass() == null) {
singletonSuperclass = getLogicalClass();
} else {
singletonSuperclass = getSuperClass().getSingletonClass(currentNode);
singletonSuperclass = getSuperClass().createOneSingletonClass();
}

metaClass = new RubyClass(currentNode, null, singletonSuperclass, String.format("#<Class:%s>", getName()), true);
metaClass = new RubyClass(getContext(), getContext().getCoreLibrary().getClassClass(),
null, singletonSuperclass, String.format("#<Class:%s>", getName()), true);

return metaClass;
}
@@ -107,7 +122,7 @@ public RubyClass getSingletonClass(Node currentNode) {
* This method supports initialization and solves boot-order problems and should not normally be
* used.
*/
public void unsafeSetSuperclass(Node currentNode, RubyClass newSuperclass) {
public void unsafeSetSuperclass(RubyClass newSuperclass) {
RubyNode.notDesignedForCompilation();

assert parentModule == null;
Original file line number Diff line number Diff line change
@@ -10,13 +10,11 @@
package org.jruby.truffle.runtime.core;

import org.jcodings.Encoding;
import org.jcodings.specific.USASCIIEncoding;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
* This is a bridge between JRuby encoding and Truffle encoding
@@ -35,7 +33,7 @@ public class RubyEncoding extends RubyObject {
public static class RubyEncodingClass extends RubyClass {

public RubyEncodingClass(RubyClass objectClass) {
super(null, null, objectClass, "Encoding");
super(null, objectClass, "Encoding");
}

@Override
Original file line number Diff line number Diff line change
@@ -9,8 +9,6 @@
*/
package org.jruby.truffle.runtime.core;

import java.util.*;

import org.jcodings.transcode.EConv;
import org.jruby.truffle.nodes.RubyNode;

@@ -23,7 +21,7 @@ public EConv getEConv() {
public static class RubyEncodingConverterClass extends RubyClass {

public RubyEncodingConverterClass(RubyClass objectClass) {
super(null, null, objectClass, "Converter");
super(null, objectClass, "Converter");
}

@Override
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ public class RubyException extends RubyObject {
public static class RubyExceptionClass extends RubyClass {

public RubyExceptionClass(RubyClass superClass, String name) {
super(null, null, superClass, name);
super(null, superClass, name);
}

@Override
Original file line number Diff line number Diff line change
@@ -36,11 +36,6 @@ public int hashCode() {
return Boolean.FALSE.hashCode();
}

@Override
public boolean isTrue() {
return false;
}

@Override
public boolean hasClassAsSingleton() {
return true;
Original file line number Diff line number Diff line change
@@ -13,7 +13,6 @@

import com.oracle.truffle.api.nodes.*;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.subsystems.*;

/**
@@ -28,7 +27,7 @@ public class RubyFiber extends RubyObject {
public static class RubyFiberClass extends RubyClass {

public RubyFiberClass(RubyClass objectClass) {
super(null, null, objectClass, "Fiber");
super(null, objectClass, "Fiber");
}

@Override
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ public class RubyHash extends RubyObject {
public static class RubyHashClass extends RubyClass {

public RubyHashClass(RubyClass objectClass) {
super(null, null, objectClass, "Hash");
super(null, objectClass, "Hash");
}

@Override
53 changes: 45 additions & 8 deletions core/src/main/java/org/jruby/truffle/runtime/core/RubyModule.java
Original file line number Diff line number Diff line change
@@ -116,7 +116,7 @@ public static void debugModuleChain(RubyModule module) {
public static class RubyModuleClass extends RubyClass {

public RubyModuleClass(RubyContext context) {
super(null, context, null, null, null, "Module");
super(context, null, null, null, "Module", false);
}

@Override
@@ -192,13 +192,20 @@ public void include(Node currentNode, RubyModule module) {
/**
* Set the value of a constant, possibly redefining it.
*/
public void setConstant(RubyNode currentNode, String constantName, Object value) {
public void setConstant(RubyNode currentNode, String name, Object value) {
RubyNode.notDesignedForCompilation();

checkFrozen(currentNode);
getConstants().put(constantName, new RubyConstant(value, false));

RubyConstant previous = getConstants().get(name);
if (previous == null) {
getConstants().put(name, new RubyConstant(this, value, false));
} else {
// TODO(CS): warn when redefining a constant
getConstants().put(name, new RubyConstant(this, value, previous.isPrivate()));
}

newLexicalVersion();
// TODO(CS): warn when redefining a constant
}

public void removeConstant(RubyNode currentNode, String data) {
@@ -251,7 +258,7 @@ public void undefMethod(RubyNode currentNode, String methodName) {
if (method == null) {
throw new UnsupportedOperationException();
} else {
undefMethod(currentNode, ModuleOperations.lookupMethod(this, methodName));
undefMethod(currentNode, method);
}
}

@@ -291,16 +298,15 @@ public void alias(RubyNode currentNode, String newName, String oldName) {
public void changeConstantVisibility(RubyNode currentNode, RubySymbol constant, boolean isPrivate) {
RubyNode.notDesignedForCompilation();

RubyConstant rubyConstant = ModuleOperations.lookupConstant(null, this, constant.toString());
RubyConstant rubyConstant = ModuleOperations.lookupConstant(getContext(), null, this, constant.toString());
checkFrozen(currentNode);

if (rubyConstant != null) {
rubyConstant.setPrivate(isPrivate);
newLexicalVersion();
} else {
throw new RaiseException(context.getCoreLibrary().nameErrorUninitializedConstant(constant.toString(), currentNode));
}

newLexicalVersion();
}

public void appendFeatures(RubyNode currentNode, RubyModule other) {
@@ -488,6 +494,17 @@ public void remove() {
}
}

private class IncludedModulesIterator extends AncestorIterator {
public IncludedModulesIterator(ModuleChain top) {
super(top);
}

@Override
public boolean hasNext() {
return module instanceof RubyModule;
}
}

public Iterable<RubyModule> ancestors() {
final RubyModule top = this;
return new Iterable<RubyModule>() {
@@ -508,4 +525,24 @@ public Iterator<RubyModule> iterator() {
};
}

public Iterable<RubyModule> selfAndIncludedModules() {
final ModuleChain top = this;
return new Iterable<RubyModule>() {
@Override
public Iterator<RubyModule> iterator() {
return new AncestorIterator(top);
}
};
}

public Iterable<RubyModule> includedModules() {
final ModuleChain top = parentModule;
return new Iterable<RubyModule>() {
@Override
public Iterator<RubyModule> iterator() {
return new AncestorIterator(top);
}
};
}

}
Original file line number Diff line number Diff line change
@@ -26,11 +26,6 @@ public int hashCode() {
return 0;
}

@Override
public boolean isTrue() {
return false;
}

@Override
public boolean hasClassAsSingleton() {
return true;
Original file line number Diff line number Diff line change
@@ -13,7 +13,6 @@
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.frame.MaterializedFrame;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.DebugOperations;
import org.jruby.truffle.runtime.RubyArguments;
import org.jruby.truffle.runtime.methods.*;
import org.jruby.truffle.runtime.subsystems.ObjectSpaceManager;
@@ -34,7 +33,7 @@ public class RubyProc extends RubyObject implements MethodLike {
public static class RubyProcClass extends RubyClass {

public RubyProcClass(RubyClass objectClass) {
super(null, null, objectClass, "Proc");
super(null, objectClass, "Proc");
}

@Override
Original file line number Diff line number Diff line change
@@ -20,7 +20,6 @@
import org.joni.*;
import org.joni.exception.ValueException;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.RubyContext;

import java.nio.ByteBuffer;
@@ -40,7 +39,7 @@ public class RubyRegexp extends RubyObject {
public static class RubyRegexpClass extends RubyClass {

public RubyRegexpClass(RubyClass objectClass) {
super(null, null, objectClass, "Regexp");
super(null, objectClass, "Regexp");
}

@Override
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ public class RubyString extends RubyObject {
public static class RubyStringClass extends RubyClass {

public RubyStringClass(RubyClass objectClass) {
super(null, null, objectClass, "String");
super(null, objectClass, "String");
}

@Override
Original file line number Diff line number Diff line change
@@ -45,7 +45,7 @@ public void shutdown() {
public static class RubyThreadClass extends RubyClass {

public RubyThreadClass(RubyClass objectClass) {
super(null, null, objectClass, "Thread");
super(null, objectClass, "Thread");
}

@Override
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@ public class RubyTime extends RubyObject {
public static class RubyTimeClass extends RubyClass {

public RubyTimeClass(RubyClass objectClass) {
super(null, null, objectClass, "Time");
super(null, objectClass, "Time");
}

@Override
Original file line number Diff line number Diff line change
@@ -48,18 +48,18 @@ public class RubiniusLibrary {

public RubiniusLibrary(CoreLibrary coreLib) {
rubiniusModule = new RubyModule(coreLib.getModuleClass(), null, "Rubinius");
tupleClass = new RubyClass(null, rubiniusModule, coreLib.getObjectClass(), "Tuple");
tupleClass = new RubyClass(rubiniusModule, coreLib.getObjectClass(), "Tuple");
typeModule = new RubyModule(coreLib.getModuleClass(), rubiniusModule, "Type");
environmentAccessModule = new RubyModule(coreLib.getModuleClass(), rubiniusModule, "EnvironmentAccess");
channelClass = new RubyClass(null, rubiniusModule, coreLib.getObjectClass(), "Channel");
byteArrayCLass = new RubyClass(null, rubiniusModule, coreLib.getObjectClass(), "ByteArray");
channelClass = new RubyClass(rubiniusModule, coreLib.getObjectClass(), "Channel");
byteArrayCLass = new RubyClass(rubiniusModule, coreLib.getObjectClass(), "ByteArray");

//TODO: how is Rubinius.LookupTable specified?
// rubinius.setConstant("LookupTable", currentNode.getHash());

vmExceptionClass = new RubyClass(null, rubiniusModule, coreLib.getExceptionClass(), "VMException");
objectBoundsExceededErrorClass = new RubyClass(null, rubiniusModule, vmExceptionClass, "ObjectBoundsExceededError");
assertionErrorClass = new RubyClass(null, rubiniusModule, vmExceptionClass, "AssertionError");
vmExceptionClass = new RubyClass(rubiniusModule, coreLib.getExceptionClass(), "VMException");
objectBoundsExceededErrorClass = new RubyClass(rubiniusModule, vmExceptionClass, "ObjectBoundsExceededError");
assertionErrorClass = new RubyClass(rubiniusModule, vmExceptionClass, "AssertionError");

coreLib.getObjectClass().setConstant(null, rubiniusModule.getName(), rubiniusModule);

Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ public FeatureManager(RubyContext context) {
}

public boolean require(String feature, RubyNode currentNode) throws IOException {
final RubyConstant dataConstantBefore = ModuleOperations.lookupConstant(null, context.getCoreLibrary().getObjectClass(), "DATA");
final RubyConstant dataConstantBefore = ModuleOperations.lookupConstant(context, null, context.getCoreLibrary().getObjectClass(), "DATA");

try {
// Some features are handled specially
28 changes: 18 additions & 10 deletions core/src/main/java/org/jruby/truffle/translator/BodyTranslator.java
Original file line number Diff line number Diff line change
@@ -625,24 +625,25 @@ public RubyNode visitClassVarNode(org.jruby.ast.ClassVarNode node) {

@Override
public RubyNode visitColon2Node(org.jruby.ast.Colon2Node node) {
// Qualified constant access, as in Mod::CONST
if (!(node instanceof Colon2ConstNode)) {
throw new UnsupportedOperationException(node.toString());
}

final RubyNode lhs = node.getLeftNode().accept(this);

return new ReadConstantNode(context, translate(node.getPosition()), node.getName(), lhs);
return new ReadConstantNode(context, translate(node.getPosition()), node.getName(), lhs, environment.getLexicalScope());
}

@Override
public RubyNode visitColon3Node(org.jruby.ast.Colon3Node node) {
// Colon3 means the root namespace, as in ::Foo
// Root namespace constant access, as in ::Foo

final SourceSection sourceSection = translate(node.getPosition());

final ObjectLiteralNode root = new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getObjectClass());

return new ReadConstantNode(context, sourceSection, node.getName(), root);
return new ReadConstantNode(context, sourceSection, node.getName(), root, LexicalScope.NONE);
}

private RubyNode translateCPath(SourceSection sourceSection, org.jruby.ast.Colon3Node node) {
@@ -677,11 +678,12 @@ public RubyNode visitConstDeclNode(org.jruby.ast.ConstDeclNode node) {

@Override
public RubyNode visitConstNode(org.jruby.ast.ConstNode node) {
// Unqualified constant access, as in CONST
final SourceSection sourceSection = translate(node.getPosition());

RubyNode moduleNode = new LexicalScopeNode(context, sourceSection, environment.getLexicalScope());

return new ReadConstantNode(context, sourceSection, node.getName(), moduleNode);
return new ReadConstantNode(context, sourceSection, node.getName(), moduleNode, environment.getLexicalScope());
}

@Override
@@ -1721,15 +1723,21 @@ public RubyNode visitOpAsgnNode(org.jruby.ast.OpAsgnNode node) {
@Override
public RubyNode visitOpAsgnOrNode(org.jruby.ast.OpAsgnOrNode node) {
/*
* De-sugar x ||= y into x || x = y. No repeated evaluations there so it's easy. It's also
* basically how jruby-parser represents it already. We'll do it directly, rather than via
* another JRuby AST node.
* De-sugar x ||= y into ([defined?(x) &&] x) || x = y.
* The defined? check is only needed for some expressions.
* It's also basically how jruby-parser represents it already.
* We'll do it directly, rather than via another JRuby AST node.
*/

final org.jruby.ast.Node lhs = node.getFirstNode();
final org.jruby.ast.Node rhs = node.getSecondNode();
RubyNode lhs = node.getFirstNode().accept(this);
RubyNode rhs = node.getSecondNode().accept(this);

if (node.getFirstNode().needsDefinitionCheck()) {
RubyNode defined = new DefinedNode(context, lhs.getSourceSection(), lhs);
lhs = new AndNode(context, lhs.getSourceSection(), defined, lhs);
}

return new OrNode(context, translate(node.getPosition()), lhs.accept(this), rhs.accept(this));
return new OrNode(context, translate(node.getPosition()), lhs, rhs);
}

@Override
Original file line number Diff line number Diff line change
@@ -43,7 +43,8 @@ public TranslatorDriver(RubyContext context) {
public MethodDefinitionNode parse(RubyContext context, org.jruby.ast.Node parseTree, org.jruby.ast.ArgsNode argsNode, org.jruby.ast.Node bodyNode, RubyNode currentNode) {
final SourceSection sourceSection = null;

final SharedMethodInfo sharedMethod = new SharedMethodInfo(sourceSection, null, "(unknown)", false, parseTree);
final LexicalScope lexicalScope = context.getRootLexicalScope(); // TODO(eregon): figure out how to get the lexical scope from JRuby
final SharedMethodInfo sharedMethod = new SharedMethodInfo(sourceSection, lexicalScope, "(unknown)", false, parseTree);

final TranslatorEnvironment environment = new TranslatorEnvironment(
context, environmentForFrame(context, null), this, allocateReturnID(), true, true, sharedMethod, sharedMethod.getName(), false);
@@ -116,7 +117,7 @@ public RubyRootNode parse(RubyContext context, Source source, ParserContext pars

public RubyRootNode parse(RubyNode currentNode, RubyContext context, Source source, ParserContext parserContext, MaterializedFrame parentFrame, org.jruby.ast.RootNode rootNode) {
final SourceSection sourceSection = source.createSection("<main>", 0, source.getCode().length());
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, null, "<main>", false, rootNode);
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, context.getRootLexicalScope(), "<main>", false, rootNode);

final TranslatorEnvironment environment = new TranslatorEnvironment(context, environmentForFrame(context, parentFrame), this, allocateReturnID(), true, true, sharedMethodInfo, sharedMethodInfo.getName(), false);

@@ -210,7 +211,8 @@ private TranslatorEnvironment environmentForFrame(RubyContext context, Materiali
if (frame == null) {
return null;
} else {
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(new NullSourceSection("Unknown source section", "(unknown)"), null, "(unknown)", false, null);
SourceSection sourceSection = new NullSourceSection("Unknown source section", "(unknown)");
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, context.getRootLexicalScope(), "(unknown)", false, null);
final MaterializedFrame parent = RubyArguments.getDeclarationFrame(frame.getArguments());
// TODO(CS): how do we know if the frame is a block or not?
return new TranslatorEnvironment(context, environmentForFrame(context, parent), frame.getFrameDescriptor(), this, allocateReturnID(), true, true, sharedMethodInfo, sharedMethodInfo.getName(), false);
16 changes: 9 additions & 7 deletions core/src/main/java/org/jruby/util/JRubyClassLoader.java
Original file line number Diff line number Diff line change
@@ -136,15 +136,17 @@ public void addURL(URL url) {

@Override
public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
c = findClass(name);
} catch (ClassNotFoundException e) {
return super.loadClass(name, resolve);
synchronized (getClassLoadingLock(name)) {
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
c = findClass(name);
} catch (ClassNotFoundException e) {
return super.loadClass(name, resolve);
}
}
return c;
}
return c;
}

/**
2 changes: 1 addition & 1 deletion maven/pom.rb
Original file line number Diff line number Diff line change
@@ -26,7 +26,7 @@
map = { 'jruby' => [ :release, :main, :osgi, :j2ee ],
'jruby-noasm' => [ :release, :main ],
'jruby-stdlib' => [ :release, :main, :complete, :dist, 'jruby-jars', :osgi, :j2ee ],
'jruby-complete' => [ :release, :complete, :osgi ],
'jruby-complete' => [ :release, :complete, :osgi, :'jruby_complete_jar_jruby'],
'jruby-jars' => [ :release, 'jruby-jars' ],
'jruby-dist' => [ :release, :dist ]
}
6 changes: 6 additions & 0 deletions maven/pom.xml
Original file line number Diff line number Diff line change
@@ -112,5 +112,11 @@
<module>jruby-jars</module>
</modules>
</profile>
<profile>
<id>jruby_complete_jar_jruby</id>
<modules>
<module>jruby-complete</module>
</modules>
</profile>
</profiles>
</project>
10 changes: 6 additions & 4 deletions pom.rb
Original file line number Diff line number Diff line change
@@ -230,12 +230,14 @@

all_modules = [ 'test', 'maven' ]

profile 'all' do
[ 'all', 'jruby_complete_jar_jruby' ].each do |name|
profile name do

modules all_modules
modules all_modules

build do
default_goal 'install'
build do
default_goal 'install'
end
end
end

10 changes: 10 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -682,6 +682,16 @@
<module>maven</module>
</modules>
</profile>
<profile>
<id>jruby_complete_jar_jruby</id>
<build>
<defaultGoal>install</defaultGoal>
</build>
<modules>
<module>test</module>
<module>maven</module>
</modules>
</profile>
<profile>
<id>clean</id>
<build>
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/module/instance_methods_tags.txt

This file was deleted.

12 changes: 0 additions & 12 deletions spec/truffle/tags/language/constants_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/language/module_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
fails:Assigning an anonymous module to a constant sets the name of the module
fails:Assigning an anonymous module to a constant does not set the name of a module scoped by an anonymous module
fails:Assigning an anonymous module to a constant sets the name of contained modules when assigning a toplevel anonymous module
fails:The module keyword reopens a module included in Object
9 changes: 0 additions & 9 deletions spec/truffle/tags/language/singleton_class_tags.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1 @@
fails:A singleton class is a subclass of Class's singleton class
fails(inherited):A singleton class is a subclass of the same level of Class's singleton class
fails(inherited):A singleton class doesn't have singleton class
fails:Defining instance methods on a singleton class define public methods
fails:Class methods of a singleton class include ones of the object's class
fails:Class methods of a singleton class for a singleton class include instance methods of the singleton class of Class
fails(inherited):Class methods of a singleton class for a singleton class include class methods of the singleton class of Class
fails:Instantiating a singleton class raises a TypeError when new is called
fails:Instantiating a singleton class raises a TypeError when allocate is called
fails:A constant on a singleton class is preserved when the object is cloned
23 changes: 23 additions & 0 deletions test/pom.rb
Original file line number Diff line number Diff line change
@@ -137,6 +137,29 @@

end

profile 'jruby_complete_jar_jruby' do

jar 'org.jruby:jruby-complete', '${project.version}', :scope => :provided

rake = Dir[File.join(basedir, "../lib/ruby/gems/shared/gems/rake-*/lib/rake/rake_test_loader.rb")].first
files = ""
File.open(File.join(basedir, 'jruby.index')) do |f|
f.each_line.each do |line|
filename = "test/#{line.chomp}.rb"
next unless File.exist? filename
files << "<arg value='#{filename}'/>"
end
end

plugin :antrun do
execute_goals( 'run',
:id => 'jruby_complete_jar_jruby',
:phase => 'test',
:configuration => [ xml( "<target><exec dir='${jruby.home}' executable='java' failonerror='true'><arg value='-cp'/><arg value='core/target/test-classes:test/target/test-classes:maven/jruby-complete/target/jruby-complete-${project.version}.jar'/><arg value='org.jruby.Main'/><arg value='-I.'/><arg value='#{rake}'/>#{files}<arg value='-v'/></exec></target>" ) ] )
end

end

profile 'truffle-specs-language' do

plugin :antrun do
132 changes: 132 additions & 0 deletions test/pom.xml
Original file line number Diff line number Diff line change
@@ -253,6 +253,138 @@
</plugins>
</build>
</profile>
<profile>
<id>jruby_complete_jar_jruby</id>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>jruby_complete_jar_jruby</id>
<phase>test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<exec dir="${jruby.home}" executable="java" failonerror="true">
<arg value="-cp" />
<arg value="core/target/test-classes:test/target/test-classes:maven/jruby-complete/target/jruby-complete-${project.version}.jar" />
<arg value="org.jruby.Main" />
<arg value="-I." />
<arg value="/home/christian/projects/active/maven/jruby/test/../lib/ruby/gems/shared/gems/rake-10.1.0/lib/rake/rake_test_loader.rb" />
<arg value="test/jruby/test_globals.rb" />
<arg value="test/jruby/test_argf.rb" />
<arg value="test/jruby/test_array.rb" />
<arg value="test/jruby/test_autoload.rb" />
<arg value="test/jruby/test_backquote.rb" />
<arg value="test/jruby/test_backtraces.rb" />
<arg value="test/jruby/test_big_decimal.rb" />
<arg value="test/jruby/test_binding_eval_yield.rb" />
<arg value="test/jruby/test_caller.rb" />
<arg value="test/jruby/test_case.rb" />
<arg value="test/jruby/test_class.rb" />
<arg value="test/jruby/test_comparable.rb" />
<arg value="test/jruby/test_core_arities.rb" />
<arg value="test/jruby/test_custom_enumerable.rb" />
<arg value="test/jruby/test_cvars_in_odd_scopes.rb" />
<arg value="test/jruby/test_date_joda_time.rb" />
<arg value="test/jruby/test_defined.rb" />
<arg value="test/jruby/test_default_constants.rb" />
<arg value="test/jruby/test_delegated_array_equals.rb" />
<arg value="test/jruby/test_dir.rb" />
<arg value="test/jruby/test_dir_with_jar_without_dir_entry.rb" />
<arg value="test/jruby/test_digest_extend.rb" />
<arg value="test/jruby/test_digest2.rb" />
<arg value="test/jruby/test_env.rb" />
<arg value="test/jruby/test_etc.rb" />
<arg value="test/jruby/test_file.rb" />
<arg value="test/jruby/test_flip.rb" />
<arg value="test/jruby/test_frame_self.rb" />
<arg value="test/jruby/test_hash.rb" />
<arg value="test/jruby/test_higher_javasupport.rb" />
<arg value="test/jruby/test_included_in_object_space.rb" />
<arg value="test/jruby/test_integer_overflows.rb" />
<arg value="test/jruby/test_ivar_table_integrity.rb" />
<arg value="test/jruby/test_io.rb" />
<arg value="test/jruby/test_load.rb" />
<arg value="test/jruby/test_method.rb" />
<arg value="test/jruby/test_method_cache.rb" />
<arg value="test/jruby/test_method_override_and_caching.rb" />
<arg value="test/jruby/test_java_accessible_object.rb" />
<arg value="test/jruby/test_java_extension.rb" />
<arg value="test/jruby/test_java_wrapper_deadlock.rb" />
<arg value="test/jruby/test_jruby_internals.rb" />
<arg value="test/jruby/test_marshal_with_instance_variables.rb" />
<arg value="test/jruby/test_marshal_gemspec.rb" />
<arg value="test/jruby/test_method_missing.rb" />
<arg value="test/jruby/test_no_stack_trace_stomp.rb" />
<arg value="test/jruby/test_pack.rb" />
<arg value="test/jruby/test_primitive_to_java.rb" />
<arg value="test/jruby/test_process.rb" />
<arg value="test/jruby/test_proc_visibility.rb" />
<arg value="test/jruby/test_parsing.rb" />
<arg value="test/jruby/test_pathname_dup.rb" />
<arg value="test/jruby/test_random.rb" />
<arg value="test/jruby/test_rbconfig.rb" />
<arg value="test/jruby/test_require_once.rb" />
<arg value="test/jruby/test_respond_to.rb" />
<arg value="test/jruby/test_socket.rb" />
<arg value="test/jruby/test_string_java_bytes.rb" />
<arg value="test/jruby/test_string_printf.rb" />
<arg value="test/jruby/test_string_to_number.rb" />
<arg value="test/jruby/test_super_call_site_caching.rb" />
<arg value="test/jruby/test_system.rb" />
<arg value="test/jruby/test_system_error.rb" />
<arg value="test/jruby/test_timeout.rb" />
<arg value="test/jruby/test_thread.rb" />
<arg value="test/jruby/test_threaded_nonlocal_return.rb" />
<arg value="test/jruby/test_time_add.rb" />
<arg value="test/jruby/test_time_nil_ops.rb" />
<arg value="test/jruby/test_time_tz.rb" />
<arg value="test/jruby/test_unmarshal.rb" />
<arg value="test/jruby/test_vietnamese_charset.rb" />
<arg value="test/jruby/test_win32.rb" />
<arg value="test/jruby/test_zlib.rb" />
<arg value="test/jruby/test_loading_builtin_libraries.rb" />
<arg value="test/jruby/test_null_channel.rb" />
<arg value="test/jruby/test_irubyobject_java_passing.rb" />
<arg value="test/jruby/test_jruby_object_input_stream.rb" />
<arg value="test/jruby/test_jar_on_load_path.rb" />
<arg value="test/jruby/test_jruby_ext.rb" />
<arg value="test/jruby/test_jruby_core_ext.rb" />
<arg value="test/jruby/test_thread_context_frame_dereferences_unreachable_variables.rb" />
<arg value="test/jruby/test_context_classloader.rb" />
<arg value="test/jruby/test_rexml_document.rb" />
<arg value="test/jruby/test_openssl_stub.rb" />
<arg value="test/jruby/test_missing_jruby_home.rb" />
<arg value="test/jruby/test_jarred_gems_with_spaces_in_directory.rb" />
<arg value="test/jruby/test_kernel.rb" />
<arg value="test/jruby/test_dir_with_plusses.rb" />
<arg value="test/jruby/test_jar_file.rb" />
<arg value="test/jruby/test_jruby_synchronized.rb" />
<arg value="test/jruby/test_instantiating_interfaces.rb" />
<arg value="test/jruby/test_openssl.rb" />
<arg value="test/jruby/test_tempfile_cleanup.rb" />
<arg value="-v" />
</exec>
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby-complete</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
<profile>
<id>truffle-specs-language</id>
<build>
4 changes: 2 additions & 2 deletions tool/build-graal-bundles.sh
Original file line number Diff line number Diff line change
@@ -56,5 +56,5 @@ function pack {
shasum -a 1 $targetname > $targetname.sha1
}

pack "linux" "b132" "0.4"
pack "macosx" "b132" "0.4"
pack "linux" "b132" "0.5"
pack "macosx" "b132" "0.5"

0 comments on commit 640a388

Please sign in to comment.