Skip to content

Commit

Permalink
Showing 47 changed files with 1,082 additions and 391 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'
@@ -50,6 +51,7 @@ matrix:
fast_finish: true
allow_failures:
- env: TARGET='-Pcomplete'
- env: TARGET='-Pjruby_complete_jar_jruby'
- env: TARGET='-Prake -Dtask=spec:compiler'
- env: TARGET='-Pj2ee'
- env: TARGET='-Prake -Dtask=spec:profiler'
17 changes: 8 additions & 9 deletions core/src/main/java/org/jruby/IncludedModule.java
Original file line number Diff line number Diff line change
@@ -34,11 +34,6 @@ public void setMetaClass(RubyClass newRubyClass) {
throw new UnsupportedOperationException("An included class is only a wrapper for a module");
}

@Override
public void addMethod(String name, DynamicMethod method) {
throw new UnsupportedOperationException("An included class is only a wrapper for a module");
}

public void setMethods(Map newMethods) {
throw new UnsupportedOperationException("An included class is only a wrapper for a module");
}
@@ -48,12 +43,16 @@ public String getName() {
return origin.getName();
}

// XXX ??? maybe not getNonIncludedClass()
@Override
protected boolean isSame(RubyModule module) {
return origin.isSame(module.getNonIncludedClass());
public RubyModule getNonIncludedClass() {
return origin;
}


// @Override
// public RubyModule getNonPrependedClass() {
// return origin;
// }

/**
* We don't want to reveal ourselves to Ruby code, so origin this
* operation.
161 changes: 152 additions & 9 deletions core/src/main/java/org/jruby/IncludedModuleWrapper.java
Original file line number Diff line number Diff line change
@@ -33,10 +33,13 @@
package org.jruby;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.jruby.internal.runtime.methods.DynamicMethod;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.builtin.Variable;

@@ -56,6 +59,7 @@ public class IncludedModuleWrapper extends IncludedModule {
public IncludedModuleWrapper(Ruby runtime, RubyClass superClass, RubyModule origin) {
super(runtime, superClass, origin);
origin.addIncludingHierarchy(this);
if (origin.methodLocation != origin) this.methodLocation = origin.methodLocation;
}

/**
@@ -66,7 +70,7 @@ public IncludedModuleWrapper(Ruby runtime, RubyClass superClass, RubyModule orig
*/
@Override
@Deprecated
public IncludedModule newIncludeClass(RubyClass superClass) {
public IncludedModuleWrapper newIncludeClass(RubyClass superClass) {
IncludedModuleWrapper includedModule = new IncludedModuleWrapper(getRuntime(), superClass, getNonIncludedClass());

// include its parent (and in turn that module's parents)
@@ -77,29 +81,135 @@ public IncludedModule newIncludeClass(RubyClass superClass) {
return includedModule;
}

@Override
public void addMethod(String name, DynamicMethod method) {
throw new UnsupportedOperationException("An included class is only a wrapper for a module");
}

public void setMethods(Map newMethods) {
throw new UnsupportedOperationException("An included class is only a wrapper for a module");
}

public RubyModule getDelegate() {
return origin;
}

// @Override
// protected DynamicMethod searchMethodCommon(String name) {
// DynamicMethod method = null;
// RubyModule topModule = origin.getMethodLocation().getSuperClass();
//
// for(RubyModule module = origin; module != null; module = module.getSuperClass()) {
// method = module.searchMethodCommon(name);
// if (method != null) return method;
// }
//
// return null;
// }

// @Override
// public void populateInstanceMethodNames(Set<String> seen, RubyArray ary, final Visibility visibility, boolean not, boolean useSymbols, boolean includeSuper) {
// origin.populateInstanceMethodNames(seen, ary, visibility, not, useSymbols, true);
// }

@Override
public RubyModule findImplementer(RubyModule clazz) {
RubyModule retVal = null;
RubyModule topModule = origin.getMethodLocation().getSuperClass();

if (this == clazz) return this;

for (RubyModule module = origin; module != null; module = module.getSuperClass()) {
if (module.isSame(clazz.getNonIncludedClass())) {
retVal = module.getSuperClass() == null ? this : module;
break;
}

if (module.hasModuleInHierarchy(clazz)) {
retVal = module.findImplementer(clazz);
if (retVal != null) {
retVal = retVal.getSuperClass() != null ? retVal : this;
break;
}

for(RubyModule current = module.getNonIncludedClass(); current != this && current != null; current = current.getSuperClass()) {
if (current.isSame(clazz)) {
return current.getSuperClass() == null ? module : current;
}
}
break;
}
}

return retVal;
}

// @Override
// public boolean hasModuleInPrepends(RubyModule type) {
// for (RubyModule module = origin; module != null; module = module.getSuperClass()) {
// if (module.getNonIncludedClass() == type.getNonIncludedClass() || (module.isIncluded() && module.hasModuleInHierarchy(type)))
// return true;
// }
//
// return false;
// }

@Override
public boolean hasModuleInHierarchy(RubyModule type) {
for (RubyModule module = origin; module != null; module = module.getSuperClass()) {
if (module.getNonIncludedClass() == type.getNonIncludedClass() || (module.isIncluded() && module.hasModuleInHierarchy(type)))
return true;
}

return false;
}

@Override
public IRubyObject fetchConstant(String name, boolean includePrivate) {
RubyModule topModule = origin.getMethodLocation().getSuperClass();
for (RubyModule module = origin; module != null; module = module.getSuperClass()) {
IRubyObject value = module.fetchConstant(name, includePrivate);

if (value != null) {
return value == UNDEF ? resolveUndefConstant(name) : value;
}
}
return null;
}

// @Override
// protected boolean hasConstantInHierarchy(final String name) {
// for (RubyModule module = origin; module != null; module = module.getSuperClass()) {
// if (module.hasConstant(name))
// return true;
// }
// return false;
// }

@Override
public boolean isIncluded() {
return true;
}

@Override
public Map<String, DynamicMethod> getMethods() {
return origin.methodLocation.getMethods();
public boolean isPrepended() {
return origin.hasPrepends();
}

// XXX ??? maybe not getNonIncludedClass()
@Override
public Map<String, DynamicMethod> getMethodsForWrite() {
return origin.methodLocation.getMethodsForWrite();
protected boolean isSame(RubyModule module) {
return origin.isSame(module.getDelegate());
}

@Override
public RubyModule getMethodLocation() {
return origin.getMethodLocation();
public Map<String, DynamicMethod> getMethods() {
return origin.getMethods();
}

@Override
public RubyModule getNonIncludedClass() {
return origin;
public Map<String, DynamicMethod> getMethodsForWrite() {
return origin.getMethodsForWrite();
}

@Override
@@ -177,13 +287,46 @@ public List<String> getStoredConstantNameList() {
@Override
public Collection<String> getConstantNames() {
return origin.getConstantNames();
// Collection<String> names = new HashSet<String>(origin.getConstantMap().size());
// RubyModule topModule = origin.getMethodLocation().getSuperClass();
//
// for (RubyModule module = origin; module != null; module = module.getSuperClass()) {
// module.getConstantNamesInner(names);
// }
//
// return names;
}

// @Override
// public void getConstantNamesInner(Collection<String> names) {
// RubyModule topModule = origin.getMethodLocation().getSuperClass();
// for (RubyModule module = origin; module != null; module = module.getSuperClass()) {
// module.getConstantNamesInner(names);
// }
// }

@Override
public Collection<String> getConstantNames(boolean includePrivate) {
return origin.getConstantNames(includePrivate);
// Collection<String> names = new HashSet<String>(origin.getConstantMap().size());
// RubyModule topModule = origin.getMethodLocation().getSuperClass();
//
// for (RubyModule module = origin; module != null; module = module.getSuperClass()) {
// module.getConstantNamesInner(names, includePrivate);
// }
//
// return names;
}

// @Override
// public void getConstantNamesInner(Collection<String> names, boolean includePrivate) {
// RubyModule topModule = origin.getMethodLocation().getSuperClass();
//
// for (RubyModule module = origin; module != null; module = module.getSuperClass()) {
// module.getConstantNamesInner(names, includePrivate);
// }
// }

@Override
public IRubyObject getAutoloadConstant(String name) {
return origin.getAutoloadConstant(name);
243 changes: 144 additions & 99 deletions core/src/main/java/org/jruby/RubyModule.java

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/compiler/JITCompiler.java
Original file line number Diff line number Diff line change
@@ -190,7 +190,7 @@ public void run() {
// Check if the method has been explicitly excluded
if (config.getExcludedMethods().size() > 0) {
String excludeModuleName = className;
if (method.getImplementationClass().isSingleton()) {
if (method.getImplementationClass().getMethodLocation().isSingleton()) {
IRubyObject possibleRealClass = ((MetaClass) method.getImplementationClass()).getAttached();
if (possibleRealClass instanceof RubyModule) {
excludeModuleName = "Meta:" + ((RubyModule) possibleRealClass).getName();
Original file line number Diff line number Diff line change
@@ -350,6 +350,17 @@ public final boolean isUndefined() {
return this == UndefinedMethod.INSTANCE;
}

/**
* Whether this method is the "null" method, used to stop method
* name resolution loops. Only returns true for NullMethod instances,
* of which there should be only one (a singleton).
*
* @return true if this method is the undefined method; false otherwise
*/
public final boolean isNull() {
return this == NullMethod.INSTANCE;
}

/**
* Retrieve the arity of this method, used for reporting arity to Ruby
* code. This arity may or may not reflect the actual specific or variable
126 changes: 126 additions & 0 deletions core/src/main/java/org/jruby/internal/runtime/methods/NullMethod.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/***** BEGIN LICENSE BLOCK *****
* Version: EPL 1.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Eclipse Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.eclipse.org/legal/epl-v10.html
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Copyright (C) 2002-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
* Copyright (C) 2004-2005 Thomas E Enebo <enebo@acm.org>
* Copyright (C) 2014 Timur Duehr <tduehr@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the EPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the EPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/
package org.jruby.internal.runtime.methods;

import org.jruby.RubyModule;
import org.jruby.runtime.Block;
import org.jruby.runtime.CallType;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.builtin.IRubyObject;

/**
* This class represents a singleton type of method used as a marker for
* breaking method lookup loops. Like UndefinedMethod, only one instance is ever created, it
* can't be invoked, and shouldn't be returned as though it were a real method.
*/
public class NullMethod extends DynamicMethod {
public static final NullMethod INSTANCE = new NullMethod();

/**
* Constructor for the one NullMethod instance.
*/
private NullMethod() {
}

/**
* The one implementation of call, which throws an exception because
* NullMethod can't be invoked.
*
* @see DynamicMethod.call
*/
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule klazz, String name, IRubyObject[] args, Block block) {
throw new UnsupportedOperationException("BUG: invoking NullMethod.call; report at http://bugs.jruby.org");
}

/**
* A dummy implementation of dup that just returns the singleton instance.
*
* @return The singleton instance
*/
public DynamicMethod dup() {
return INSTANCE;
}

/**
* Retrieve the singleton instance.
*
* @return The singleton instance
*/
public static NullMethod getInstance() {
return INSTANCE;
}

/**
* Dummy override of setImplementationClass that does nothing.
*
* @param implClass Ignored
*/
@Override
public void setImplementationClass(RubyModule implClass) {
throw new UnsupportedOperationException("BUG: NullMethod is immutable: setImplmentationClass called; report at http://bugs.jruby.org");
// NullMethod should be immutable
}

/**
* Dummy implementation of setVisibility that does nothing.
*
* @param visibility Ignored
*/
@Override
public void setVisibility(Visibility visibility) {
throw new UnsupportedOperationException("BUG: NullMethod is immutable: setVisibility called; report at http://bugs.jruby.org");
// NullMethod should be immutable
}

/**
* Dummy implementation of setCallConfig that does nothing.
*
* @param callConfig Ignored
*/
@Override
public void setCallConfig(CallConfiguration callConfig) {
throw new UnsupportedOperationException("BUG: NullMethod is immutable: setCallConfig called; report at http://bugs.jruby.org");
// NullMethod should be immutable
}

/**
* NullMethod is always visible because it's only used as a marker to
* break method lookup loops.
*
* @param caller The calling object
* @param callType The type of call
* @return true always
*/
@Override
public boolean isCallableFrom(IRubyObject caller, CallType callType) {
return true;
}
}
30 changes: 18 additions & 12 deletions core/src/main/java/org/jruby/ir/IRBuilder.java
Original file line number Diff line number Diff line change
@@ -1447,25 +1447,31 @@ public Operand run() {
addInstr(scope, new LabelInstr(doneLabel));
return tmpVar;
}
case COLON3NODE:
return addResultInstr(scope, new RuntimeHelperCall(scope.createTemporaryVariable(), IS_DEFINED_CONSTANT_OR_METHOD,
new Operand[] {new ObjectClass(), new ConstantStringLiteral(((Colon3Node) node).getName())}));
case COLON2NODE: {
final Colon2Node colon = (Colon2Node) node;
final ConstantStringLiteral name = new ConstantStringLiteral(colon.getName());
case COLON3NODE: case COLON2NODE: {
// SSS FIXME: Is there a reason to do this all with low-level IR?
// Can't this all be folded into a Java method that would be part
// of the runtime library, which then can be used by buildDefinitionCheck method above?
// This runtime library would be used both by the interpreter & the compiled code!

final Colon3Node colon = (Colon3Node) node;
final String name = colon.getName();
final Variable errInfo = scope.createTemporaryVariable();

// Complicated case where LHS can be an expression - (eval "Foo")::Bar
addInstr(scope, new GetErrorInfoInstr(errInfo)); // store previous exception for restoration if we rescue something
// store previous exception for restoration if we rescue something
addInstr(scope, new GetErrorInfoInstr(errInfo));

CodeBlock protectedCode = new CodeBlock() {
public Operand run() {
Operand lhs = build(colon.getLeftNode(), scope);
return addResultInstr(scope, new RuntimeHelperCall(scope.createTemporaryVariable(),
IS_DEFINED_CONSTANT_OR_METHOD, new Operand[] {lhs, name}));
Operand v = colon instanceof Colon2Node ?
build(((Colon2Node)colon).getLeftNode(), scope) : new ObjectClass();

Variable tmpVar = scope.createTemporaryVariable();
addInstr(scope, new RuntimeHelperCall(tmpVar, IS_DEFINED_CONSTANT_OR_METHOD, new Operand[] {v, new ConstantStringLiteral(name)}));
return tmpVar;
}
};

// rescue block
CodeBlock rescueBlock = new CodeBlock() {
public Operand run() {
// Nothing to do -- ignore the exception, and restore stashed error info!
@@ -1474,7 +1480,7 @@ public Operand run() {
}
};

// Try verifying definition, and if we get an JumpException exception, process it with the rescue block above
// Try verifying definition, and if we get an JumpException exception, process it with the rescue block above
return protectCodeWithRescue(scope, protectedCode, rescueBlock);
}
case FCALLNODE: {
Original file line number Diff line number Diff line change
@@ -9,7 +9,11 @@
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.ir.transformations.inlining.CloneInfo;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.*;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.Block;
import org.jruby.runtime.CallType;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

public class InstanceSuperInstr extends CallInstr {
@@ -42,7 +46,7 @@ public CallBase specializeForInterpretation() {
public Object interpret(ThreadContext context, StaticScope currScope, DynamicScope currDynScope, IRubyObject self, Object[] temp) {
IRubyObject[] args = prepareArguments(context, self, getCallArgs(), currScope, currDynScope, temp);
Block block = prepareBlock(context, self, currScope, currDynScope, temp);
RubyModule definingModule = (RubyModule) getDefiningModule().retrieve(context, self, currScope, currDynScope, temp);
RubyModule definingModule = ((RubyModule) getDefiningModule().retrieve(context, self, currScope, currDynScope, temp)).getMethodLocation();
String methodName = methAddr.getName();
return IRRuntimeHelpers.instanceSuper(context, self, methodName, definingModule, args, block);
}
30 changes: 24 additions & 6 deletions core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
Original file line number Diff line number Diff line change
@@ -213,7 +213,7 @@ public static IRubyObject handlePropagatedBreak(ThreadContext context, DynamicSc
public static void defCompiledIRMethod(ThreadContext context, MethodHandle handle, String rubyName, DynamicScope currDynScope, IRubyObject self, IRScope irScope) {
Ruby runtime = context.runtime;

RubyModule containingClass = IRRuntimeHelpers.findInstanceMethodContainer(context, currDynScope, self);
RubyModule containingClass = IRRuntimeHelpers.findInstanceMethodContainer(context, currDynScope, self).getMethodLocation();
Visibility currVisibility = context.getCurrentVisibility();
Visibility newVisibility = Helpers.performNormalMethodChecksAndDetermineVisibility(runtime, containingClass, rubyName, currVisibility);

@@ -700,6 +700,7 @@ public static RubyModule findInstanceMethodContainer(ThreadContext context, Dyna
switch (scopeType) {
case MODULE_BODY:
case CLASS_BODY:
return ((RubyModule)self).getMethodLocation();
case METACLASS_BODY:
return (RubyModule) self;

@@ -803,7 +804,7 @@ public static IRubyObject instanceSuperSplatArgs(ThreadContext context, IRubyObj

@Interp
public static IRubyObject instanceSuper(ThreadContext context, IRubyObject self, String methodName, RubyModule definingModule, IRubyObject[] args, Block block) {
RubyClass superClass = definingModule.getSuperClass();
RubyClass superClass = definingModule.getMethodLocation().getSuperClass();
DynamicMethod method = superClass != null ? superClass.searchMethod(methodName) : UndefinedMethod.INSTANCE;
IRubyObject rVal = method.isUndefined() ? Helpers.callMethodMissing(context, self, method.getVisibility(), methodName, CallType.SUPER, args, block)
: method.call(context, self, superClass, methodName, args, block);
@@ -829,17 +830,34 @@ public static IRubyObject unresolvedSuperSplatArgs(ThreadContext context, IRubyO
}

public static IRubyObject unresolvedSuper(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {

// We have to rely on the frame stack to find the implementation class
RubyModule klazz = context.getFrameKlazz();
String methodName = context.getCurrentFrame().getName();

checkSuperDisabledOrOutOfMethod(context, klazz, methodName);
RubyClass superClass = Helpers.findImplementerIfNecessary(self.getMetaClass(), klazz).getSuperClass();
RubyModule implMod = Helpers.findImplementerIfNecessary(self.getMetaClass(), klazz);
RubyClass superClass = implMod.getSuperClass();
DynamicMethod method = superClass != null ? superClass.searchMethod(methodName) : UndefinedMethod.INSTANCE;
// DynamicMethod method = superClass == null ? null : superClass.searchWithCache(methodName, false).method;
//
// if (method == null || !superClass.isIncluded()) {
// for (RubyModule implClass = Helpers.findImplementerIfNecessary(self.getMetaClass(), klazz); implClass != null; implClass = Helpers.findImplementerIfNecessary(self.getMetaClass(), superClass)) {
// superClass = implClass == null ? null : implClass.getSuperClass();
//
// method = superClass != null ? superClass.searchWithCache(methodName, false).method : null;
// if (!(method == null || method.isUndefined() ) || superClass == null) break;
// }
// }
//
// method = method == null ? UndefinedMethod.getInstance() : method;

// TODO tduehr 7/2014 There has to be a better way to break the recursion
IRubyObject rVal = (method.isUndefined() || (superClass.isPrepended() && (method.getImplementationClass() == self.getType()))) ? Helpers.callMethodMissing(context, self, method.getVisibility(), methodName, CallType.SUPER, args, block)
: method.call(context, self, superClass, methodName, args, block);
IRubyObject rVal = null;
if (method.isUndefined()|| (superClass.isPrepended() && (method.getImplementationClass() == self.getType()))) {
rVal = Helpers.callMethodMissing(context, self, method.getVisibility(), methodName, CallType.SUPER, args, block);
} else {
rVal = method.call(context, self, superClass, methodName, args, block);
}

return rVal;
}
5 changes: 3 additions & 2 deletions core/src/main/java/org/jruby/java/util/BlankSlateWrapper.java
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
import org.jruby.RubyClass;
import org.jruby.RubyModule;
import org.jruby.internal.runtime.methods.DynamicMethod;
import org.jruby.internal.runtime.methods.NullMethod;

import java.util.regex.Pattern;

@@ -25,7 +26,7 @@ public BlankSlateWrapper(Ruby runtime, RubyClass superClass, RubyModule delegate
}

@Override
public DynamicMethod searchMethodInner(String name) {
protected DynamicMethod searchMethodCommon(String name) {
// this module is special and only searches itself; do not go to superclasses
// except for special methods

@@ -41,7 +42,7 @@ public DynamicMethod searchMethodInner(String name) {
return superClass.searchMethodInner(name);
}

return null;
return NullMethod.getInstance();
}

private static final Pattern KEEP = Pattern.compile("^(__|<|>|=)|^(class|initialize_copy|singleton_method_added|const_missing|inspect|method_missing|to_s)$|(\\?|!|=)$");
9 changes: 5 additions & 4 deletions core/src/main/java/org/jruby/runtime/IRBlockBody.java
Original file line number Diff line number Diff line change
@@ -92,16 +92,14 @@ public IRubyObject yieldSpecific(ThreadContext context, IRubyObject arg0, Bindin
}

private IRubyObject yieldSpecificMultiArgsCommon(ThreadContext context, IRubyObject[] args, Binding binding, Type type) {


int blockArity = arity().getValue();
if (blockArity == 0) {
args = IRubyObject.NULL_ARRAY; // discard args
} else if (blockArity == 1) {
args = new IRubyObject[] { RubyArray.newArrayNoCopy(context.runtime, args) };
}

if (type == Type.LAMBDA) arity().checkArity(context.runtime, args);
if (type == Type.LAMBDA) arity().checkArity(context.runtime, args);

return commonYieldPath(context, args, null, binding, type, Block.NULL_BLOCK);
}
@@ -121,7 +119,10 @@ public IRubyObject doYield(ThreadContext context, IRubyObject value, Binding bin
IRubyObject[] args;

int blockArity = arity().getValue();
if (blockArity >= -1 && blockArity <= 1) {

// For lambdas, independent of whether there is a REST arg or not, if # required args is 1,
// the value is passed through unmodified even when it is an array!
if ((type == Type.LAMBDA && arity().required() == 1) || (blockArity >= -1 && blockArity <= 1)) {
args = new IRubyObject[] { value };
} else {
IRubyObject val0 = Helpers.aryToAry(value);
Original file line number Diff line number Diff line change
@@ -54,7 +54,7 @@
import org.jruby.RubyString;
import org.jruby.RubyStruct;
import org.jruby.RubySymbol;
import org.jruby.IncludedModule;
import org.jruby.IncludedModuleWrapper;
import org.jruby.runtime.ClassIndex;
import org.jruby.runtime.Constants;
import org.jruby.runtime.builtin.IRubyObject;
@@ -456,7 +456,7 @@ private RubyClass dumpExtended(RubyClass type) throws IOException {
}
while(type.isIncluded()) {
write('e');
writeAndRegisterSymbol(((IncludedModule)type).getNonIncludedClass().getName());
writeAndRegisterSymbol(((IncludedModuleWrapper)type).getNonIncludedClass().getName());
type = type.getSuperClass();
}
return type;
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
49 changes: 49 additions & 0 deletions core/src/main/java/org/jruby/truffle/nodes/cast/UnboxingNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.nodes.cast;

import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.Unboxable;

import java.math.BigInteger;

@NodeChild("child")
public abstract class UnboxingNode extends RubyNode {

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

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

public abstract Object executeUnbox(VirtualFrame frame, Object value);

@Specialization public boolean unbox(boolean value) { return value; }
@Specialization public int unbox(int value) { return value; }
@Specialization public long unbox(long value) { return value; }
@Specialization public double unbox(double value) { return value; }
@Specialization public BigInteger unbox(BigInteger value) { return value; }

@Specialization
public Object unbox(Object value) {
if (value instanceof Unboxable) {
return ((Unboxable) value).unbox();
} else {
return value;
}
}
}
Original file line number Diff line number Diff line change
@@ -20,6 +20,8 @@
import com.oracle.truffle.api.frame.VirtualFrame;
import org.jruby.runtime.Visibility;
import org.jruby.truffle.nodes.RubyCallNode;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.cast.UnboxingNodeFactory;
import org.jruby.truffle.nodes.dispatch.Dispatch;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
import org.jruby.truffle.nodes.yield.YieldDispatchHeadNode;
@@ -102,52 +104,51 @@ public ReferenceEqualNode(ReferenceEqualNode prev) {
super(prev);
}

public abstract boolean executeEqual(VirtualFrame frame, Object a, Object b);
// The @CreateCast is not applied when using this, so the caller needs to unbox itself.
protected abstract boolean executeEqualWithUnboxed(VirtualFrame frame, Object a, Object b);

@CreateCast("arguments") public RubyNode[] createCast(RubyNode[] arguments) {
return new RubyNode[]{
UnboxingNodeFactory.create(getContext(), getSourceSection(), arguments[0]),
UnboxingNodeFactory.create(getContext(), getSourceSection(), arguments[1])
};
}

@Specialization public boolean equal(boolean a, boolean b) { return a == b; }
@Specialization public boolean equal(int a, int b) { return a == b; }
@Specialization public boolean equal(long a, long b) { return a == b; }
@Specialization public boolean equal(double a, double b) { return a == b; }
@Specialization public boolean equal(BigInteger a, BigInteger b) { return a == b; }
@Specialization public boolean equal(BigInteger a, BigInteger b) { return a == b; } // On purpose, Bignum are not #equal?

@Specialization(guards = {"firstUnboxable", "secondUnboxable"})
public boolean equalUnboxable(Object a, Object b) {
return ((Unboxable) a).unbox().equals(((Unboxable) b).unbox());
@Specialization public boolean equal(RubyBasicObject a, RubyBasicObject b) {
assert !(a instanceof Unboxable) && !(b instanceof Unboxable);
return a == b;
}

@Specialization(guards = {"firstUnboxable", "!secondUnboxable"})
public boolean equalFirstUnboxable(Object a, Object b) {
return ((Unboxable) a).unbox().equals(b);
@Specialization(guards = {"isNotRubyBasicObject(arguments[0])", "isNotRubyBasicObject(arguments[1])", "notSameClass"})
public boolean equal(Object a, Object b) {
assert !(a instanceof Unboxable) && !(b instanceof Unboxable);
return false;
}

@Specialization(guards = {"!firstUnboxable", "secondUnboxable"})
public boolean equalSecondUnboxable(Object a, Object b) {
return a.equals(((Unboxable) b).unbox());
@Specialization(guards = "isNotRubyBasicObject(arguments[0])")
public boolean equal(Object a, RubyBasicObject b) {
assert !(b instanceof Unboxable);
return false;
}

@Specialization
public boolean equal(Object a, Object b) {
if (a instanceof Unboxable) {
if (b instanceof Unboxable) {
return ((Unboxable) a).unbox().equals(((Unboxable) b).unbox());
} else {
return ((Unboxable) a).unbox().equals(b);
}
} else {
if (b instanceof Unboxable) {
return a.equals(((Unboxable) b).unbox());
} else {
return a == b;
}
}
@Specialization(guards = "isNotRubyBasicObject(arguments[1])")
public boolean equal(RubyBasicObject a, Object b) {
assert !(a instanceof Unboxable);
return false;
}

protected boolean firstUnboxable(Object a, Object b) {
return a instanceof Unboxable;
protected boolean isNotRubyBasicObject(Object value) {
return !(value instanceof RubyBasicObject);
}

protected boolean secondUnboxable(Object a, Object b) {
return b instanceof Unboxable;
protected boolean notSameClass(Object a, Object b) {
return a.getClass() != b.getClass();
}

}
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();
}
}

97 changes: 49 additions & 48 deletions core/src/main/java/org/jruby/truffle/nodes/core/FixnumNodes.java
Original file line number Diff line number Diff line change
@@ -1098,88 +1098,89 @@ public abstract static class LeftShiftNode extends CoreMethodNode {

@Child protected FixnumOrBignumNode fixnumOrBignum;

private final BranchProfile bAboveZeroProfile = BranchProfile.create();
private final BranchProfile bNotAboveZeroProfile = BranchProfile.create();
private final BranchProfile useBignumProfile = BranchProfile.create();

public LeftShiftNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
fixnumOrBignum = new FixnumOrBignumNode();
}

public LeftShiftNode(LeftShiftNode prev) {
super(prev);
fixnumOrBignum = prev.fixnumOrBignum;
}

@Specialization(guards = "canShiftIntoInt")
protected Object lower(BigInteger value) {
if (fixnumOrBignum == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
fixnumOrBignum = insert(new FixnumOrBignumNode());
}
return fixnumOrBignum.fixnumOrBignum(value);
}

@Specialization(guards = {"isPositive(arguments[1])", "canShiftIntoInt"})
public int leftShift(int a, int b) {
if (b > 0) {
bAboveZeroProfile.enter();
return a << b;
}

return a << b;
} else {
bNotAboveZeroProfile.enter();
if (-b >= Integer.SIZE) {
return 0;
} else {
return a >> -b;
}
}
@Specialization(guards = {"isPositive(arguments[1])", "canShiftIntoLong"})
public long leftShiftToLong(int a, int b) {
return leftShiftToLong((long) a, b);
}

@Specialization
@Specialization(guards = {"isPositive(arguments[1])"})
public Object leftShiftWithOverflow(int a, int b) {
return leftShiftWithOverflow((long) a, b);
}

@Specialization(guards = "canShiftIntoLong")
public long leftShift(long a, int b) {
if (b > 0) {
bAboveZeroProfile.enter();

return a << b;
@Specialization(guards = "isStrictlyNegative(arguments[1])")
public int leftShiftNeg(int a, int b) {
if (-b >= Integer.SIZE) {
return 0;
} else {
bNotAboveZeroProfile.enter();

if (-b >= Long.SIZE) {
return 0;
} else {
return a >> -b;
}
return a >> -b;
}
}

@Specialization
public Object leftShiftWithOverflow(long a, int b) {
if (b > 0) {
bAboveZeroProfile.enter();
@Specialization(guards = {"isPositive(arguments[1])", "canShiftIntoLong"})
public long leftShiftToLong(long a, int b) {
return a << b;
}

if (canShiftIntoLong(a, b)) {
return a << b;
} else {
useBignumProfile.enter();
return fixnumOrBignum.fixnumOrBignum(RuntimeBigInteger.shiftLeft(BigInteger.valueOf(a), b));
}
@Specialization(guards = {"isPositive(arguments[1])"})
public Object leftShiftWithOverflow(long a, int b) {
if (canShiftIntoLong(a, b)) {
return leftShiftToLong(a, b);
} else {
bNotAboveZeroProfile.enter();
return lower(RuntimeBigInteger.shiftLeft(BigInteger.valueOf(a), b));
}
}

if (-b >= Long.SIZE) {
return 0;
} else {
return a >> -b;
}
@Specialization(guards = "isStrictlyNegative(arguments[1])")
public long leftShiftNeg(long a, int b) {
if (-b >= Integer.SIZE) {
return 0;
} else {
return a >> -b;
}
}

static boolean canShiftIntoInt(int a, int b) {
return Integer.numberOfLeadingZeros(a) - b > 0;
}

static boolean canShiftIntoLong(int a, int b) {
return canShiftIntoLong((long) a, b);
}

static boolean canShiftIntoLong(long a, int b) {
return Long.numberOfLeadingZeros(a) - b > 0;
}

static boolean isPositive(int value) {
return value >= 0;
}

static boolean isStrictlyNegative(int value) {
return value < 0;
}

}

@CoreMethod(names = ">>", required = 1, lowerFixnumParameters = 0)
42 changes: 36 additions & 6 deletions core/src/main/java/org/jruby/truffle/nodes/core/KernelNodes.java
Original file line number Diff line number Diff line change
@@ -46,28 +46,58 @@ public abstract class KernelNodes {
@CoreMethod(names = "===", required = 1)
public abstract static class SameOrEqualNode extends CoreMethodNode {

@Child protected UnboxingNode unboxLeftNode;
@Child protected UnboxingNode unboxRightNode;
@Child protected BasicObjectNodes.ReferenceEqualNode referenceEqualNode;
@Child protected DispatchHeadNode equalNode;

public SameOrEqualNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
referenceEqualNode = BasicObjectNodesFactory.ReferenceEqualNodeFactory.create(context, sourceSection, new RubyNode[]{null, null});
equalNode = new DispatchHeadNode(context);
}

public SameOrEqualNode(SameOrEqualNode prev) {
super(prev);
referenceEqualNode = prev.referenceEqualNode;
equalNode = prev.equalNode;
}

protected Object unboxLeft(VirtualFrame frame, Object value) {
if (unboxLeftNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
unboxLeftNode = insert(UnboxingNodeFactory.create(getContext(), getSourceSection(), null));
}
return unboxLeftNode.executeUnbox(frame, value);
}

protected Object unboxRight(VirtualFrame frame, Object value) {
if (unboxRightNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
unboxRightNode = insert(UnboxingNodeFactory.create(getContext(), getSourceSection(), null));
}
return unboxRightNode.executeUnbox(frame, value);
}

protected boolean areSame(VirtualFrame frame, Object left, Object right) {
if (referenceEqualNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
referenceEqualNode = insert(BasicObjectNodesFactory.ReferenceEqualNodeFactory.create(getContext(), getSourceSection(), new RubyNode[]{null, null}));
}
return referenceEqualNode.executeEqualWithUnboxed(frame, left, right);
}

protected boolean areEqual(VirtualFrame frame, Object left, Object right) {
if (equalNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
equalNode = insert(new DispatchHeadNode(getContext()));
}
return equalNode.callIsTruthy(frame, left, "==", null, right);
}

public abstract boolean executeSameOrEqual(VirtualFrame frame, Object a, Object b);

@Specialization
public boolean sameOrEqual(VirtualFrame frame, Object a, Object b) {
if (referenceEqualNode.executeEqual(frame, a, b))
if (areSame(frame, unboxLeft(frame, a), unboxRight(frame, b)))
return true;
return equalNode.callIsTruthy(frame, a, "==", null, b);
return areEqual(frame, a, b);
}

}
Original file line number Diff line number Diff line change
@@ -491,15 +491,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 +509,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;
}

}
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.TruffleBoundary
Original file line number Diff line number Diff line change
@@ -20,16 +20,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 +35,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 +49,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(this, 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,8 +12,10 @@
import org.jruby.truffle.runtime.core.RubyModule;

public class LexicalScope {
final LexicalScope parent;
RubyModule liveModule;
public static final LexicalScope NONE = null;

private final LexicalScope parent;
private RubyModule liveModule;

public LexicalScope(LexicalScope parent, RubyModule liveModule) {
this.parent = parent;
31 changes: 21 additions & 10 deletions core/src/main/java/org/jruby/truffle/runtime/ModuleOperations.java
Original file line number Diff line number Diff line change
@@ -58,7 +58,12 @@ public static Map<String, RubyConstant> getAllConstants(RubyModule module) {
return constants;
}

public static RubyConstant lookupConstant(LexicalScope lexicalScope, RubyModule module, String name) {
/**
* @param lexicalScope The surrounding LexicalScope, null if it is ignored (as in Mod::Constant)
* @param module The receiver of the constant lookup.
* Identical to lexicalScope.getLiveModule() if there no qualifier (Constant).
*/
public static RubyConstant lookupConstant(RubyContext context, LexicalScope lexicalScope, RubyModule module, String name) {
CompilerAsserts.neverPartOfCompilation();

RubyConstant constant;
@@ -71,17 +76,23 @@ public static RubyConstant lookupConstant(LexicalScope lexicalScope, RubyModule
}

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

while (lexicalScope != null && lexicalScope != context.getRootLexicalScope()) { // TODO: looking twice self ?
constant = lexicalScope.getLiveModule().getConstants().get(name);

if (constant != null) {
return constant;
if (lexicalScope != null) {
if (lexicalScope.getLiveModule() == module && lexicalScope != context.getRootLexicalScope()) {
// Already looked in module.
lexicalScope = lexicalScope.getParent();
}

lexicalScope = lexicalScope.getParent();
while (lexicalScope != context.getRootLexicalScope()) {
constant = lexicalScope.getLiveModule().getConstants().get(name);

if (constant != null) {
return constant;
}

lexicalScope = lexicalScope.getParent();
}
}

// Look in ancestors
@@ -93,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;
}

}
Original file line number Diff line number Diff line change
@@ -527,6 +527,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
@@ -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
@@ -36,11 +36,6 @@ public int hashCode() {
return Boolean.FALSE.hashCode();
}

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

@Override
public boolean hasClassAsSingleton() {
return true;
49 changes: 43 additions & 6 deletions core/src/main/java/org/jruby/truffle/runtime/core/RubyModule.java
Original file line number Diff line number Diff line change
@@ -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) {
@@ -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
@@ -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
48 changes: 28 additions & 20 deletions core/src/main/java/org/jruby/truffle/translator/BodyTranslator.java
Original file line number Diff line number Diff line change
@@ -598,16 +598,6 @@ public RubyNode visitClassNode(org.jruby.ast.ClassNode node) {
return openModule(sourceSection, defineOrGetClass, name, node.getBodyNode());
}

private RubyNode translateCPath(SourceSection sourceSection, org.jruby.ast.Colon3Node node) {
if (node instanceof Colon2ImplicitNode) { // use current lexical scope
return new LexicalScopeNode(context, sourceSection, environment.getLexicalScope());
} else if (node instanceof Colon2ConstNode) { // A::B
return node.childNodes().get(0).accept(this);
} else { // Colon3Node: on top-level (Object)
return new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getObjectClass());
}
}

@Override
public RubyNode visitClassVarAsgnNode(org.jruby.ast.ClassVarAsgnNode node) {
final SourceSection sourceSection = translate(node.getPosition());
@@ -635,24 +625,35 @@ 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) {
if (node instanceof Colon2ImplicitNode) { // use current lexical scope
return new LexicalScopeNode(context, sourceSection, environment.getLexicalScope());
} else if (node instanceof Colon2ConstNode) { // A::B
return node.childNodes().get(0).accept(this);
} else { // Colon3Node: on top-level (Object)
return new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getObjectClass());
}
}

@Override
@@ -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);
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
@@ -231,12 +231,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
@@ -681,6 +681,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>
6 changes: 0 additions & 6 deletions spec/tags/ruby/core/module/prepend_features_tags.txt

This file was deleted.

17 changes: 1 addition & 16 deletions spec/tags/ruby/core/module/prepend_tags.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1 @@
fails:Module#prepend calls #prepend_features(self) in reversed order on each module
fails:Module#prepend raises a TypeError when the argument is not a Module
fails:Module#prepend imports instance methods
fails:Module#prepend allows wrapping methods
fails:Module#prepend also prepends included modules
fails:Module#prepend prepends multiple modules in the right order
fails:Module#prepend includes prepended modules in ancestors
fails:Module#prepend sees an instance of a prepended class as kind of the prepended module
fails:Module#prepend keeps the module in the chain when dupping the class
fails:Module#prepend keeps the module in the chain when dupping an intermediate module
fails:Module#prepend inserts a later prepended module into the chain
fails:Module#prepend works with subclasses
fails:Module#prepend calls prepended after prepend_features
fails:Module#prepend detects cyclic prepends
fails:Module#prepend returns the class it's included into
fails:Module#prepend clears any caches
fails:Module#prepend throws a NoMethodError when there is no more superclass
2 changes: 1 addition & 1 deletion spec/tags/ruby/core/module/prepended_tags.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
fails:Module#prepended is a private method
prepend:Module#prepended is a private method
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
10 changes: 5 additions & 5 deletions test/mri/excludes/TestModule.rb
Original file line number Diff line number Diff line change
@@ -23,11 +23,11 @@
exclude :test_nested_defined, "needs investigation"
exclude :test_nested_defined_bad_class, "needs investigation"
exclude :test_nested_get_symbol, "needs investigation"
exclude :test_prepend, "needs investigation"
exclude :test_prepend_class_ancestors, "needs investigation"
exclude :test_prepend_instance_methods_false, "needs investigation"
exclude :test_prepend_module_ancestors, "needs investigation"
exclude :test_prepend_super_in_alias, "needs investigation"
# exclude :test_prepend, "needs investigation"
# exclude :test_prepend_class_ancestors, "needs investigation"
# exclude :test_prepend_instance_methods_false, "needs investigation"
# exclude :test_prepend_module_ancestors, "needs investigation"
# exclude :test_prepend_super_in_alias, "needs investigation"
exclude :test_private_constant_reopen, "needs investigation"
exclude :test_private_constant_with_no_args, "needs investigation"
exclude :test_private_constants_clear_inlinecache, "fails to launch external JRuby instance"
23 changes: 23 additions & 0 deletions test/pom.rb
Original file line number Diff line number Diff line change
@@ -139,6 +139,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
@@ -265,6 +265,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>

0 comments on commit 7192c00

Please sign in to comment.