Skip to content
Snippets Groups Projects
Commit ea499e8a authored by Lukas Stadler's avatar Lukas Stadler
Browse files

proper loop unrolling in AccessArgumentNode and CallArgumentsNode

parent 34fd16db
Branches
No related tags found
No related merge requests found
......@@ -278,7 +278,7 @@ public abstract class Lapply extends RBuiltinNode {
protected ResolvedCachedCallNode(RootCallTarget originalTarget, RArgsValuesAndNames varArgs, CachedCallNode next) {
super(next.owner);
this.originalTarget = originalTarget;
this.originalSignature = CallArgumentsNode.createSignature(varArgs, 1, true);
this.originalSignature = CallArgumentsNode.createSignature(varArgs, 1);
this.callNode = checkFunction(originalTarget, varArgs);
this.next = next;
}
......@@ -290,7 +290,7 @@ public abstract class Lapply extends RBuiltinNode {
@Override
public Object execute(VirtualFrame frame, RootCallTarget target, RArgsValuesAndNames varArgs) {
VarArgsSignature signature = CallArgumentsNode.createSignature(varArgs, 1, true);
VarArgsSignature signature = CallArgumentsNode.createSignature(varArgs, 1);
if (target != originalTarget || signature.isNotEqualTo(originalSignature)) {
return next.execute(frame, target, varArgs);
} else {
......
......@@ -113,16 +113,30 @@ public abstract class AccessArgumentNode extends RNode {
return handlePromise(frame, promise, topLevelInlinedPromiseProfile);
}
@Specialization
private void handleVarArgPromise(VirtualFrame frame, Object[] varArgs, int i) {
// DON'T use exprExecNode here, as caching would fail here: Every argument wrapped into
// "..." is a different expression
if (varArgIsPromiseProfile.profile(varArgs[i] instanceof RPromise)) {
varArgs[i] = handlePromise(frame, (RPromise) varArgs[i], varArgInlinedPromiseProfile);
}
}
@Specialization(limit = "1", guards = "cachedVarArgLength == varArgsContainer.length()")
@ExplodeLoop
protected Object doArgumentCached(VirtualFrame frame, RArgsValuesAndNames varArgsContainer, @Cached("varArgsContainer.length()") int cachedVarArgLength) {
Object[] varArgs = varArgsContainer.getValues();
for (int i = 0; i < cachedVarArgLength; i++) {
handleVarArgPromise(frame, varArgs, i);
}
return varArgsContainer;
}
@Specialization(contains = "doArgumentCached")
protected Object doArgument(VirtualFrame frame, RArgsValuesAndNames varArgsContainer) {
Object[] varArgs = varArgsContainer.getValues();
for (int i = 0; i < varArgsContainer.length(); i++) {
// DON'T use exprExecNode here, as caching would fail here: Every argument wrapped into
// "..." is a different expression
if (varArgIsPromiseProfile.profile(varArgs[i] instanceof RPromise)) {
varArgs[i] = handlePromise(frame, (RPromise) varArgs[i], varArgInlinedPromiseProfile);
}
handleVarArgPromise(frame, varArgs, i);
}
return varArgsContainer;
}
......
......@@ -59,6 +59,11 @@ public class CallArgumentsNode extends ArgumentsNode implements UnmatchedArgumen
*/
@CompilationFinal private final int[] varArgsSymbolIndices;
private static final int UNINITIALIZED = -1;
private static final int VARIABLE = -2;
@CompilationFinal private int cachedSignatureLength = UNINITIALIZED;
private final IdentityHashMap<RNode, Closure> closureCache = new IdentityHashMap<>();
/**
......@@ -150,7 +155,28 @@ public class CallArgumentsNode extends ArgumentsNode implements UnmatchedArgumen
// Unroll "..."s and insert their arguments into VarArgsSignature
int times = varArgsSymbolIndices.length;
return createSignature(getVarargsAndNames(frame), times, true);
RArgsValuesAndNames varArgsAndNames = getVarargsAndNames(frame);
// "..." empty?
if (varArgsAndNames.isEmpty()) {
return VarArgsSignature.NO_VARARGS_GIVEN;
} else {
// Arguments wrapped into "..."
Object[] varArgs = varArgsAndNames.getValues();
Object[] content;
if (cachedSignatureLength != VARIABLE && cachedSignatureLength != varArgs.length) {
CompilerDirectives.transferToInterpreterAndInvalidate();
cachedSignatureLength = cachedSignatureLength == UNINITIALIZED ? varArgs.length : VARIABLE;
}
if (cachedSignatureLength == VARIABLE) {
content = new Object[varArgs.length];
createSignatureLoop(content, varArgs);
} else {
content = new Object[cachedSignatureLength];
createSignatureLoopUnrolled(content, varArgs, cachedSignatureLength);
}
return VarArgsSignature.create(content, times);
}
}
public RArgsValuesAndNames getVarargsAndNames(VirtualFrame frame) {
......@@ -163,33 +189,46 @@ public class CallArgumentsNode extends ArgumentsNode implements UnmatchedArgumen
return varArgsAndNames;
}
public static VarArgsSignature createSignature(RArgsValuesAndNames varArgsAndNames, int times, boolean allowConstants) {
Object[] content;
public static VarArgsSignature createSignature(RArgsValuesAndNames varArgsAndNames, int times) {
// "..." empty?
if (varArgsAndNames.isEmpty()) {
content = new Object[]{VarArgsSignature.NO_VARARGS};
return VarArgsSignature.NO_VARARGS_GIVEN;
} else {
// Arguments wrapped into "..."
Object[] varArgs = varArgsAndNames.getValues();
content = new Object[varArgs.length];
// As we want to check on expression identity later on:
for (int i = 0; i < varArgs.length; i++) {
Object varArg = varArgs[i];
if (varArg instanceof RPromise) {
// Unwrap expression (one instance per argument/call site)
content[i] = ((RPromise) varArg).getRep();
} else if (RMissingHelper.isMissing(varArg)) {
// Use static symbol for "missing" instead of ConstantNode.create
content[i] = VarArgsSignature.NO_VARARGS;
} else {
assert allowConstants;
content[i] = varArg;
}
}
Object[] content = new Object[varArgs.length];
createSignatureLoop(content, varArgs);
return VarArgsSignature.create(content, times);
}
}
private static void createSignatureLoop(Object[] content, Object[] varArgs) {
// As we want to check on expression identity later on:
for (int i = 0; i < varArgs.length; i++) {
createSignatureLoopContents(content, varArgs, i);
}
}
@ExplodeLoop
private static void createSignatureLoopUnrolled(Object[] content, Object[] varArgs, int length) {
// As we want to check on expression identity later on:
for (int i = 0; i < length; i++) {
createSignatureLoopContents(content, varArgs, i);
}
}
private static void createSignatureLoopContents(Object[] content, Object[] varArgs, int i) {
Object varArg = varArgs[i];
if (varArg instanceof RPromise) {
// Unwrap expression (one instance per argument/call site)
content[i] = ((RPromise) varArg).getRep();
} else if (RMissingHelper.isMissing(varArg)) {
// Use static symbol for "missing" instead of ConstantNode.create
content[i] = VarArgsSignature.NO_VARARGS;
} else {
content[i] = varArg;
}
return VarArgsSignature.create(content, times);
}
@ExplodeLoop
......
......@@ -56,6 +56,7 @@ public final class VarArgsSignature {
*/
public static final RNode NO_VARARGS = ConstantNode.create(RArgsValuesAndNames.EMPTY);
public static final VarArgsSignature TAKES_NO_VARARGS = new VarArgsSignature(null, 0);
public static final VarArgsSignature NO_VARARGS_GIVEN = new VarArgsSignature(new Object[]{NO_VARARGS}, 0);
@CompilationFinal private final Object[] expressions;
private final int times;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment