Skip to content

Commit

Permalink
[GR-25305] Implement RubyRootNode#cloneUninitialized
Browse files Browse the repository at this point in the history
PullRequest: truffleruby/3472
  • Loading branch information
eregon committed Oct 10, 2022
2 parents a02c9a3 + 9924cd7 commit 72aa843
Show file tree
Hide file tree
Showing 260 changed files with 2,991 additions and 608 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Compatibility:
Performance:

* Marking of native structures wrapped in objects is now done on C call exit to reduce memory overhead (@aardvark179).
* Splitting (copying) of call targets has been optimized by implementing `cloneUninitialized()` (@andrykonchin, @eregon).

Changes:

Expand Down
19 changes: 19 additions & 0 deletions src/main/java/org/truffleruby/builtins/BuiltinsClasses.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.Arrays;
import java.util.List;

import com.oracle.truffle.api.CompilerDirectives;
import org.truffleruby.cext.CExtNodesBuiltins;
import org.truffleruby.cext.CExtNodesFactory;
import org.truffleruby.core.GCNodesBuiltins;
Expand Down Expand Up @@ -155,6 +156,7 @@
import org.truffleruby.interop.SourceLocationNodesBuiltins;
import org.truffleruby.interop.SourceLocationNodesFactory;
import org.truffleruby.language.RubyBaseNode;
import org.truffleruby.language.RubyNode;
import org.truffleruby.language.TruffleBootNodesBuiltins;
import org.truffleruby.language.TruffleBootNodesFactory;
import org.truffleruby.stdlib.CoverageNodesBuiltins;
Expand Down Expand Up @@ -418,4 +420,21 @@ public static List<List<? extends NodeFactory<? extends RubyBaseNode>>> getCoreN
WeakRefNodesFactory.getFactories());
}

// TODO: maybe we can make this more efficient or prepopulate it (but that might eager-load node classes on JVM, not so good)
public static final ClassValue<NodeFactory<RubyNode>> FACTORIES = new ClassValue<>() {
@SuppressWarnings("unchecked")
@Override
protected NodeFactory<RubyNode> computeValue(Class<?> type) {
for (var factories : getCoreNodeFactories()) {
for (var factory : factories) {
if (factory.getNodeClass() == type) {
return (NodeFactory<RubyNode>) factory;
}
}
}

throw CompilerDirectives.shouldNotReachHere("Could not find NodeFactory for " + type);
}
};

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import com.oracle.truffle.api.dsl.NodeChild;

@NodeChild(value = "arguments", type = RubyNode[].class)
@NodeChild(value = "argumentNodes", type = RubyNode[].class)
public abstract class CoreMethodArrayArgumentsNode extends CoreMethodNode {

}
8 changes: 8 additions & 0 deletions src/main/java/org/truffleruby/builtins/CoreMethodNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,19 @@
*/
package org.truffleruby.builtins;

import com.oracle.truffle.api.CompilerDirectives;
import org.truffleruby.language.RubyContextSourceNode;

import com.oracle.truffle.api.dsl.GenerateNodeFactory;
import org.truffleruby.language.RubyNode;

@GenerateNodeFactory
public abstract class CoreMethodNode extends RubyContextSourceNode {

@Override
public final RubyNode cloneUninitialized() {
throw CompilerDirectives.shouldNotReachHere(
getClass() + " should be handled by RubyCoreMethodRootNode#cloneUninitializedRootNode()");
}

}
27 changes: 17 additions & 10 deletions src/main/java/org/truffleruby/builtins/CoreMethodNodeManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ private void addCoreMethod(RubyModule module, MethodDetails methodDetails) {
final Split split = effectiveSplit(annotation.split(), annotation.needsBlock());

final Function<SharedMethodInfo, RootCallTarget> callTargetFactory = sharedMethodInfo -> {
return createCoreMethodRootNode(nodeFactory, language, sharedMethodInfo, split, annotation);
return createCoreMethodCallTarget(nodeFactory, language, sharedMethodInfo, split, annotation);
};

addMethods(
Expand Down Expand Up @@ -189,7 +189,7 @@ public void addLazyCoreMethod(
final Function<SharedMethodInfo, RootCallTarget> callTargetFactory = sharedMethodInfo -> {
final NodeFactory<? extends RubyBaseNode> nodeFactory = loadNodeFactory(nodeFactoryName);
final CoreMethod annotation = nodeFactory.getNodeClass().getAnnotation(CoreMethod.class);
return createCoreMethodRootNode(nodeFactory, language, sharedMethodInfo, finalSplit, annotation);
return createCoreMethodCallTarget(nodeFactory, language, sharedMethodInfo, finalSplit, annotation);
};

addMethods(
Expand Down Expand Up @@ -319,9 +319,8 @@ private static SharedMethodInfo makeSharedMethodInfo(String moduleName, boolean
null);
}

public RootCallTarget createCoreMethodRootNode(NodeFactory<? extends RubyBaseNode> nodeFactory,
public static RootCallTarget createCoreMethodCallTarget(NodeFactory<? extends RubyBaseNode> nodeFactory,
RubyLanguage language, SharedMethodInfo sharedMethodInfo, Split split, CoreMethod method) {

// It's fine to load the node class here, this is only called when resolving the lazy CallTarget
var nodeClass = nodeFactory.getNodeClass();

Expand Down Expand Up @@ -350,11 +349,18 @@ public RootCallTarget createCoreMethodRootNode(NodeFactory<? extends RubyBaseNod
null,
sharedMethodInfo,
new ReRaiseInlinedExceptionNode(nodeFactory),
split,
Split.NEVER,
ReturnID.INVALID);
return reRaiseRootNode.getCallTarget();
}

return createCoreMethodRootNode(nodeFactory, language, sharedMethodInfo, split, method).getCallTarget();
}

public static RubyCoreMethodRootNode createCoreMethodRootNode(NodeFactory<? extends RubyBaseNode> nodeFactory,
RubyLanguage language, SharedMethodInfo sharedMethodInfo, Split split, CoreMethod method) {
assert !method.alwaysInlined();

final RubyNode[] argumentsNodes = new RubyNode[nodeFactory.getExecutionSignature().size()];
int i = 0;

Expand Down Expand Up @@ -384,18 +390,19 @@ public RootCallTarget createCoreMethodRootNode(NodeFactory<? extends RubyBaseNod
}

RubyNode node = (RubyNode) createNodeFromFactory(nodeFactory, argumentsNodes);
RubyNode methodNode = transformResult(method, node);
RubyNode methodNode = transformResult(language, method, node);

final RubyCoreMethodRootNode rootNode = new RubyCoreMethodRootNode(
return new RubyCoreMethodRootNode(
language,
sharedMethodInfo.getSourceSection(),
null,
sharedMethodInfo,
methodNode,
split,
ReturnID.INVALID,
sharedMethodInfo.getArity());
return rootNode.getCallTarget();
sharedMethodInfo.getArity(),
nodeFactory,
method);
}

public static RubyBaseNode createNodeFromFactory(NodeFactory<? extends RubyBaseNode> nodeFactory,
Expand Down Expand Up @@ -438,7 +445,7 @@ private static RubyNode transformArgument(CoreMethod method, RubyNode argument,
return argument;
}

private RubyNode transformResult(CoreMethod method, RubyNode node) {
private static RubyNode transformResult(RubyLanguage language, CoreMethod method, RubyNode node) {
if (!method.enumeratorSize().isEmpty()) {
assert !method.returnsEnumeratorIfNoBlock()
: "Only one of enumeratorSize or returnsEnumeratorIfNoBlock can be specified";
Expand Down
13 changes: 11 additions & 2 deletions src/main/java/org/truffleruby/builtins/EnumeratorSizeNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ public class EnumeratorSizeNode extends RubyContextSourceNode {
private final RubySymbol methodName;
private final RubySymbol sizeMethodName;

public EnumeratorSizeNode(RubySymbol enumeratorSize, RubySymbol methodName, RubyNode method) {
public EnumeratorSizeNode(RubySymbol sizeMethodName, RubySymbol methodName, RubyNode method) {
this.method = method;
this.methodName = methodName;
this.sizeMethodName = enumeratorSize;
this.sizeMethodName = sizeMethodName;
}

@Override
Expand All @@ -57,4 +57,13 @@ public Object execute(VirtualFrame frame) {
}
}

@Override
public RubyNode cloneUninitialized() {
var copy = new EnumeratorSizeNode(
sizeMethodName,
methodName,
method.cloneUninitialized());
return copy.copyFlags(this);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,22 @@
*/
package org.truffleruby.builtins;

import com.oracle.truffle.api.dsl.NodeFactory;
import org.truffleruby.language.RubyNode;

import com.oracle.truffle.api.dsl.NodeChild;

@NodeChild(value = "arguments", type = RubyNode[].class)
@NodeChild(value = "argumentNodes", type = RubyNode[].class)
public abstract class PrimitiveArrayArgumentsNode extends PrimitiveNode {

public abstract RubyNode[] getArgumentNodes();

@Override
public RubyNode cloneUninitialized() {
NodeFactory<RubyNode> factory = BuiltinsClasses.FACTORIES.get(getClass().getSuperclass());
RubyNode[] copiedArguments = cloneUninitialized(getArgumentNodes());
var copy = (PrimitiveArrayArgumentsNode) CoreMethodNodeManager.createNodeFromFactory(factory, copiedArguments);
return copy.copyFlags(this);
}

}
8 changes: 7 additions & 1 deletion src/main/java/org/truffleruby/builtins/PrimitiveNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,24 @@

package org.truffleruby.builtins;

import com.oracle.truffle.api.dsl.NodeFactory;
import org.truffleruby.language.RubyContextSourceNode;
import org.truffleruby.language.NotProvided;

import com.oracle.truffle.api.dsl.GenerateNodeFactory;
import org.truffleruby.language.RubyNode;

@GenerateNodeFactory
public abstract class PrimitiveNode extends RubyContextSourceNode {

// The same as "undefined" in Ruby code
protected static final Object FAILURE = NotProvided.INSTANCE;

public PrimitiveNode() {
@Override
public RubyNode cloneUninitialized() {
NodeFactory<RubyNode> factory = BuiltinsClasses.FACTORIES.get(getClass().getSuperclass());
var copy = (PrimitiveNode) CoreMethodNodeManager.createNodeFromFactory(factory, RubyNode.EMPTY_ARRAY);
return copy.copyFlags(this);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.truffleruby.core.exception.RubyException;
import org.truffleruby.language.RubyBaseNode;
import org.truffleruby.language.RubyContextSourceNode;
import org.truffleruby.language.RubyNode;
import org.truffleruby.language.control.RaiseException;

import com.oracle.truffle.api.CompilerDirectives;
Expand Down Expand Up @@ -48,4 +49,9 @@ public Object execute(VirtualFrame frame) {
throw new RaiseException(getContext(), rubyException);
}

@Override
public RubyNode cloneUninitialized() {
throw CompilerDirectives.shouldNotReachHere(getClass() + " should never be split");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,12 @@ public Object execute(VirtualFrame frame) {
}
}

@Override
public RubyNode cloneUninitialized() {
var copy = new ReturnEnumeratorIfNoBlockNode(
methodName,
method.cloneUninitialized());
return copy.copyFlags(this);
}

}
24 changes: 0 additions & 24 deletions src/main/java/org/truffleruby/builtins/UnaryCoreMethodNode.java

This file was deleted.

2 changes: 1 addition & 1 deletion src/main/java/org/truffleruby/cext/CExtNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,7 @@ protected int bitLength(RubyBignum num) {
}

@Primitive(name = "rb_int_singlebit_p")
public abstract static class IntSinglebitPPrimitiveNode extends CoreMethodArrayArgumentsNode {
public abstract static class IntSinglebitPPrimitiveNode extends PrimitiveArrayArgumentsNode {

@Specialization
protected int intSinglebitP(int num) {
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/org/truffleruby/core/IsNilNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,10 @@ public Object execute(VirtualFrame frame) {
return child.execute(frame) == nil;
}

@Override
public RubyNode cloneUninitialized() {
var copy = new IsNilNode(child.cloneUninitialized());
return copy.copyFlags(this);
}

}
4 changes: 2 additions & 2 deletions src/main/java/org/truffleruby/core/MathNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -387,9 +387,9 @@ protected double doFunction(double a) {
}

@Primitive(name = "math_hypot")
public abstract static class HypotNode extends SimpleDyadicMathNode {
public abstract static class HypotNode extends PrimitiveArrayArgumentsNode {

@Override
@Specialization
protected double doFunction(double a, double b) {
return Math.hypot(a, b);
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/truffleruby/core/TruffleSystemNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ protected RubyArray envVars() {
}

@Primitive(name = "java_get_env")
public abstract static class JavaGetEnv extends CoreMethodArrayArgumentsNode {
public abstract static class JavaGetEnv extends PrimitiveArrayArgumentsNode {

@Specialization(guards = "strings.isRubyString(name)", limit = "1")
protected Object javaGetEnv(Object name,
Expand Down
13 changes: 12 additions & 1 deletion src/main/java/org/truffleruby/core/array/ArrayAppendOneNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.profiles.ConditionProfile;

@NodeChild(value = "array", type = RubyNode.class)
@NodeChild(value = "arrayNode", type = RubyNode.class)
@NodeChild(value = "valueNode", type = RubyNode.class)
@ImportStatic(ArrayGuards.class)
public abstract class ArrayAppendOneNode extends RubyContextSourceNode {
Expand All @@ -35,6 +35,8 @@ public static ArrayAppendOneNode create() {

public abstract RubyArray executeAppendOne(RubyArray array, Object value);

public abstract RubyNode getArrayNode();

public abstract RubyNode getValueNode();

// Append of the correct type
Expand Down Expand Up @@ -83,4 +85,13 @@ protected RubyArray appendOneGeneralizeNonMutable(RubyArray array, Object value,
setStoreAndSize(array, newStore, newSize);
return array;
}

@Override
public RubyNode cloneUninitialized() {
var copy = ArrayAppendOneNodeGen.create(
getArrayNode().cloneUninitialized(),
getValueNode().cloneUninitialized());
return copy.copyFlags(this);
}

}
5 changes: 5 additions & 0 deletions src/main/java/org/truffleruby/core/array/ArrayConcatNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,9 @@ public void doExecuteVoid(VirtualFrame frame) {
}
}

public RubyNode cloneUninitialized() {
var copy = new ArrayConcatNode(cloneUninitialized(children));
return copy.copyFlags(this);
}

}
Loading

0 comments on commit 72aa843

Please sign in to comment.