Skip to content

Commit

Permalink
Showing 57 changed files with 1,029 additions and 841 deletions.
2 changes: 1 addition & 1 deletion .mvn/extensions.xml
Original file line number Diff line number Diff line change
@@ -3,6 +3,6 @@
<extension>
<groupId>io.takari.polyglot</groupId>
<artifactId>polyglot-ruby</artifactId>
<version>0.1.15</version>
<version>0.1.11</version>
</extension>
</extensions>
2 changes: 1 addition & 1 deletion core/pom.rb
Original file line number Diff line number Diff line change
@@ -46,7 +46,7 @@
jar 'com.github.jnr:jnr-x86asm:1.0.2', :exclusions => ['com.github.jnr:jnr-ffi']
jar 'com.github.jnr:jnr-unixsocket:0.10', :exclusions => ['com.github.jnr:jnr-ffi']
jar 'com.github.jnr:jnr-posix:3.0.28-SNAPSHOT', :exclusions => ['com.github.jnr:jnr-ffi']
jar 'com.github.jnr:jnr-constants:0.9.0', :exclusions => ['com.github.jnr:jnr-ffi']
jar 'com.github.jnr:jnr-constants:0.9.1-SNAPSHOT', :exclusions => ['com.github.jnr:jnr-ffi']
jar 'com.github.jnr:jnr-ffi:2.0.7'
jar 'com.github.jnr:jffi:${jffi.version}'
jar 'com.github.jnr:jffi:${jffi.version}:native'
2 changes: 1 addition & 1 deletion core/pom.xml
Original file line number Diff line number Diff line change
@@ -147,7 +147,7 @@ DO NOT MODIFIY - GENERATED CODE
<dependency>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-constants</artifactId>
<version>0.9.0</version>
<version>0.9.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<artifactId>jnr-ffi</artifactId>
27 changes: 27 additions & 0 deletions core/src/main/java/org/jruby/Ruby.java
Original file line number Diff line number Diff line change
@@ -58,6 +58,7 @@
import org.jruby.javasupport.JavaSupportImpl;
import org.jruby.lexer.yacc.ISourcePosition;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.invokedynamic.InvokeDynamicSupport;
import org.jruby.util.ClassDefiningClassLoader;
import org.objectweb.asm.util.TraceClassVisitor;

@@ -164,6 +165,7 @@
import java.io.InputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.lang.invoke.MethodHandle;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@@ -197,6 +199,9 @@
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Pattern;

import static java.lang.invoke.MethodHandles.explicitCastArguments;
import static java.lang.invoke.MethodHandles.insertArguments;
import static java.lang.invoke.MethodType.methodType;
import static org.jruby.internal.runtime.GlobalVariable.Scope.GLOBAL;

/**
@@ -4880,6 +4885,23 @@ public DynamicMethod getBaseNewMethod() {
return baseNewMethod;
}

/**
* Get the "nullToNil" method handle filter for this runtime.
*
* @return a method handle suitable for filtering a single IRubyObject value from null to nil
*/
public MethodHandle getNullToNilHandle() {
MethodHandle nullToNil = this.nullToNil;

if (nullToNil != null) return nullToNil;

nullToNil = InvokeDynamicSupport.findStatic(Helpers.class, "nullToNil", methodType(IRubyObject.class, IRubyObject.class, IRubyObject.class));
nullToNil = insertArguments(nullToNil, 1, nilObject);
nullToNil = explicitCastArguments(nullToNil, methodType(IRubyObject.class, Object.class));

return this.nullToNil = nullToNil;
}

@Deprecated
public int getSafeLevel() {
return 0;
@@ -5238,4 +5260,9 @@ public void addToObjectSpace(boolean useObjectSpace, IRubyObject object) {
* The built-in Class#new method, so we can bind more directly to allocate and initialize.
*/
private DynamicMethod baseNewMethod;

/**
* The nullToNil filter for this runtime.
*/
private MethodHandle nullToNil;
}
4 changes: 4 additions & 0 deletions core/src/main/java/org/jruby/RubyFile.java
Original file line number Diff line number Diff line change
@@ -199,6 +199,10 @@ public static RubyClass createFileClass(Ruby runtime) {
// /* Try to minimize cache effects of the I/O to and from this file. */
// constants.setConstant("DIRECT", runtime.newFixnum(OpenFlags.O_DIRECT.intValue()));
// #endif
if (OpenFlags.O_TMPFILE.defined()) {
/* Create an unnamed temporary file */
constants.setConstant("TMPFILE", runtime.newFixnum(OpenFlags.O_TMPFILE.intValue()));
}

// case handling, escaping, path and dot matching
constants.setConstant("FNM_NOESCAPE", runtime.newFixnum(FNM_NOESCAPE));
27 changes: 25 additions & 2 deletions core/src/main/java/org/jruby/RubyIO.java
Original file line number Diff line number Diff line change
@@ -3142,6 +3142,7 @@ private IRubyObject eachCodePointCommon(ThreadContext context, Block block, Stri
fptr.READ_CHECK(context);
if (fptr.needsReadConversion()) {
fptr.SET_BINARY_MODE();
r = 1; /* no invalid char yet */
for (;;) {
fptr.makeReadConversion(context);
for (;;) {
@@ -3158,12 +3159,16 @@ private IRubyObject eachCodePointCommon(ThreadContext context, Block block, Stri
}
if (fptr.moreChar(context) == OpenFile.MORE_CHAR_FINISHED) {
fptr.clearReadConversion();
/* ignore an incomplete character before EOF */
if (!StringSupport.MBCLEN_CHARFOUND_P(r)) {
enc = fptr.encs.enc;
throw runtime.newArgumentError("invalid byte sequence in " + enc.toString());
}
return this;
}
}
if (StringSupport.MBCLEN_INVALID_P(r)) {
throw runtime.newArgumentError("invalid byte sequence in " + fptr.encs.enc.toString());
enc = fptr.encs.enc;
throw runtime.newArgumentError("invalid byte sequence in " + enc.toString());
}
n = StringSupport.MBCLEN_CHARFOUND_LEN(r);
if (fptr.encs.enc != null) {
@@ -3189,6 +3194,24 @@ private IRubyObject eachCodePointCommon(ThreadContext context, Block block, Stri
block.yield(context, runtime.newFixnum(c & 0xFFFFFFFF));
} else if (StringSupport.MBCLEN_INVALID_P(r)) {
throw runtime.newArgumentError("invalid byte sequence in " + enc.toString());
} else if (StringSupport.MBCLEN_NEEDMORE_P(r)) {
byte[] cbuf = new byte[8];
int p = 0;
int more = StringSupport.MBCLEN_NEEDMORE_LEN(r);
if (more > cbuf.length) throw runtime.newArgumentError("invalid byte sequence in " + enc.toString());
more += n = fptr.rbuf.len;
if (more > cbuf.length) throw runtime.newArgumentError("invalid byte sequence in " + enc.toString());
while ((n = (int)fptr.readBufferedData(cbuf, p, more)) > 0) {
p += n;
if ((more -= n) <= 0) break;

if (fptr.fillbuf(context) < 0) throw runtime.newArgumentError("invalid byte sequence in " + enc.toString());
if ((n = fptr.rbuf.len) > more) n = more;
}
r = enc.length(cbuf, 0, p);
if (!StringSupport.MBCLEN_CHARFOUND_P(r)) throw runtime.newArgumentError("invalid byte sequence in " + enc.toString());
c = enc.mbcToCode(cbuf, 0, p);
block.yield(context, runtime.newFixnum(c));
} else {
continue;
}
6 changes: 1 addition & 5 deletions core/src/main/java/org/jruby/ext/io/wait/IOWaitLibrary.java
Original file line number Diff line number Diff line change
@@ -120,12 +120,8 @@ public static IRubyObject wait_readable(ThreadContext context, IRubyObject _io,
}

if (fptr.readPending() != 0) return runtime.getTrue();
// TODO: better effort to get available bytes from our channel
// if (!FIONREAD_POSSIBLE_P(fptr->fd)) return Qfalse;
boolean ready = fptr.ready(runtime, context.getThread(), SelectionKey.OP_READ, tv);
boolean ready = fptr.ready(runtime, context.getThread(), SelectionKey.OP_READ | SelectionKey.OP_ACCEPT, tv);
fptr.checkClosed();
// if (ioctl(fptr->fd, FIONREAD, &n)) rb_sys_fail(0);
// if (n > 0) return io;
if (ready) return io;
return context.nil;
}
15 changes: 14 additions & 1 deletion core/src/main/java/org/jruby/ir/IRBuilder.java
Original file line number Diff line number Diff line change
@@ -1023,13 +1023,26 @@ public Operand buildCall(CallNode callNode) {
Operand receiver = buildWithOrder(receiverNode, callNode.containsVariableAssignment());
Variable callResult = createTemporaryVariable();

ArrayNode argsAry;
if (
callNode.getName().equals("[]") &&
callNode.getArgsNode() instanceof ArrayNode &&
(argsAry = (ArrayNode) callNode.getArgsNode()).size() == 1 &&
argsAry.get(0) instanceof StrNode &&
!scope.maybeUsingRefinements()) {
StrNode keyNode = (StrNode) argsAry.get(0);
addInstr(ArrayDerefInstr.create(callResult, receiver, new FrozenString(keyNode.getValue(), keyNode.getCodeRange(), keyNode.getPosition().getFile(), keyNode.getLine())));
return callResult;
}

Operand[] args = setupCallArgs(callArgsNode);

Label lazyLabel = getNewLabel();
Label endLabel = getNewLabel();
if (callNode.isLazy()) {
addInstr(new BNilInstr(lazyLabel, receiver));
}

Operand[] args = setupCallArgs(callArgsNode);
Operand block = setupCallClosure(callNode.getIterNode());

CallInstr callInstr = CallInstr.create(scope, callResult, callNode.getName(), receiver, args, block);
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/ir/IRVisitor.java
Original file line number Diff line number Diff line change
@@ -32,6 +32,7 @@ private void error(Object object) {
public void AliasInstr(AliasInstr aliasinstr) { error(aliasinstr); }
public void ArgScopeDepthInstr(ArgScopeDepthInstr instr) { error(instr); }
public void AttrAssignInstr(AttrAssignInstr attrassigninstr) { error(attrassigninstr); }
public void ArrayDerefInstr(ArrayDerefInstr arrayderefinstr) { error(arrayderefinstr); }
public void BacktickInstr(BacktickInstr instr) { error(instr); }
public void BEQInstr(BEQInstr beqinstr) { error(beqinstr); }
public void BFalseInstr(BFalseInstr bfalseinstr) { error(bfalseinstr); }
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/ir/Operation.java
Original file line number Diff line number Diff line change
@@ -65,6 +65,7 @@ public enum Operation {
CALL(OpFlags.f_has_side_effect | OpFlags.f_is_call | OpFlags.f_can_raise_exception),
NORESULT_CALL(OpFlags.f_has_side_effect | OpFlags.f_is_call | OpFlags.f_can_raise_exception),
ATTR_ASSIGN(OpFlags.f_is_call | OpFlags.f_has_side_effect | OpFlags.f_can_raise_exception),
ARRAY_DEREF(OpFlags.f_is_call | OpFlags.f_has_side_effect | OpFlags.f_can_raise_exception),
CLASS_SUPER(OpFlags.f_has_side_effect | OpFlags.f_is_call | OpFlags.f_can_raise_exception),
INSTANCE_SUPER(OpFlags.f_has_side_effect | OpFlags.f_is_call | OpFlags.f_can_raise_exception),
UNRESOLVED_SUPER(OpFlags.f_has_side_effect | OpFlags.f_is_call | OpFlags.f_can_raise_exception),
85 changes: 85 additions & 0 deletions core/src/main/java/org/jruby/ir/instructions/ArrayDerefInstr.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package org.jruby.ir.instructions;

import org.jruby.RubyInstanceConfig;
import org.jruby.RubyString;
import org.jruby.ir.IRScope;
import org.jruby.ir.IRVisitor;
import org.jruby.ir.Operation;
import org.jruby.ir.instructions.specialized.OneOperandArgNoBlockCallInstr;
import org.jruby.ir.operands.FrozenString;
import org.jruby.ir.operands.Operand;
import org.jruby.ir.operands.Variable;
import org.jruby.ir.persistence.IRReaderDecoder;
import org.jruby.ir.persistence.IRWriterEncoder;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.ir.transformations.inlining.CloneInfo;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.CallType;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

import static org.jruby.ir.IRFlags.REQUIRES_FRAME;

/**
* Instruction representing Ruby code of the form: "a['str']"
* which is equivalent to: a.[]('str'). Because a Hash receiver
* would immediately freeze the string, we can freeze and dedup
* the string ahead of time and call [] directly.
*/
public class ArrayDerefInstr extends OneOperandArgNoBlockCallInstr {
private final FrozenString key;

public static ArrayDerefInstr create(Variable result, Operand obj, FrozenString arg0) {
return new ArrayDerefInstr(result, obj, arg0);
}

public ArrayDerefInstr(Variable result, Operand obj, FrozenString arg0) {
super(Operation.ARRAY_DEREF, CallType.FUNCTIONAL, result, "[]", obj, new Operand[] {arg0}, false);

key = arg0;
}

@Override
public boolean computeScopeFlags(IRScope scope) {
// CON: No native [] impls require backref/lastline for a literal String arg,
// so we don't have to deopt frame here.
super.computeScopeFlags(scope);
return true;
}

@Override
public Instr clone(CloneInfo ii) {
return new ArrayDerefInstr((Variable) getResult().cloneForInlining(ii), getReceiver().cloneForInlining(ii), key);
}

@Override
public void encode(IRWriterEncoder e) {
if (RubyInstanceConfig.IR_WRITING_DEBUG) System.out.println("Instr(" + getOperation() + "): " + this);
e.encode(getOperation());
e.encode(getResult());
e.encode(getReceiver());
e.encode(getArg1());
}

public static ArrayDerefInstr decode(IRReaderDecoder d) {
return create(d.decodeVariable(), d.decodeOperand(), (FrozenString) d.decodeOperand());
}

@Override
public Object interpret(ThreadContext context, StaticScope currScope, DynamicScope dynamicScope, IRubyObject self, Object[] temp) {
IRubyObject object = (IRubyObject) getReceiver().retrieve(context, self, currScope, dynamicScope, temp);
RubyString keyStr = (RubyString) key.retrieve(context, self, currScope, dynamicScope, temp);

return IRRuntimeHelpers.callOptimizedAref(context, self, object, keyStr, getCallSite());
}

@Override
public void visit(IRVisitor visitor) {
visitor.ArrayDerefInstr(this);
}

public FrozenString getKey() {
return key;
}
}
Original file line number Diff line number Diff line change
@@ -16,7 +16,12 @@
public class OneOperandArgNoBlockCallInstr extends CallInstr {
public OneOperandArgNoBlockCallInstr(CallType callType, Variable result, String name, Operand receiver,
Operand[] args, boolean isPotentiallyRefined) {
super(Operation.CALL_1O, callType, result, name, receiver, args, null, isPotentiallyRefined);
this(Operation.CALL_1O, callType, result, name, receiver, args, isPotentiallyRefined);
}

public OneOperandArgNoBlockCallInstr(Operation op, CallType callType, Variable result, String name, Operand receiver,
Operand[] args, boolean isPotentiallyRefined) {
super(op, callType, result, name, receiver, args, null, isPotentiallyRefined);
}

@Override
11 changes: 11 additions & 0 deletions core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
Original file line number Diff line number Diff line change
@@ -1797,4 +1797,15 @@ public static RubyString freezeLiteralString(ThreadContext context, RubyString s

return string;
}

@JIT
public static IRubyObject callOptimizedAref(ThreadContext context, IRubyObject caller, IRubyObject target, RubyString keyStr, CallSite site) {
// FIXME: optimized builtin check for Hash#[]
if (target instanceof RubyHash) {
// call directly with cached frozen string
return ((RubyHash) target).op_aref(context, keyStr);
}

return site.call(context, caller, target, keyStr.strDup(context.runtime));
}
}
Loading

0 comments on commit 27087be

Please sign in to comment.