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: a3a7b91456bb
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: bd7724688c07
Choose a head ref
  • 11 commits
  • 26 files changed
  • 2 contributors

Commits on Dec 28, 2015

  1. Use Truffle mode for RubyLanguage.

    headius authored and chrisseaton committed Dec 28, 2015
    Copy the full SHA
    d26c846 View commit details
  2. Fix multiplying through NaN as in MRI.

    Original fix in ruby/ruby@3bcb10a:
    
    calculate as rotation in complex plane if matrix calculation resulted in NaN.
    headius committed Dec 28, 2015
    Copy the full SHA
    ecf0aa7 View commit details
  3. Various literal to_proc'ed Symbol optimizations.

    * Use a dummy binding rather than creating new every time.
    * Cache the resulting proc at create site.
    
    The second optimization results in a given &:foo in code only
    creating a single Proc, ever, and caching it at that point in the
    code. This is based on the observation that symbol procs typically
    are used to iterate over homogeneous collections of objects, so
    caching the proc allows its cache to stay populated and local to
    the related code. This also eliminates the allocation of a Block,
    BlockBody, and RubyProc for each encounter, which improves perf
    also for heterogeneous collections with poor cacheability.
    
    Benchmark:
    
    ```ruby
    loop {
      puts Benchmark.measure {
        ary = [1,2,3,4]
        1_000_000.times {
          ary.each(&:object_id)
        }
      }
    }
    ```
    
    Before:
    
    ```
      1.270000   0.070000   1.340000 (  0.710043)
      0.640000   0.020000   0.660000 (  0.511692)
      0.470000   0.000000   0.470000 (  0.460667)
      0.490000   0.010000   0.500000 (  0.480732)
      0.470000   0.000000   0.470000 (  0.462888)
    ```
    
    Just the dummy binding optimization:
    
    ```
      1.210000   0.070000   1.280000 (  0.660924)
      0.540000   0.020000   0.560000 (  0.432614)
      0.430000   0.000000   0.430000 (  0.422502)
      0.430000   0.000000   0.430000 (  0.416549)
      0.410000   0.010000   0.420000 (  0.412461)
    ```
    
    And with proc caching:
    
    ```
      0.890000   0.060000   0.950000 (  0.456065)
      0.410000   0.020000   0.430000 (  0.279023)
      0.290000   0.000000   0.290000 (  0.282117)
      0.300000   0.010000   0.310000 (  0.288516)
      0.270000   0.000000   0.270000 (  0.270100)
    ```
    headius committed Dec 28, 2015
    1
    Copy the full SHA
    69662ab View commit details

Commits on Dec 30, 2015

  1. Copy the full SHA
    5941f37 View commit details
  2. Copy the full SHA
    813a222 View commit details
  3. Copy the full SHA
    5a3de79 View commit details
  4. Copy the full SHA
    8dc8ccc View commit details
  5. Copy the full SHA
    4ff8a48 View commit details
  6. [Truffle] Fix last super spec.

    eregon committed Dec 30, 2015
    Copy the full SHA
    33d388a View commit details
  7. Merge pull request #3571 from jruby/symbol_to_proc_cache

    Various literal to_proc'ed Symbol optimizations.
    headius committed Dec 30, 2015
    Copy the full SHA
    cca4a33 View commit details
  8. Copy the full SHA
    bd77246 View commit details
Showing with 296 additions and 105 deletions.
  1. +9 −4 core/src/main/java/org/jruby/RubyComplex.java
  2. +73 −65 core/src/main/java/org/jruby/RubySymbol.java
  3. +5 −1 core/src/main/java/org/jruby/ir/IRBuilder.java
  4. +1 −0 core/src/main/java/org/jruby/ir/IRVisitor.java
  5. +2 −1 core/src/main/java/org/jruby/ir/operands/OperandType.java
  6. +73 −0 core/src/main/java/org/jruby/ir/operands/SymbolProc.java
  7. +24 −0 core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
  8. +12 −1 core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter.java
  9. +13 −0 core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter6.java
  10. +5 −0 core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
  11. +13 −0 core/src/main/java/org/jruby/runtime/Binding.java
  12. +13 −0 core/src/main/java/org/jruby/util/Numeric.java
  13. +0 −1 spec/truffle/tags/language/encoding_tags.txt
  14. +0 −1 spec/truffle/tags/language/file_tags.txt
  15. +0 −5 spec/truffle/tags/language/predefined_tags.txt
  16. +0 −1 spec/truffle/tags/language/super_tags.txt
  17. +0 −9 spec/truffle/tags/language/variables_tags.txt
  18. +9 −4 tool/jruby_eclipse
  19. +0 −3 tool/jt.rb
  20. +4 −0 truffle/src/main/java/org/jruby/truffle/nodes/StringCachingGuards.java
  21. +10 −1 truffle/src/main/java/org/jruby/truffle/nodes/core/BasicObjectNodes.java
  22. +2 −1 truffle/src/main/java/org/jruby/truffle/nodes/core/KernelNodes.java
  23. +18 −3 truffle/src/main/java/org/jruby/truffle/nodes/supercall/GeneralSuperReCallNode.java
  24. +1 −1 truffle/src/main/java/org/jruby/truffle/nodes/supercall/ZSuperOutsideMethodNode.java
  25. +6 −1 truffle/src/main/java/org/jruby/truffle/runtime/core/CoreLibrary.java
  26. +3 −2 truffle/src/main/java/org/jruby/truffle/runtime/loader/FeatureLoader.java
13 changes: 9 additions & 4 deletions core/src/main/java/org/jruby/RubyComplex.java
Original file line number Diff line number Diff line change
@@ -72,6 +72,7 @@

import static org.jruby.runtime.Helpers.invokedynamic;
import static org.jruby.runtime.invokedynamic.MethodNames.HASH;
import static org.jruby.util.Numeric.safe_mul;

/**
* 1.9 complex.c as of revision: 20011
@@ -539,12 +540,16 @@ public IRubyObject op_sub(ThreadContext context, IRubyObject other) {
public IRubyObject op_mul(ThreadContext context, IRubyObject other) {
if (other instanceof RubyComplex) {
RubyComplex otherComplex = (RubyComplex)other;
boolean arzero = f_zero_p(context, real);
boolean aizero = f_zero_p(context, image);
boolean brzero = f_zero_p(context, otherComplex.real);
boolean bizero = f_zero_p(context, otherComplex.image);
IRubyObject realp = f_sub(context,
f_mul(context, real, otherComplex.real),
f_mul(context, image, otherComplex.image));
safe_mul(context, real, otherComplex.real, arzero, brzero),
safe_mul(context, image, otherComplex.image, aizero, bizero));
IRubyObject imagep = f_add(context,
f_mul(context, real, otherComplex.image),
f_mul(context, image, otherComplex.real));
safe_mul(context, real, otherComplex.image, arzero, bizero),
safe_mul(context, image, otherComplex.real, aizero, brzero));

return newComplex(context, getMetaClass(), realp, imagep);
} else if (other instanceof RubyNumeric && f_real_p(context, other).isTrue()) {
138 changes: 73 additions & 65 deletions core/src/main/java/org/jruby/RubySymbol.java
Original file line number Diff line number Diff line change
@@ -44,6 +44,7 @@
import org.jruby.compiler.Constantizable;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.ArgumentDescriptor;
import org.jruby.runtime.Binding;
import org.jruby.runtime.Block;
import org.jruby.runtime.BlockBody;
import org.jruby.runtime.CallSite;
@@ -462,73 +463,10 @@ public IRubyObject encoding(ThreadContext context) {

@JRubyMethod
public IRubyObject to_proc(ThreadContext context) {
StaticScope scope = context.runtime.getStaticScopeFactory().getDummyScope();
final CallSite site = new FunctionalCachingCallSite(symbol);
BlockBody body = new ContextAwareBlockBody(scope, Signature.OPTIONAL) {
private IRubyObject yieldInner(ThreadContext context, RubyArray array, Block blockArg) {
if (array.isEmpty()) {
throw context.runtime.newArgumentError("no receiver given");
}

IRubyObject self = array.shift(context);

return site.call(context, self, self, array.toJavaArray(), blockArg);
}

@Override
public IRubyObject yield(ThreadContext context, Block block, IRubyObject[] args, IRubyObject self, Block blockArg) {
RubyProc.prepareArgs(context, block.type, blockArg.getBody(), args);
return yieldInner(context, context.runtime.newArrayNoCopyLight(args), blockArg);
}

@Override
public IRubyObject yield(ThreadContext context, Block block, IRubyObject value, Block blockArg) {
return yieldInner(context, ArgsUtil.convertToRubyArray(context.runtime, value, false), blockArg);
}

@Override
protected IRubyObject doYield(ThreadContext context, Block block, IRubyObject value) {
return yieldInner(context, ArgsUtil.convertToRubyArray(context.runtime, value, false), Block.NULL_BLOCK);
}

@Override
protected IRubyObject doYield(ThreadContext context, Block block, IRubyObject[] args, IRubyObject self) {
return yieldInner(context, context.runtime.newArrayNoCopyLight(args), Block.NULL_BLOCK);
}

@Override
public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0) {
return site.call(context, arg0, arg0);
}

@Override
public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1) {
return site.call(context, arg0, arg0, arg1);
}

@Override
public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
return site.call(context, arg0, arg0, arg1, arg2);
}

@Override
public String getFile() {
return symbol;
}

@Override
public int getLine() {
return -1;
}

@Override
public ArgumentDescriptor[] getArgumentDescriptors() {
return ArgumentDescriptor.ANON_REST;
}
};
BlockBody body = new SymbolProcBody(context.runtime, symbol);

return RubyProc.newProc(context.runtime,
new Block(body, context.currentBinding()),
new Block(body, Binding.DUMMY),
Block.Type.PROC);
}

@@ -1071,4 +1009,74 @@ public static String objectToSymbolString(IRubyObject object) {
return object.convertToString().getByteList().toString();
}
}

private static class SymbolProcBody extends ContextAwareBlockBody {
private final CallSite site;

public SymbolProcBody(Ruby runtime, String symbol) {
super(runtime.getStaticScopeFactory().getDummyScope(), Signature.OPTIONAL);
this.site = new FunctionalCachingCallSite(symbol);
}

private IRubyObject yieldInner(ThreadContext context, RubyArray array, Block blockArg) {
if (array.isEmpty()) {
throw context.runtime.newArgumentError("no receiver given");
}

IRubyObject self = array.shift(context);

return site.call(context, self, self, array.toJavaArray(), blockArg);
}

@Override
public IRubyObject yield(ThreadContext context, Block block, IRubyObject[] args, IRubyObject self, Block blockArg) {
RubyProc.prepareArgs(context, block.type, blockArg.getBody(), args);
return yieldInner(context, context.runtime.newArrayNoCopyLight(args), blockArg);
}

@Override
public IRubyObject yield(ThreadContext context, Block block, IRubyObject value, Block blockArg) {
return yieldInner(context, ArgsUtil.convertToRubyArray(context.runtime, value, false), blockArg);
}

@Override
protected IRubyObject doYield(ThreadContext context, Block block, IRubyObject value) {
return yieldInner(context, ArgsUtil.convertToRubyArray(context.runtime, value, false), Block.NULL_BLOCK);
}

@Override
protected IRubyObject doYield(ThreadContext context, Block block, IRubyObject[] args, IRubyObject self) {
return yieldInner(context, context.runtime.newArrayNoCopyLight(args), Block.NULL_BLOCK);
}

@Override
public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0) {
return site.call(context, arg0, arg0);
}

@Override
public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1) {
return site.call(context, arg0, arg0, arg1);
}

@Override
public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
return site.call(context, arg0, arg0, arg1, arg2);
}

@Override
public String getFile() {
return site.methodName;
}

@Override
public int getLine() {
return -1;
}

@Override
public ArgumentDescriptor[] getArgumentDescriptors() {
return ArgumentDescriptor.ANON_REST;
}
}
}
6 changes: 5 additions & 1 deletion core/src/main/java/org/jruby/ir/IRBuilder.java
Original file line number Diff line number Diff line change
@@ -2371,7 +2371,11 @@ private Operand setupCallClosure(Node node) {
case ITERNODE:
return build(node);
case BLOCKPASSNODE:
return build(((BlockPassNode)node).getBodyNode());
Node bodyNode = ((BlockPassNode)node).getBodyNode();
if (bodyNode instanceof SymbolNode) {
return new SymbolProc(((SymbolNode)bodyNode).getName(), ((SymbolNode)bodyNode).getEncoding());
}
return build(bodyNode);
default:
throw new NotCompilableException("ERROR: Encountered a method with a non-block, non-blockpass iter node at: " + node);
}
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
@@ -188,6 +188,7 @@ private void error(Object object) {
public void StringLiteral(StringLiteral stringliteral) { error(stringliteral); }
public void SValue(SValue svalue) { error(svalue); }
public void Symbol(Symbol symbol) { error(symbol); }
public void SymbolProc(SymbolProc symbolproc) { error(symbolproc); }
public void TemporaryVariable(TemporaryVariable temporaryvariable) { error(temporaryvariable); }
public void TemporaryLocalVariable(TemporaryLocalVariable temporarylocalvariable) { error(temporarylocalvariable); }
public void TemporaryFloatVariable(TemporaryFloatVariable temporaryfloatvariable) { error(temporaryfloatvariable); }
3 changes: 2 additions & 1 deletion core/src/main/java/org/jruby/ir/operands/OperandType.java
Original file line number Diff line number Diff line change
@@ -43,7 +43,8 @@ public enum OperandType {
WRAPPED_IR_CLOSURE((byte) 'w'),
FROZEN_STRING((byte) 'z'),
NULL_BLOCK((byte) 'o'),
FILENAME((byte) 'm')
FILENAME((byte) 'm'),
SYMBOL_PROC((byte) 'P')
;

private final byte coded;
73 changes: 73 additions & 0 deletions core/src/main/java/org/jruby/ir/operands/SymbolProc.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package org.jruby.ir.operands;

import org.jcodings.Encoding;
import org.jruby.ir.IRVisitor;
import org.jruby.ir.persistence.IRReaderDecoder;
import org.jruby.ir.persistence.IRWriterEncoder;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.runtime.ThreadContext;

/**
* A literal representing proc'ified symbols, as in &:foo.
*
* Used to cache a unique and constant proc at the use site to reduce allocation and improve caching.
*/
public class SymbolProc extends ImmutableLiteral {
private final String name;
private final Encoding encoding;

public SymbolProc(String name, Encoding encoding) {
super();
this.name = name;
this.encoding = encoding;
}

@Override
public OperandType getOperandType() {
return OperandType.SYMBOL_PROC;
}

@Override
public Object createCacheObject(ThreadContext context) {
return IRRuntimeHelpers.newSymbolProc(context, name, encoding);
}

@Override
public int hashCode() {
return 47 * 7 + (int) (this.name.hashCode() ^ (this.encoding.hashCode() >>> 32));
}

@Override
public boolean equals(Object other) {
return other instanceof SymbolProc && name.equals(((SymbolProc) other).name) && encoding.equals(((SymbolProc) other).encoding);
}

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

public String getName() {
return name;
}

public Encoding getEncoding() {
return encoding;
}

@Override
public void encode(IRWriterEncoder e) {
super.encode(e);
e.encode(name);
e.encode(encoding);
}

public static SymbolProc decode(IRReaderDecoder d) {
return new SymbolProc(d.decodeString(), d.decodeEncoding());
}

@Override
public String toString() {
return "SymbolProc:" + name;
}
}
24 changes: 24 additions & 0 deletions core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
Original file line number Diff line number Diff line change
@@ -1698,4 +1698,28 @@ public static IRubyObject useBindingSelf(Binding binding) {

return self;
}

/**
* Create a new Symbol.to_proc for the given symbol name and encoding.
*
* @param context
* @param symbol
* @return
*/
@Interp
public static RubyProc newSymbolProc(ThreadContext context, String symbol, Encoding encoding) {
return (RubyProc)context.runtime.newSymbol(symbol, encoding).to_proc(context);
}

/**
* Create a new Symbol.to_proc for the given symbol name and encoding.
*
* @param context
* @param symbol
* @return
*/
@JIT
public static RubyProc newSymbolProc(ThreadContext context, String symbol, String encoding) {
return newSymbolProc(context, symbol, retrieveJCodingsEncoding(context, encoding));
}
}
13 changes: 12 additions & 1 deletion core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter.java
Original file line number Diff line number Diff line change
@@ -351,14 +351,25 @@ public void pushBlockBody(Handle handle, org.jruby.runtime.Signature signature,
* Stack required: none
*
* @param sym the symbol's string identifier
* @param encoding the symbol's encoding
*/
public abstract void pushSymbol(String sym, Encoding encoding);

/**
* Push the JRuby runtime on the stack.
* Push a Symbol.to_proc on the stack.
*
* Stack required: none
*
* @param name the symbol's string identifier
* @param encoding the symbol's encoding
*/
public abstract void pushSymbolProc(String name, Encoding encoding);

/**
* Push the JRuby runtime on the stack.
*
* Stack required: none
*/
public abstract void loadRuntime();

/**
13 changes: 13 additions & 0 deletions core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter6.java
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@
import org.jruby.RubyFloat;
import org.jruby.RubyHash;
import org.jruby.RubyModule;
import org.jruby.RubyProc;
import org.jruby.RubyRegexp;
import org.jruby.RubyString;
import org.jruby.RubySymbol;
@@ -261,6 +262,18 @@ public void run() {
});
}

public void pushSymbolProc(final String name, final Encoding encoding) {
cacheValuePermanently("symbolProc", RubyProc.class, null, new Runnable() {
@Override
public void run() {
loadContext();
adapter.ldc(name);
adapter.ldc(encoding.toString());
invokeIRHelper("newSymbolProc", sig(RubyProc.class, ThreadContext.class, String.class, String.class));
}
});
}

public void loadRuntime() {
loadContext();
adapter.getfield(p(ThreadContext.class), "runtime", ci(Ruby.class));
5 changes: 5 additions & 0 deletions core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
Original file line number Diff line number Diff line change
@@ -2306,6 +2306,11 @@ public void Symbol(Symbol symbol) {
jvmMethod().pushSymbol(symbol.getName(), symbol.getEncoding());
}

@Override
public void SymbolProc(SymbolProc symbolproc) {
jvmMethod().pushSymbolProc(symbolproc.getName(), symbolproc.getEncoding());
}

@Override
public void TemporaryVariable(TemporaryVariable temporaryvariable) {
jvmLoadLocal(temporaryvariable);
Loading