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: 58edb3b9c8a9
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 157bd6ae7bb8
Choose a head ref
  • 2 commits
  • 18 files changed
  • 1 contributor

Commits on Jun 1, 2016

  1. [Truffle] Unify ToJavaStringNode and NameToJavaStringNode.

    * And abstract dynamic ivar lookup in separate nodes.
    eregon committed Jun 1, 2016
    Copy the full SHA
    310b71c View commit details
  2. [Truffle] Optimize fiber-locals by using instance_variable_{gs}et on …

    …an object.
    
    * 5-10x faster in compiled code and 2-4x faster in interpreter.
    * Safety will be automatic with the new object model.
    * Actually per-Fiber, not per-Thread.
    eregon committed Jun 1, 2016
    2
    Copy the full SHA
    157bd6a View commit details
Showing with 307 additions and 246 deletions.
  1. +34 −0 truffle/src/main/java/org/jruby/truffle/core/ObjectNodes.java
  2. +49 −21 truffle/src/main/java/org/jruby/truffle/core/cast/NameToJavaStringNode.java
  3. +3 −0 truffle/src/main/java/org/jruby/truffle/core/fiber/FiberLayout.java
  4. +8 −5 truffle/src/main/java/org/jruby/truffle/core/fiber/FiberNodes.java
  5. +23 −86 truffle/src/main/java/org/jruby/truffle/core/kernel/KernelNodes.java
  6. +22 −32 truffle/src/main/java/org/jruby/truffle/core/module/ModuleNodes.java
  7. +10 −0 truffle/src/main/java/org/jruby/truffle/core/thread/ThreadNodes.java
  8. +1 −1 truffle/src/main/java/org/jruby/truffle/interop/CExtNodes.java
  9. +3 −2 truffle/src/main/java/org/jruby/truffle/interop/ForeignReadStringCachingHelperNode.java
  10. +3 −3 truffle/src/main/java/org/jruby/truffle/interop/ForeignWriteStringCachingHelperNode.java
  11. +6 −5 truffle/src/main/java/org/jruby/truffle/interop/InteropNodes.java
  12. +3 −2 truffle/src/main/java/org/jruby/truffle/interop/RubyToForeignNode.java
  13. +0 −77 truffle/src/main/java/org/jruby/truffle/interop/ToJavaStringNode.java
  14. +4 −5 truffle/src/main/java/org/jruby/truffle/language/dispatch/UncachedDispatchNode.java
  15. +3 −0 truffle/src/main/java/org/jruby/truffle/language/objects/ObjectGraph.java
  16. +57 −0 truffle/src/main/java/org/jruby/truffle/language/objects/ObjectIVarGetNode.java
  17. +59 −0 truffle/src/main/java/org/jruby/truffle/language/objects/ObjectIVarSetNode.java
  18. +19 −7 truffle/src/main/ruby/core/thread.rb
34 changes: 34 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/core/ObjectNodes.java
Original file line number Diff line number Diff line change
@@ -23,6 +23,10 @@
import org.jruby.truffle.language.objects.IsTaintedNode;
import org.jruby.truffle.language.objects.IsTaintedNodeGen;
import org.jruby.truffle.language.objects.ObjectIDOperations;
import org.jruby.truffle.language.objects.ObjectIVarGetNode;
import org.jruby.truffle.language.objects.ObjectIVarGetNodeGen;
import org.jruby.truffle.language.objects.ObjectIVarSetNode;
import org.jruby.truffle.language.objects.ObjectIVarSetNodeGen;
import org.jruby.truffle.language.objects.ReadObjectFieldNode;
import org.jruby.truffle.language.objects.ReadObjectFieldNodeGen;
import org.jruby.truffle.language.objects.TaintNode;
@@ -138,4 +142,34 @@ public Object objectInfect(Object host, Object source) {

}

@Primitive(name = "object_ivar_get")
public abstract static class ObjectIVarGetPrimitiveNode extends PrimitiveArrayArgumentsNode {

@Specialization
public Object ivarGet(DynamicObject object, DynamicObject name,
@Cached("createObjectIVarGetNode()") ObjectIVarGetNode iVarGetNode) {
return iVarGetNode.executeIVarGet(object, Layouts.SYMBOL.getString(name));
}

protected ObjectIVarGetNode createObjectIVarGetNode() {
return ObjectIVarGetNodeGen.create(false, null, null);
}

}

@Primitive(name = "object_ivar_set")
public abstract static class ObjectIVarSetPrimitiveNode extends PrimitiveArrayArgumentsNode {

@Specialization
public Object ivarGet(DynamicObject object, DynamicObject name, Object value,
@Cached("createObjectIVarSetNode()") ObjectIVarSetNode iVarSetNode) {
return iVarSetNode.executeIVarSet(object, Layouts.SYMBOL.getString(name), value);
}

protected ObjectIVarSetNode createObjectIVarSetNode() {
return ObjectIVarSetNodeGen.create(false, null, null, null);
}

}

}
Original file line number Diff line number Diff line change
@@ -10,55 +10,75 @@

package org.jruby.truffle.core.cast;

import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.ImportStatic;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.profiles.BranchProfile;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.rope.Rope;
import org.jruby.truffle.core.string.StringCachingGuards;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.RubyGuards;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.control.RaiseException;
import org.jruby.truffle.language.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.language.dispatch.DispatchHeadNodeFactory;

/**
* Take a Symbol or some object accepting #to_str
* and convert it to a Java String.
*/
@NodeChild(value = "child", type = RubyNode.class)
@ImportStatic(StringCachingGuards.class)
@NodeChild(value = "value", type = RubyNode.class)
public abstract class NameToJavaStringNode extends RubyNode {

@Child private CallDispatchHeadNode toStr;
public static NameToJavaStringNode create() {
return NameToJavaStringNodeGen.create(null);
}

private final BranchProfile errorProfile = BranchProfile.create();
public abstract String executeToJavaString(VirtualFrame frame, Object name);

public NameToJavaStringNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
toStr = DispatchHeadNodeFactory.createMethodCall(context);
@Specialization(guards = { "isRubyString(value)", "ropesEqual(value, cachedRope)" }, limit = "getLimit()")
String stringCached(DynamicObject value,
@Cached("privatizeRope(value)") Rope cachedRope,
@Cached("value.toString()") String convertedString) {
return convertedString;
}

public abstract String executeToJavaString(VirtualFrame frame, Object name);
@Specialization(guards = "isRubyString(value)", contains = "stringCached")
public String stringUncached(DynamicObject value) {
return StringOperations.getString(getContext(), value);
}

@Specialization
public String passThroughJavaString(String string) {
return string;
@Specialization(guards = { "symbol == cachedSymbol", "isRubySymbol(cachedSymbol)" }, limit = "getLimit()")
public String symbolCached(DynamicObject symbol,
@Cached("symbol") DynamicObject cachedSymbol,
@Cached("symbolToString(symbol)") String convertedString) {
return convertedString;
}

@Specialization(guards = "isRubySymbol(symbol)")
public String coerceRubySymbol(DynamicObject symbol) {
return Layouts.SYMBOL.getString(symbol);
@Specialization(guards = "isRubySymbol(symbol)", contains = "symbolCached")
public String symbolUncached(DynamicObject symbol) {
return symbolToString(symbol);
}

@Specialization(guards = "string == cachedString", limit = "getLimit()")
public String javaStringCached(String string,
@Cached("string") String cachedString) {
return cachedString;
}

@Specialization(guards = "isRubyString(string)")
public String coerceRubyString(DynamicObject string) {
return string.toString();
@Specialization(contains = "javaStringCached")
public String javaStringUncached(String value) {
return value;
}

@Specialization(guards = { "!isString(object)", "!isRubySymbol(object)", "!isRubyString(object)" })
public String coerceObject(VirtualFrame frame, Object object) {
public String coerceObjectToStr(VirtualFrame frame, Object object,
@Cached("create()") BranchProfile errorProfile,
@Cached("createMethodCall()") CallDispatchHeadNode toStr) {
final Object coerced;
try {
coerced = toStr.call(frame, object, "to_str", null);
@@ -72,10 +92,18 @@ public String coerceObject(VirtualFrame frame, Object object) {
}

if (RubyGuards.isRubyString(coerced)) {
return coerced.toString();
return StringOperations.getString(getContext(), (DynamicObject) coerced);
} else {
errorProfile.enter();
throw new RaiseException(coreExceptions().typeErrorBadCoercion(object, "String", "to_str", coerced, this));
}
}

protected String symbolToString(DynamicObject symbol) {
return Layouts.SYMBOL.getString(symbol);
}

protected int getLimit() {
return getContext().getOptions().INTEROP_CONVERT_CACHE;
}
}
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ DynamicObjectFactory createFiberShape(DynamicObject logicalClass,
DynamicObject metaClass);

DynamicObject createFiber(DynamicObjectFactory factory,
DynamicObject fiberLocals,
boolean rootFiber,
CountDownLatch initializedLatch,
BlockingQueue<FiberNodes.FiberMessage> messageQueue,
@@ -36,6 +37,8 @@ DynamicObject createFiber(DynamicObjectFactory factory,

boolean isFiber(DynamicObject object);

DynamicObject getFiberLocals(DynamicObject object);

boolean getRootFiber(DynamicObject object);

CountDownLatch getInitializedLatch(DynamicObject object);
Original file line number Diff line number Diff line change
@@ -44,18 +44,21 @@
@CoreClass("Fiber")
public abstract class FiberNodes {

public static DynamicObject createFiber(DynamicObject thread, DynamicObjectFactory factory, String name) {
return createFiber(thread, factory, name, false);
public static DynamicObject createFiber(RubyContext context, DynamicObject thread, DynamicObjectFactory factory, String name) {
return createFiber(context, thread, factory, name, false);
}

public static DynamicObject createRootFiber(RubyContext context, DynamicObject thread) {
return createFiber(thread, context.getCoreLibrary().getFiberFactory(), "root Fiber for Thread", true);
return createFiber(context, thread, context.getCoreLibrary().getFiberFactory(), "root Fiber for Thread", true);
}

private static DynamicObject createFiber(DynamicObject thread, DynamicObjectFactory factory, String name, boolean isRootFiber) {
private static DynamicObject createFiber(RubyContext context, DynamicObject thread, DynamicObjectFactory factory, String name, boolean isRootFiber) {
assert RubyGuards.isRubyThread(thread);
final DynamicObjectFactory instanceFactory = Layouts.CLASS.getInstanceFactory(context.getCoreLibrary().getObjectClass());
final DynamicObject fiberLocals = Layouts.BASIC_OBJECT.createBasicObject(instanceFactory);
return Layouts.FIBER.createFiber(
factory,
fiberLocals,
isRootFiber,
new CountDownLatch(1),
new LinkedBlockingQueue<FiberMessage>(2),
@@ -376,7 +379,7 @@ public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {
public DynamicObject allocate(DynamicObject rubyClass) {
DynamicObject parent = getContext().getThreadManager().getCurrentThread();
DynamicObjectFactory factory = Layouts.CLASS.getInstanceFactory(rubyClass);
return createFiber(parent, factory, null);
return createFiber(getContext(), parent, factory, null);
}

}
109 changes: 23 additions & 86 deletions truffle/src/main/java/org/jruby/truffle/core/kernel/KernelNodes.java
Original file line number Diff line number Diff line change
@@ -118,8 +118,10 @@
import org.jruby.truffle.language.objects.LogicalClassNodeGen;
import org.jruby.truffle.language.objects.MetaClassNode;
import org.jruby.truffle.language.objects.MetaClassNodeGen;
import org.jruby.truffle.language.objects.ReadObjectFieldNode;
import org.jruby.truffle.language.objects.ReadObjectFieldNodeGen;
import org.jruby.truffle.language.objects.ObjectIVarGetNode;
import org.jruby.truffle.language.objects.ObjectIVarGetNodeGen;
import org.jruby.truffle.language.objects.ObjectIVarSetNode;
import org.jruby.truffle.language.objects.ObjectIVarSetNodeGen;
import org.jruby.truffle.language.objects.SingletonClassNode;
import org.jruby.truffle.language.objects.SingletonClassNodeGen;
import org.jruby.truffle.language.objects.TaintNode;
@@ -130,7 +132,6 @@
import org.jruby.truffle.language.parser.jruby.TranslatorDriver;
import org.jruby.truffle.language.threadlocal.ThreadLocalObject;
import org.jruby.truffle.platform.UnsafeGroup;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
@@ -943,7 +944,7 @@ public abstract static class InstanceVariableDefinedNode extends CoreMethodNode

@CreateCast("name")
public RubyNode coerceToString(RubyNode name) {
return NameToJavaStringNodeGen.create(null, null, name);
return NameToJavaStringNodeGen.create(name);
}

@TruffleBoundary
@@ -963,49 +964,18 @@ public boolean isInstanceVariableDefined(DynamicObject object, String name) {
public abstract static class InstanceVariableGetNode extends CoreMethodNode {

@CreateCast("name")
public RubyNode coerceToSymbolOrString(RubyNode name) {
return NameToSymbolOrStringNodeGen.create(null, null, name);
}

@Specialization(
guards = { "name == cachedName" , "isRubySymbol(cachedName)" },
limit = "getCacheLimit()")
public Object instanceVariableGetSymbolCached(DynamicObject object, DynamicObject name,
@Cached("name") DynamicObject cachedName,
@Cached("createReadFieldNode(checkName(symbolToString(cachedName)))") ReadObjectFieldNode readHeadObjectFieldNode) {
return readHeadObjectFieldNode.execute(object);
}

@Specialization(guards = "isRubySymbol(name)")
public Object instanceVariableGetSymbol(DynamicObject object, DynamicObject name) {
return ivarGet(object, symbolToString(name));
}

@TruffleBoundary
@Specialization(guards = "isRubyString(name)")
public Object instanceVariableGetString(DynamicObject object, DynamicObject name) {
return ivarGet(object, name.toString());
public RubyNode coerceName(RubyNode name) {
return NameToJavaStringNodeGen.create(name);
}

@TruffleBoundary
private Object ivarGet(DynamicObject object, String name) {
return object.get(checkName(name), nil());
}

protected String symbolToString(DynamicObject name) {
return Layouts.SYMBOL.getString(name);
}

protected String checkName(String name) {
return SymbolTable.checkInstanceVariableName(getContext(), name, this);
@Specialization
public Object instanceVariableGetSymbol(DynamicObject object, String name,
@Cached("createObjectIVarGetNode()") ObjectIVarGetNode iVarGetNode) {
return iVarGetNode.executeIVarGet(object, name);
}

protected ReadObjectFieldNode createReadFieldNode(String name) {
return ReadObjectFieldNodeGen.create(name, nil());
}

protected int getCacheLimit() {
return getContext().getOptions().INSTANCE_VARIABLE_CACHE;
protected ObjectIVarGetNode createObjectIVarGetNode() {
return ObjectIVarGetNodeGen.create(true, null, null);
}

}
@@ -1019,51 +989,18 @@ protected int getCacheLimit() {
public abstract static class InstanceVariableSetNode extends CoreMethodNode {

@CreateCast("name")
public RubyNode coerceToSymbolOrString(RubyNode name) {
return NameToSymbolOrStringNodeGen.create(null, null, name);
public RubyNode coerceName(RubyNode name) {
return NameToJavaStringNodeGen.create(name);
}

@Specialization(
guards = { "name == cachedName", "isRubySymbol(cachedName)" },
limit = "getCacheLimit()")
public Object instanceVariableSetSymbolCached(DynamicObject object, DynamicObject name, Object value,
@Cached("name") DynamicObject cachedName,
@Cached("createWriteFieldNode(checkName(symbolToString(cachedName)))") WriteObjectFieldNode writeHeadObjectFieldNode) {
writeHeadObjectFieldNode.execute(object, value);
return value;
}

@Specialization(guards = "isRubySymbol(name)")
public Object instanceVariableSetSymbol(DynamicObject object, DynamicObject name, Object value) {
return ivarSet(object, symbolToString(name), value);
}

@TruffleBoundary
@Specialization(guards = "isRubyString(name)")
public Object instanceVariableSetString(DynamicObject object, DynamicObject name, Object value) {
return ivarSet(object, name.toString(), value);
}

@TruffleBoundary
private Object ivarSet(DynamicObject object, String name, Object value) {
object.define(checkName(name), value, 0);
return value;
}

protected String symbolToString(DynamicObject name) {
return Layouts.SYMBOL.getString(name);
}

protected String checkName(String name) {
return SymbolTable.checkInstanceVariableName(getContext(), name, this);
}

protected WriteObjectFieldNode createWriteFieldNode(String name) {
return WriteObjectFieldNodeGen.create(name);
@Specialization
public Object instanceVariableSet(DynamicObject object, String name, Object value,
@Cached("createObjectIVarSetNode()") ObjectIVarSetNode iVarSetNode) {
return iVarSetNode.executeIVarSet(object, name, value);
}

protected int getCacheLimit() {
return getContext().getOptions().INSTANCE_VARIABLE_CACHE;
protected ObjectIVarSetNode createObjectIVarSetNode() {
return ObjectIVarSetNodeGen.create(true, null, null, null);
}

}
@@ -1077,7 +1014,7 @@ public abstract static class RemoveInstanceVariableNode extends CoreMethodNode {

@CreateCast("name")
public RubyNode coerceToString(RubyNode name) {
return NameToJavaStringNodeGen.create(null, null, name);
return NameToJavaStringNodeGen.create(name);
}

@TruffleBoundary
@@ -1199,7 +1136,7 @@ public abstract static class MethodNode extends CoreMethodNode {

public MethodNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
nameToJavaStringNode = NameToJavaStringNodeGen.create(getContext(), getSourceSection(), null);
nameToJavaStringNode = NameToJavaStringNode.create();
lookupMethodNode = LookupMethodNodeGen.create(context, sourceSection, null, null);
respondToMissingNode = DispatchHeadNodeFactory.createMethodCall(getContext(), true);
}
Loading