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

Commits on Sep 5, 2017

  1. Copy the full SHA
    5e917ce View commit details
  2. Merge pull request #4777 from original-brownbear/smaller-bytecode-jav…

    …ainterface-impl
    
     Generate smaller bytecode when using Ruby type on implemented Java Interface + Benchmark
    headius authored Sep 5, 2017
    Copy the full SHA
    6e9854f View commit details
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package org.jruby.benchmark;

import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import org.jruby.Ruby;
import org.jruby.RubyFixnum;
import org.jruby.RubyInstanceConfig;
import org.jruby.runtime.builtin.IRubyObject;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OperationsPerInvocation;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.Blackhole;

@Warmup(iterations = 3, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Fork(1)
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
public class JavaInterfaceBenchmark {

private static final int INVOCATIONS = 200_000_000;

private static final Ruby RUBY = initRuby();

private static final RubyFixnum LEFT = RUBY.newFixnum(ThreadLocalRandom.current().nextInt());

private static final RubyFixnum RIGHT = RUBY.newFixnum(ThreadLocalRandom.current().nextInt());

private static final JavaInterfaceBenchmark.Summation JAVA_SUMMER =
new JavaInterfaceBenchmark.Summation() {
@Override
public IRubyObject sum(final RubyFixnum left, final RubyFixnum right) {
return left.op_plus(RUBY.getCurrentContext(), right);
}
};

public interface Summation {
IRubyObject sum(RubyFixnum left, RubyFixnum right);
}

@Benchmark
@OperationsPerInvocation(INVOCATIONS)
public void benchHalfRubyVersion(final Blackhole blackhole) {
blackhole.consume(
RUBY.executeScript(
"org.jruby.benchmark.JavaInterfaceBenchmark.doRun(RubySummation.new)"
,"benchHalfRubyVersion")
);
}

@Benchmark
@OperationsPerInvocation(INVOCATIONS)
public void benchJavaVersion(final Blackhole blackhole) {
blackhole.consume(doRun(JAVA_SUMMER));
}

public static IRubyObject doRun(final JavaInterfaceBenchmark.Summation summer) {
IRubyObject sum = null;
for (int i = 0; i < INVOCATIONS; ++i) {
sum = summer.sum(LEFT, RIGHT);
}
return sum;
}

private static Ruby initRuby() {
final RubyInstanceConfig config = new RubyInstanceConfig();
config.setCompileMode(RubyInstanceConfig.CompileMode.FORCE);
final Ruby ruby = Ruby.newInstance(config);
ruby.executeScript(
new StringBuilder()
.append("class RubySummation\n")
.append("\tinclude org.jruby.benchmark.JavaInterfaceBenchmark::Summation\n")
.append('\n')
.append("\tdef sum(a, b)\n")
.append("\t\ta + b\n")
.append("\tend\n")
.append("end")
.toString(), "initRuby"
);
return ruby;
}
}
Original file line number Diff line number Diff line change
@@ -48,12 +48,12 @@ private static void recordSimplification(Variable res, Operand val, Map<Operand,

// For all variables used by val, record a reverse mapping to let us track
// Read-After-Write scenarios when any of these variables are modified.
List<Variable> valVars = new ArrayList<Variable>();
List<Variable> valVars = new ArrayList<>();
val.addUsedVariables(valVars);
for (Variable v: valVars) {
List<Variable> x = simplificationMap.get(v);
if (x == null) {
x = new ArrayList<Variable>();
x = new ArrayList<>();
simplificationMap.put(v, x);
}
x.add(res);
26 changes: 18 additions & 8 deletions core/src/main/java/org/jruby/java/codegen/RealClassGenerator.java
Original file line number Diff line number Diff line change
@@ -38,7 +38,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.jruby.Ruby;
import org.jruby.RubyBasicObject;
import org.jruby.RubyClass;
@@ -47,21 +46,29 @@
import org.jruby.compiler.impl.SkinnyMethodAdapter;
import org.jruby.compiler.util.BasicObjectStubGenerator;
import org.jruby.internal.runtime.methods.DynamicMethod;
import org.jruby.internal.runtime.methods.UndefinedMethod;
import org.jruby.javasupport.JavaUtil;
import org.jruby.runtime.Block;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.callsite.CacheEntry;
import org.jruby.util.ClassDefiningClassLoader;
import org.jruby.util.ClassDefiningJRubyClassLoader;
import static org.jruby.util.CodegenUtils.*;

import org.jruby.util.Loader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.Type;
import static org.objectweb.asm.Opcodes.*;

import static org.jruby.util.CodegenUtils.ci;
import static org.jruby.util.CodegenUtils.getBoxType;
import static org.jruby.util.CodegenUtils.p;
import static org.jruby.util.CodegenUtils.params;
import static org.jruby.util.CodegenUtils.prettyParams;
import static org.jruby.util.CodegenUtils.sig;
import static org.objectweb.asm.Opcodes.ACC_FINAL;
import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.ACC_STATIC;
import static org.objectweb.asm.Opcodes.ACC_SUPER;
import static org.objectweb.asm.Opcodes.V1_6;

/**
* On fly .class generator (used for Ruby interface impls).
@@ -731,8 +738,8 @@ public static void coerceArgumentsToRuby(SkinnyMethodAdapter mv, Class[] paramTy
mv.dup();
mv.pushInt(i);
// convert to IRubyObject
mv.aload(rubyIndex);
if (paramTypes[i].isPrimitive()) {
mv.aload(rubyIndex);
if (paramType == byte.class || paramType == short.class || paramType == char.class || paramType == int.class) {
mv.iload(argIndex++);
mv.invokestatic(p(JavaUtil.class), "convertJavaToRuby", sig(IRubyObject.class, Ruby.class, int.class));
@@ -751,9 +758,12 @@ public static void coerceArgumentsToRuby(SkinnyMethodAdapter mv, Class[] paramTy
mv.iload(argIndex++);
mv.invokestatic(p(JavaUtil.class), "convertJavaToRuby", sig(IRubyObject.class, Ruby.class, boolean.class));
}
} else {
} else if (!IRubyObject.class.isAssignableFrom(paramType)) {
mv.aload(rubyIndex);
mv.aload(argIndex++);
mv.invokestatic(p(JavaUtil.class), "convertJavaToUsableRubyObject", sig(IRubyObject.class, Ruby.class, Object.class));
} else {
mv.aload(argIndex++);
}
mv.aastore();
}