Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 0b2ea13bf4d3
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: db2de9e1ce83
Choose a head ref
  • 4 commits
  • 12 files changed
  • 1 contributor

Commits on Jan 21, 2015

  1. Improvements to sleep and executeTask.

    * Don't set unblockFunc before unblockData it needs.
    * For infinite sleep, always return true on interrupt.
    headius committed Jan 21, 2015
    Copy the full SHA
    c4a55ac View commit details
  2. Copy the full SHA
    b1731ad View commit details
  3. Copy the full SHA
    1c09a50 View commit details
  4. Copy the full SHA
    db2de9e View commit details
14 changes: 9 additions & 5 deletions core/src/main/java/org/jruby/RubyException.java
Original file line number Diff line number Diff line change
@@ -132,12 +132,8 @@ public RubyException exception(IRubyObject[] args) {
}
}

public IRubyObject to_s(ThreadContext context) {
return to_s19(context);
}

@JRubyMethod(name = "to_s")
public IRubyObject to_s19(ThreadContext context) {
public IRubyObject to_s(ThreadContext context) {
if (message.isNil()) return context.runtime.newString(getMetaClass().getRealClass().getName());

message.setTaint(isTaint());
@@ -382,6 +378,14 @@ public static IRubyObject newException(ThreadContext context, RubyClass exceptio
return exceptionClass.callMethod(context, "new", message.convertToString());
}

@Deprecated
public IRubyObject to_s19(ThreadContext context) {
if (message.isNil()) return context.runtime.newString(getMetaClass().getRealClass().getName());

message.setTaint(isTaint());
return message.asString();
}

private BacktraceData backtraceData;
private IRubyObject backtrace;
public IRubyObject message;
7 changes: 5 additions & 2 deletions core/src/main/java/org/jruby/RubyThread.java
Original file line number Diff line number Diff line change
@@ -1223,9 +1223,12 @@ public boolean sleep(long millis) throws InterruptedException {
assert this == getRuntime().getCurrentContext().getThread();
sleepTask.millis = millis;
try {
if (executeTask(getContext(), null, sleepTask) >= millis) {
long timeSlept = executeTask(getContext(), null, sleepTask);
if (millis == 0 || timeSlept >= millis) {
// sleep was unbounded or we slept long enough
return true;
} else {
// sleep was bounded and we did not sleep long enough
return false;
}
} finally {
@@ -1344,8 +1347,8 @@ public void executeBlockingTask(BlockingTask task) throws InterruptedException {

public <Data, Return> Return executeTask(ThreadContext context, Data data, Task<Data, Return> task) throws InterruptedException {
try {
this.unblockFunc = task;
this.unblockArg = data;
this.unblockFunc = task;

// check for interrupt before going into blocking call
pollThreadEvents(context);
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/ir/IRBuilder.java
Original file line number Diff line number Diff line change
@@ -2992,7 +2992,7 @@ public Operand buildRedo(IRScope s) {
public Operand buildRegexp(RegexpNode reNode, IRScope s) {
// SSS FIXME: Rather than throw syntax error at runtime, we should detect
// regexp syntax errors at build time and add an exception-throwing instruction instead
return copyAndReturnValue(s, new Regexp(new StringLiteral(reNode.getValue()), reNode.getOptions()));
return copyAndReturnValue(s, new Regexp(reNode.getValue(), reNode.getOptions()));
}

public Operand buildRescue(RescueNode node, IRScope s) {
67 changes: 14 additions & 53 deletions core/src/main/java/org/jruby/ir/operands/Regexp.java
Original file line number Diff line number Diff line change
@@ -1,78 +1,39 @@
package org.jruby.ir.operands;

import org.jruby.RubyRegexp;
import org.jruby.RubyString;
import org.jruby.ir.IRVisitor;
import org.jruby.ir.transformations.inlining.CloneInfo;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.DynamicScope;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ByteList;
import org.jruby.util.RegexpOptions;

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

// Represents a regexp from ruby
//
// NOTE: This operand is only used in the initial stages of optimization
// Further down the line, this regexp operand could get converted to calls
// that actually build the Regexp object
public class Regexp extends Operand {
/**
* Represents a literal regexp from ruby, constructed on first traversal and then cached.
*/
public class Regexp extends ImmutableLiteral {
final public RegexpOptions options;
final private Operand regexp;
final private ByteList source;
private RubyRegexp rubyRegexp;

public Regexp(Operand regexp, RegexpOptions options) {
public Regexp(ByteList source, RegexpOptions options) {
super(OperandType.REGEXP);

this.regexp = regexp;
this.source = source;
this.options = options;
}

public Operand getRegexp() {
return regexp;
public ByteList getSource() {
return source;
}

@Override
public String toString() {
return "RE:|" + regexp + "|" + options;
}

@Override
public boolean hasKnownValue() {
return regexp.hasKnownValue();
}

@Override
public Operand getSimplifiedOperand(Map<Operand, Operand> valueMap, boolean force) {
Operand newRegexp = regexp.getSimplifiedOperand(valueMap, force);
return newRegexp == regexp ? this : new Regexp(newRegexp, options);
return "RE:|" + source + "|" + options;
}

/** Append the list of variables used in this operand to the input list */
@Override
public void addUsedVariables(List<Variable> l) {
regexp.addUsedVariables(l);
}

@Override
public Operand cloneForInlining(CloneInfo ii) {
return hasKnownValue() ? this : new Regexp(regexp.cloneForInlining(ii), options);
}

@Override
public Object retrieve(ThreadContext context, IRubyObject self, StaticScope currScope, DynamicScope currDynScope, Object[] temp) {
// FIXME (from RegexpNode.java): 1.9 should care about internal or external encoding and not kcode.
// If we have a constant regexp string or if the regexp patterns asks for caching, cache the regexp
if ((!regexp.hasKnownValue() && !options.isOnce()) || (rubyRegexp == null) || context.runtime.getKCode() != rubyRegexp.getKCode()) {
RubyString pattern = (RubyString) regexp.retrieve(context, self, currScope, currDynScope, temp);
RubyRegexp re = RubyRegexp.newRegexp(context.runtime, pattern.getByteList(), options);
re.setLiteral();
rubyRegexp = re;
}

return rubyRegexp;
public Object createCacheObject(ThreadContext context) {
return IRRuntimeHelpers.newLiteralRegexp(context, source, options);
}

@Override
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package org.jruby.ir.persistence;

import org.jcodings.specific.USASCIIEncoding;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.RubyEncoding;
import org.jruby.RubyInstanceConfig;
import org.jruby.ir.IRClosure;
import org.jruby.ir.IRManager;
import org.jruby.ir.operands.*;
import org.jruby.util.ByteList;
import org.jruby.util.KeyValuePair;
import org.jruby.util.RegexpOptions;

@@ -103,11 +106,12 @@ private Operand decodeLabel() {
}

private Regexp decodeRegexp() {
Operand regex = d.decodeOperand();
// FIXME: This is wrong
String source = d.decodeString();
boolean isNone = d.decodeBoolean();
RegexpOptions options = RegexpOptions.fromEmbeddedOptions(d.decodeInt());
options.setEncodingNone(isNone);
return new Regexp(regex, options);
return new Regexp(new ByteList(source.getBytes(RubyEncoding.UTF8), UTF8Encoding.INSTANCE), options);
}

private Operand decodeTemporaryVariable() {
Original file line number Diff line number Diff line change
@@ -86,7 +86,8 @@ public void encode(Operand operand) {
@Override public void ObjectClass(ObjectClass objectclass) {} // No data

@Override public void Regexp(Regexp regexp) {
encode(regexp.getRegexp());
// FIXME: This is wrong
encoder.encode(new String(regexp.getSource().bytes(), regexp.getSource().getEncoding().getCharset()));
encoder.encode(regexp.options.isEncodingNone());
encoder.encode(regexp.options.toEmbeddedOptions());
}
20 changes: 11 additions & 9 deletions core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
Original file line number Diff line number Diff line change
@@ -962,15 +962,6 @@ public static final ByteList newByteListFromRaw(Ruby runtime, String str, String
return new ByteList(str.getBytes(RubyEncoding.ISO), runtime.getEncodingService().getEncodingFromString(encoding), false);
}

public static RubyRegexp constructRubyRegexp(ThreadContext context, RubyString pattern, RegexpOptions options) {
return RubyRegexp.newRegexp(context.runtime, pattern.getByteList(), options);
}

// Used by JIT
public static RubyRegexp constructRubyRegexp(ThreadContext context, RubyString pattern, int options) {
return RubyRegexp.newRegexp(context.runtime, pattern.getByteList(), RegexpOptions.fromEmbeddedOptions(options));
}

// Used by JIT
public static RubyEncoding retrieveEncoding(ThreadContext context, String name) {
return context.runtime.getEncodingService().getEncoding(retrieveJCodingsEncoding(context, name));
@@ -1240,6 +1231,17 @@ public static RubyRegexp newDynamicRegexp(ThreadContext context, IRubyObject[] p
return re;
}

public static RubyRegexp newLiteralRegexp(ThreadContext context, ByteList source, RegexpOptions options) {
RubyRegexp re = RubyRegexp.newRegexp(context.runtime, source, options);
re.setLiteral();
return re;
}

@JIT
public static RubyRegexp newLiteralRegexp(ThreadContext context, ByteList source, int embeddedOptions) {
return newLiteralRegexp(context, source, RegexpOptions.fromEmbeddedOptions(embeddedOptions));
}

@JIT
public static RubyArray irSplat(ThreadContext context, IRubyObject maybeAry) {
return Helpers.splatValue19(maybeAry);
Original file line number Diff line number Diff line change
@@ -250,11 +250,11 @@ public void pushBlockBody(Handle handle, org.jruby.runtime.Signature signature,
/**
* Build and save a literal regular expression.
*
* Stack required: ThreadContext, RubyString.
* Stack required: none
*
* @param options options for the regexp
*/
public abstract void pushRegexp(int options);
public abstract void pushRegexp(ByteList source, int options);

/**
* Build a dynamic regexp.
99 changes: 62 additions & 37 deletions core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter6.java
Original file line number Diff line number Diff line change
@@ -6,6 +6,8 @@

import com.headius.invokebinder.Signature;
import java.math.BigInteger;
import java.util.concurrent.Callable;

import org.jcodings.Encoding;
import org.jruby.Ruby;
import org.jruby.RubyArray;
@@ -53,16 +55,26 @@ public IRBytecodeAdapter6(SkinnyMethodAdapter adapter, Signature signature, Clas
super(adapter, signature, classData);
}

public void pushFixnum(long l) {
loadRuntime();
adapter.ldc(l);
adapter.invokevirtual(p(Ruby.class), "newFixnum", sig(RubyFixnum.class, long.class));
public void pushFixnum(final long l) {
cacheValuePermanently(newFieldName("fixnum"), RubyFixnum.class, new Runnable() {
@Override
public void run() {
loadRuntime();
adapter.ldc(l);
adapter.invokevirtual(p(Ruby.class), "newFixnum", sig(RubyFixnum.class, long.class));
}
});
}

public void pushFloat(double d) {
loadRuntime();
adapter.ldc(d);
adapter.invokevirtual(p(Ruby.class), "newFloat", sig(RubyFloat.class, double.class));
public void pushFloat(final double d) {
cacheValuePermanently(newFieldName("float"), RubyFloat.class, new Runnable() {
@Override
public void run() {
loadRuntime();
adapter.ldc(d);
adapter.invokevirtual(p(Ruby.class), "newFloat", sig(RubyFloat.class, double.class));
}
});
}

public void pushString(ByteList bl) {
@@ -71,50 +83,63 @@ public void pushString(ByteList bl) {
adapter.invokestatic(p(RubyString.class), "newStringShared", sig(RubyString.class, Ruby.class, ByteList.class));
}

private String newFieldName(String baseName) {
return baseName + getClassData().callSiteCount.getAndIncrement();
}

/**
* Stack required: none
*
* @param bl ByteList for the String to push
*/
public void pushFrozenString(ByteList bl) {
// FIXME: too much bytecode
String cacheField = "frozenString" + getClassData().callSiteCount.getAndIncrement();
Label done = new Label();
adapter.getClassVisitor().visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, cacheField, ci(RubyString.class), null, null).visitEnd();
adapter.getstatic(getClassData().clsName, cacheField, ci(RubyString.class));
adapter.dup();
adapter.ifnonnull(done);
adapter.pop();
loadRuntime();
adapter.ldc(bl.toString());
adapter.ldc(bl.getEncoding().toString());
invokeIRHelper("newFrozenStringFromRaw", sig(RubyString.class, Ruby.class, String.class, String.class));
adapter.dup();
adapter.putstatic(getClassData().clsName, cacheField, ci(RubyString.class));
adapter.label(done);
public void pushFrozenString(final ByteList bl) {
cacheValuePermanently(newFieldName("frozenString"), RubyString.class, new Runnable() {
@Override
public void run() {
loadRuntime();
adapter.ldc(bl.toString());
adapter.ldc(bl.getEncoding().toString());
invokeIRHelper("newFrozenStringFromRaw", sig(RubyString.class, Ruby.class, String.class, String.class));
}
});
}

public void pushByteList(ByteList bl) {
// FIXME: too much bytecode
String cacheField = "byteList" + getClassData().callSiteCount.getAndIncrement();
public void pushByteList(final ByteList bl) {
cacheValuePermanently(newFieldName("byteList"), ByteList.class, new Runnable() {
@Override
public void run() {
loadRuntime();
adapter.ldc(bl.toString());
adapter.ldc(bl.getEncoding().toString());
invokeIRHelper("newByteListFromRaw", sig(ByteList.class, Ruby.class, String.class, String.class));
}
});
}

public void cacheValuePermanently(String cacheField, Class type, Runnable construction) {
// FIXME: too much bytecode...make it a separate method?
Label done = new Label();
adapter.getClassVisitor().visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, cacheField, ci(ByteList.class), null, null).visitEnd();
adapter.getstatic(getClassData().clsName, cacheField, ci(ByteList.class));
adapter.getClassVisitor().visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, cacheField, ci(type), null, null).visitEnd();
adapter.getstatic(getClassData().clsName, cacheField, ci(type));
adapter.dup();
adapter.ifnonnull(done);
adapter.pop();
loadRuntime();
adapter.ldc(bl.toString());
adapter.ldc(bl.getEncoding().toString());
invokeIRHelper("newByteListFromRaw", sig(ByteList.class, Ruby.class, String.class, String.class));
construction.run();
adapter.dup();
adapter.putstatic(getClassData().clsName, cacheField, ci(ByteList.class));
adapter.putstatic(getClassData().clsName, cacheField, ci(type));
adapter.label(done);
}

public void pushRegexp(int options) {
adapter.pushInt(options);
invokeIRHelper("constructRubyRegexp", sig(RubyRegexp.class, ThreadContext.class, RubyString.class, int.class));
public void pushRegexp(final ByteList source, final int options) {
cacheValuePermanently(newFieldName("regexp"), RubyRegexp.class, new Runnable() {
@Override
public void run() {
loadContext();
pushByteList(source);
adapter.pushInt(options);
invokeIRHelper("newLiteralRegexp", sig(RubyRegexp.class, ThreadContext.class, ByteList.class, int.class));
}
});
}

public void pushDRegexp(Runnable callback, RegexpOptions options, int arity) {
Original file line number Diff line number Diff line change
@@ -67,8 +67,10 @@ public void pushByteList(ByteList bl) {
adapter.invokedynamic("bytelist", sig(ByteList.class), Bootstrap.bytelist(), new String(bl.bytes(), RubyEncoding.ISO), bl.getEncoding().toString());
}

public void pushRegexp(int options) {
adapter.invokedynamic("regexp", sig(RubyRegexp.class, ThreadContext.class, RubyString.class), RegexpObjectSite.BOOTSTRAP, options);
public void pushRegexp(ByteList source, int options) {
loadContext();
pushByteList(source);
adapter.invokedynamic("regexp", sig(RubyRegexp.class, ThreadContext.class, ByteList.class), RegexpObjectSite.BOOTSTRAP, options);
}

public void pushDRegexp(Runnable callback, RegexpOptions options, int arity) {
Loading