Skip to content

Commit

Permalink
Merge branch 'master' into truffle-head
Browse files Browse the repository at this point in the history
  • Loading branch information
eregon committed Nov 11, 2014
2 parents 41a6379 + dbed571 commit 9cf6a67
Show file tree
Hide file tree
Showing 40 changed files with 443 additions and 332 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -67,7 +67,7 @@ branches:
before_install:
- if [[ $TRAVIS_JDK_VERSION = 'oraclejdk8' ]]; then sudo apt-get update; sudo apt-get install oracle-java8-installer; else true; fi

script: mvn package && travis_retry mvn install $TARGET -Dinvoker.skip=false | egrep -v 'Download|\\[exec\\] [[:digit:]]+/[[:digit:]]+|^[[:space:]]*\\[exec\\][[:space:]]*$' ; [ ${PIPESTATUS[0]} == 0 ]
script: travis_retry mvn install $TARGET -Dinvoker.skip=false | egrep -v 'Download|\\[exec\\] [[:digit:]]+/[[:digit:]]+|^[[:space:]]*\\[exec\\][[:space:]]*$' ; [ ${PIPESTATUS[0]} == 0 ]
install: /bin/true
notifications:
irc:
Expand Down
2 changes: 1 addition & 1 deletion core/pom.xml
Expand Up @@ -146,7 +146,7 @@
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jzlib</artifactId>
<version>1.1.2</version>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>com.martiansoftware</groupId>
Expand Down
12 changes: 12 additions & 0 deletions core/src/main/java/org/jruby/Ruby.java
Expand Up @@ -3503,6 +3503,14 @@ public RaiseException newErrnoELOOPError() {
return newRaiseException(getErrno().getClass("ELOOP"), "Too many levels of symbolic links");
}

public RaiseException newErrnoEMFILEError() {
return newRaiseException(getErrno().getClass("EMFILE"), "Too many open files");
}

public RaiseException newErrnoENFILEError() {
return newRaiseException(getErrno().getClass("ENFILE"), "Too many open files in system");
}

public RaiseException newErrnoENOENTError() {
return newRaiseException(getErrno().getClass("ENOENT"), "File not found");
}
Expand Down Expand Up @@ -3862,6 +3870,10 @@ public RaiseException newIOErrorFromException(IOException e) {
return newErrnoECONNRESETError();
} else if ("Too many levels of symbolic links".equals(e.getMessage())) {
return newErrnoELOOPError();
} else if ("Too many open files".equals(e.getMessage())) {
return newErrnoEMFILEError();
} else if ("Too many open files in system".equals(e.getMessage())) {
return newErrnoENFILEError();
}
return newRaiseException(getIOError(), e.getMessage());
} else {
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/RubyMethod.java
Expand Up @@ -304,7 +304,7 @@ public IRubyObject parameters(ThreadContext context) {

@JRubyMethod(optional = 1)
public IRubyObject curry(ThreadContext context, IRubyObject[] args) {
return to_proc(context, null).callMethod(context, "curry", args);
return to_proc(context, Block.NULL_BLOCK).callMethod(context, "curry", args);
}

@JRubyMethod
Expand Down
6 changes: 3 additions & 3 deletions core/src/main/java/org/jruby/RubyModule.java
Expand Up @@ -1866,9 +1866,9 @@ public boolean equals(Object other) {
@JRubyMethod(name = "==", required = 1)
@Override
public IRubyObject op_equal(ThreadContext context, IRubyObject other) {
if(!(other instanceof RubyModule))
return context.runtime.getFalse();
RubyModule otherModule = (RubyModule)other;
if(!(other instanceof RubyModule)) return context.runtime.getFalse();

RubyModule otherModule = (RubyModule) other;
if(otherModule.isIncluded()) {
return context.runtime.newBoolean(otherModule.isSame(this));
} else {
Expand Down
2 changes: 0 additions & 2 deletions core/src/main/java/org/jruby/RubyStruct.java
Expand Up @@ -564,8 +564,6 @@ private IRubyObject inspectStruct(final ThreadContext context, boolean recur) {
for (int i = 0,k=member.getLength(); i < k; i++) {
if (i > 0) {
buffer.append(',').append(' ');
} else if (first != '#') {
buffer.append(' ');
}
RubySymbol slot = (RubySymbol)member.eltInternal(i);
String name = slot.toString();
Expand Down
77 changes: 74 additions & 3 deletions core/src/main/java/org/jruby/RubyThread.java
Expand Up @@ -1417,27 +1417,98 @@ private boolean abortOnException(Ruby runtime) {
public static RubyThread mainThread(IRubyObject receiver) {
return receiver.getRuntime().getThreadService().getMainThread();
}


/**
* Perform an interruptible select operation on the given channel and fptr,
* waiting for the requested operations or the given timeout.
*
* @param io the RubyIO that contains the channel, for managing blocked threads list.
* @param ops the operations to wait for, from {@see java.nio.channels.SelectionKey}.
* @return true if the IO's channel became ready for the requested operations, false if
* it was not selectable.
*/
public boolean select(RubyIO io, int ops) {
return select(io.getChannel(), io.getOpenFile(), ops);
}


/**
* Perform an interruptible select operation on the given channel and fptr,
* waiting for the requested operations or the given timeout.
*
* @param io the RubyIO that contains the channel, for managing blocked threads list.
* @param ops the operations to wait for, from {@see java.nio.channels.SelectionKey}.
* @param timeout a timeout in ms to limit the select. Less than zero selects forever,
* zero selects and returns ready channels or nothing immediately, and
* greater than zero selects for at most that many ms.
* @return true if the IO's channel became ready for the requested operations, false if
* it timed out or was not selectable.
*/
public boolean select(RubyIO io, int ops, long timeout) {
return select(io.getChannel(), io.getOpenFile(), ops, timeout);
}

/**
* Perform an interruptible select operation on the given channel and fptr,
* waiting for the requested operations.
*
* @param channel the channel to perform a select against. If this is not
* a selectable channel, then this method will just return true.
* @param fptr the fptr that contains the channel, for managing blocked threads list.
* @param ops the operations to wait for, from {@see java.nio.channels.SelectionKey}.
* @return true if the channel became ready for the requested operations, false if
* it was not selectable.
*/
public boolean select(Channel channel, OpenFile fptr, int ops) {
return select(channel, fptr, ops, -1);
}

/**
* Perform an interruptible select operation on the given channel and fptr,
* waiting for the requested operations.
*
* @param channel the channel to perform a select against. If this is not
* a selectable channel, then this method will just return true.
* @param io the RubyIO that contains the channel, for managing blocked threads list.
* @param ops the operations to wait for, from {@see java.nio.channels.SelectionKey}.
* @return true if the channel became ready for the requested operations, false if
* it was not selectable.
*/
public boolean select(Channel channel, RubyIO io, int ops) {
return select(channel, io == null ? null : io.getOpenFile(), ops, -1);
}

/**
* Perform an interruptible select operation on the given channel and fptr,
* waiting for the requested operations or the given timeout.
*
* @param channel the channel to perform a select against. If this is not
* a selectable channel, then this method will just return true.
* @param io the RubyIO that contains the channel, for managing blocked threads list.
* @param ops the operations to wait for, from {@see java.nio.channels.SelectionKey}.
* @param timeout a timeout in ms to limit the select. Less than zero selects forever,
* zero selects and returns ready channels or nothing immediately, and
* greater than zero selects for at most that many ms.
* @return true if the channel became ready for the requested operations, false if
* it timed out or was not selectable.
*/
public boolean select(Channel channel, RubyIO io, int ops, long timeout) {
return select(channel, io == null ? null : io.getOpenFile(), ops, timeout);
}

/**
* Perform an interruptible select operation on the given channel and fptr,
* waiting for the requested operations or the given timeout.
*
* @param channel the channel to perform a select against. If this is not
* a selectable channel, then this method will just return true.
* @param fptr the fptr that contains the channel, for managing blocked threads list.
* @param ops the operations to wait for, from {@see java.nio.channels.SelectionKey}.
* @param timeout a timeout in ms to limit the select. Less than zero selects forever,
* zero selects and returns ready channels or nothing immediately, and
* greater than zero selects for at most that many ms.
* @return true if the channel became ready for the requested operations, false if
* it timed out or was not selectable.
*/
public boolean select(Channel channel, OpenFile fptr, int ops, long timeout) {
// Use selectables but only if they're not associated with a file (which has odd select semantics)
if (channel instanceof SelectableChannel && (fptr == null || !fptr.fd().isNativeFile)) {
Expand All @@ -1449,7 +1520,7 @@ public boolean select(Channel channel, OpenFile fptr, int ops, long timeout) {
SelectionKey key = null;
try {
selectable.configureBlocking(false);

if (fptr != null) fptr.addBlockingThread(this);
currentSelector = getRuntime().getSelectorPool().get(selectable.provider());

Expand Down
104 changes: 80 additions & 24 deletions core/src/main/java/org/jruby/ir/targets/Bootstrap.java
Expand Up @@ -15,15 +15,19 @@
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Block;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.invokedynamic.InvocationLinker;
import org.jruby.runtime.invokedynamic.VariableSite;
import org.jruby.runtime.ivars.FieldVariableAccessor;
import org.jruby.runtime.ivars.VariableAccessor;
import org.jruby.runtime.opto.OptoFactory;
import org.jruby.util.ByteList;
import org.jruby.util.RegexpOptions;
import org.jruby.util.cli.Options;
import org.jruby.util.log.Logger;
import org.jruby.util.log.LoggerFactory;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;

Expand All @@ -37,6 +41,7 @@
import static org.jruby.util.CodegenUtils.sig;

public class Bootstrap {
private static final Logger LOG = LoggerFactory.getLogger("Bootstrap");
static final Lookup LOOKUP = MethodHandles.lookup();

public static CallSite string(Lookup lookup, String name, MethodType type, String value, String encodingName) {
Expand Down Expand Up @@ -453,28 +458,48 @@ private static int getArgCount(Class[] args, boolean isStatic) {
}

public static IRubyObject ivarGet(VariableSite site, IRubyObject self) throws Throwable {
VariableAccessor accessor = self.getMetaClass().getRealClass().getVariableAccessorForRead(site.name());
RubyClass realClass = self.getMetaClass().getRealClass();
VariableAccessor accessor = realClass.getVariableAccessorForRead(site.name());

// produce nil if the variable has not been initialize
MethodHandle nullToNil = findStatic(Bootstrap.class, "instVarNullToNil", methodType(IRubyObject.class, IRubyObject.class, IRubyObject.class, String.class));
IRubyObject nil = self.getRuntime().getNil();
nullToNil = insertArguments(nullToNil, 1, nil, site.name());
MethodHandle nullToNil = findStatic(Helpers.class, "nullToNil", methodType(IRubyObject.class, IRubyObject.class, IRubyObject.class));
nullToNil = insertArguments(nullToNil, 1, self.getRuntime().getNil());
nullToNil = explicitCastArguments(nullToNil, methodType(IRubyObject.class, Object.class));

// get variable value and filter with nullToNil
MethodHandle getValue = findVirtual(IRubyObject.class, "getVariable", methodType(Object.class, int.class));
getValue = insertArguments(getValue, 1, accessor.getIndex());
MethodHandle getValue;
boolean direct = false;

if (accessor instanceof FieldVariableAccessor) {
direct = true;
int offset = ((FieldVariableAccessor)accessor).getOffset();
Class cls = REIFIED_OBJECT_CLASSES[offset];
getValue = lookup().findGetter(cls, "var" + offset, Object.class);
getValue = explicitCastArguments(getValue, methodType(Object.class, IRubyObject.class));
} else {
getValue = findStatic(VariableAccessor.class, "getVariable", methodType(Object.class, RubyBasicObject.class, int.class));
getValue = explicitCastArguments(getValue, methodType(Object.class, IRubyObject.class, int.class));
getValue = insertArguments(getValue, 1, accessor.getIndex());
}

getValue = filterReturnValue(getValue, nullToNil);

// prepare fallback
MethodHandle fallback = null;
if (site.getTarget() == null || site.chainCount() + 1 > Options.INVOKEDYNAMIC_MAXPOLY.load()) {
// if (RubyInstanceConfig.LOG_INDY_BINDINGS) LOG.info(site.name() + "\tget triggered site rebind " + self.getMetaClass().id);
fallback = findStatic(Bootstrap.class, "ivarGet", methodType(IRubyObject.class, VariableSite.class, IRubyObject.class));
if (site.chainCount() + 1 > Options.INVOKEDYNAMIC_MAXPOLY.load()) {
if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) LOG.info(site.name() + "\tqet on type " + self.getMetaClass().id + " failed (polymorphic)" + extractSourceInfo(site));
fallback = findStatic(Bootstrap.class, "ivarGetFail", methodType(IRubyObject.class, VariableSite.class, IRubyObject.class));
fallback = fallback.bindTo(site);
site.clearChainCount();
site.setTarget(fallback);
return (IRubyObject)fallback.invokeWithArguments(self);
} else {
// if (RubyInstanceConfig.LOG_INDY_BINDINGS) LOG.info(site.name() + "\tget added to PIC " + self.getMetaClass().id);
if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) {
if (direct) {
LOG.info(site.name() + "\tget field on type " + self.getMetaClass().id + " added to PIC" + extractSourceInfo(site));
} else {
LOG.info(site.name() + "\tget on type " + self.getMetaClass().id + " added to PIC" + extractSourceInfo(site));
}
}
fallback = site.getTarget();
site.incrementChainCount();
}
Expand All @@ -485,29 +510,52 @@ public static IRubyObject ivarGet(VariableSite site, IRubyObject self) throws Th

getValue = guardWithTest(test, getValue, fallback);

// if (RubyInstanceConfig.LOG_INDY_BINDINGS) LOG.info(site.name() + "\tget on class " + self.getMetaClass().id + " bound directly");
if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) LOG.info(site.name() + "\tget on class " + self.getMetaClass().id + " bound directly" + extractSourceInfo(site));
site.setTarget(getValue);

return Bootstrap.instVarNullToNil((IRubyObject)accessor.get(self), nil, site.name());
return (IRubyObject)getValue.invokeExact(self);
}

public static IRubyObject ivarGetFail(VariableSite site, IRubyObject self) throws Throwable {
return site.getVariable(self);
}

public static void ivarSet(VariableSite site, IRubyObject self, IRubyObject value) throws Throwable {
VariableAccessor accessor = self.getMetaClass().getRealClass().getVariableAccessorForWrite(site.name());
RubyClass realClass = self.getMetaClass().getRealClass();
VariableAccessor accessor = realClass.getVariableAccessorForWrite(site.name());

// set variable value and fold by returning value
MethodHandle setValue = findVirtual(IRubyObject.class, "setVariable", methodType(void.class, int.class, Object.class));
setValue = explicitCastArguments(setValue, methodType(void.class, IRubyObject.class, int.class, IRubyObject.class));
setValue = insertArguments(setValue, 1, accessor.getIndex());
MethodHandle setValue;
boolean direct = false;

if (accessor instanceof FieldVariableAccessor) {
direct = true;
int offset = ((FieldVariableAccessor)accessor).getOffset();
Class cls = REIFIED_OBJECT_CLASSES[offset];
setValue = findStatic(cls, "setVariableChecked", methodType(void.class, cls, Object.class));
setValue = explicitCastArguments(setValue, methodType(void.class, IRubyObject.class, IRubyObject.class));
} else {
setValue = findStatic(accessor.getClass(), "setVariableChecked", methodType(void.class, RubyBasicObject.class, RubyClass.class, int.class, Object.class));
setValue = explicitCastArguments(setValue, methodType(void.class, IRubyObject.class, RubyClass.class, int.class, IRubyObject.class));
setValue = insertArguments(setValue, 1, realClass, accessor.getIndex());
}

// prepare fallback
MethodHandle fallback = null;
if (site.getTarget() == null || site.chainCount() + 1 > Options.INVOKEDYNAMIC_MAXPOLY.load()) {
// if (RubyInstanceConfig.LOG_INDY_BINDINGS) LOG.info(site.name() + "\tset triggered site rebind " + self.getMetaClass().id);
fallback = findStatic(Bootstrap.class, "ivarSet", methodType(void.class, VariableSite.class, IRubyObject.class, IRubyObject.class));
if (site.chainCount() + 1 > Options.INVOKEDYNAMIC_MAXPOLY.load()) {
if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) LOG.info(site.name() + "\tset on type " + self.getMetaClass().id + " failed (polymorphic)" + extractSourceInfo(site));
fallback = findStatic(Bootstrap.class, "ivarSetFail", methodType(void.class, VariableSite.class, IRubyObject.class, IRubyObject.class));
fallback = fallback.bindTo(site);
site.clearChainCount();
site.setTarget(fallback);
fallback.invokeExact(self, value);
} else {
// if (RubyInstanceConfig.LOG_INDY_BINDINGS) LOG.info(site.name() + "\tset added to PIC " + self.getMetaClass().id);
if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) {
if (direct) {
LOG.info(site.name() + "\tset field on type " + self.getMetaClass().id + " added to PIC" + extractSourceInfo(site));
} else {
LOG.info(site.name() + "\tset on type " + self.getMetaClass().id + " added to PIC" + extractSourceInfo(site));
}
}
fallback = site.getTarget();
site.incrementChainCount();
}
Expand All @@ -519,10 +567,14 @@ public static void ivarSet(VariableSite site, IRubyObject self, IRubyObject valu

setValue = guardWithTest(test, setValue, fallback);

// if (RubyInstanceConfig.LOG_INDY_BINDINGS) LOG.info(site.name() + "\tset on class " + self.getMetaClass().id + " bound directly");
if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) LOG.info(site.name() + "\tset on class " + self.getMetaClass().id + " bound directly" + extractSourceInfo(site));
site.setTarget(setValue);

accessor.set(self, value);
setValue.invokeExact(self, value);
}

public static void ivarSetFail(VariableSite site, IRubyObject self, IRubyObject value) throws Throwable {
site.setVariable(self, value);
}

private static MethodHandle findStatic(Class target, String name, MethodType type) {
Expand Down Expand Up @@ -661,4 +713,8 @@ public static IRubyObject instVarNullToNil(IRubyObject value, IRubyObject nil, S
public static boolean testArg0ModuleMatch(IRubyObject arg0, int id) {
return arg0 instanceof RubyModule && ((RubyModule)arg0).id == id;
}

private static String extractSourceInfo(VariableSite site) {
return " (" + site.file() + ":" + site.line() + ")";
}
}
Expand Up @@ -53,7 +53,7 @@ public Object execute(VirtualFrame frame) {

final RubyModule module = (RubyModule) receiverObject;

module.setModuleConstant(this, name, rhsValue);
module.setConstant(this, name, rhsValue);

return rhsValue;
}
Expand Down

0 comments on commit 9cf6a67

Please sign in to comment.