Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically force all-defaulted functions #3414

Merged
merged 17 commits into from
Apr 27, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.ConditionProfile;
import com.oracle.truffle.api.source.SourceSection;
import java.util.UUID;
import java.util.concurrent.locks.Lock;
Expand All @@ -17,7 +16,6 @@
import org.enso.interpreter.runtime.callable.UnresolvedConversion;
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
import org.enso.interpreter.runtime.callable.argument.Thunk;
import org.enso.interpreter.runtime.callable.atom.Atom;
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
import org.enso.interpreter.runtime.callable.function.Function;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,9 @@ private Object executeArguments(
Object state,
ThunkExecutorNode thunkExecutorNode) {
for (int i = 0; i < mapping.getArgumentShouldExecute().length; i++) {
if (TypesGen.isThunk(arguments[i]) && mapping.getArgumentShouldExecute()[i]) {
if (mapping.getArgumentShouldExecute()[i]) {
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved
Stateful result =
thunkExecutorNode.executeThunk(
TypesGen.asThunk(arguments[i]), state, BaseNode.TailStatus.NOT_TAIL);
thunkExecutorNode.executeThunk(arguments[i], state, BaseNode.TailStatus.NOT_TAIL);
arguments[i] = result.getValue();
state = result.getState();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,17 @@ public static ReadArgumentNode build(int position, ExpressionNode defaultValue)
*/
@Override
public Object executeGeneric(VirtualFrame frame) {
Object argument = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[index];
Object arguments[] = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());

if (defaultValue == null) {
return argument;
return arguments[index];
}

// Note [Handling Argument Defaults]
if (defaultingProfile.profile(argument == null)) {
if (defaultingProfile.profile(arguments.length <= index || arguments[index] == null)) {
return defaultValue.executeGeneric(frame);
} else {
return argument;
return arguments[index];
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.node.ExpressionNode;
import org.enso.interpreter.runtime.callable.argument.Thunk;
import org.enso.interpreter.runtime.callable.function.Function;

/** This node is responsible for wrapping a call target in a {@link Thunk} at execution time. */
@NodeInfo(shortName = "CreateThunk", description = "Wraps a call target in a thunk at runtime")
Expand Down Expand Up @@ -34,6 +34,6 @@ public static CreateThunkNode build(RootCallTarget callTarget) {
*/
@Override
public Object executeGeneric(VirtualFrame frame) {
return new Thunk(this.callTarget, frame.materialize());
return Function.thunk(this.callTarget, frame.materialize());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.node.ExpressionNode;
import org.enso.interpreter.runtime.callable.argument.Thunk;
import org.enso.interpreter.runtime.state.Stateful;

/** Node responsible for handling user-requested thunks forcing. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.Constants;
import org.enso.interpreter.node.BaseNode;
import org.enso.interpreter.node.callable.InvokeCallableNode;
import org.enso.interpreter.node.callable.dispatch.IndirectInvokeFunctionNode;
import org.enso.interpreter.node.callable.dispatch.InvokeFunctionNode;
import org.enso.interpreter.node.callable.dispatch.LoopingCallOptimiserNode;
import org.enso.interpreter.runtime.callable.argument.Thunk;
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.control.TailCallException;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;

/** Node responsible for executing (forcing) thunks passed to it as runtime values. */
@GenerateUncached
Expand Down Expand Up @@ -40,20 +42,15 @@ public static ThunkExecutorNode build() {
*/
public abstract Stateful executeThunk(Object thunk, Object state, BaseNode.TailStatus isTail);

static boolean isThunk(Object th) {
return TypesGen.isThunk(th);
}

@Specialization(guards = "!isThunk(thunk)")
Stateful doOther(Object thunk, Object state, BaseNode.TailStatus isTail) {
return new Stateful(state, thunk);
boolean sameCallTarget(DirectCallNode callNode, Function function) {
return function.getCallTarget() == callNode.getCallTarget();
}

@Specialization(
guards = "callNode.getCallTarget() == thunk.getCallTarget()",
guards = {"thunk.isThunk()", "sameCallTarget(callNode, thunk)"},
limit = Constants.CacheSizes.THUNK_EXECUTOR_NODE)
Stateful doCached(
Thunk thunk,
Function thunk,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit pick: does the variable still deserve name thunk when it's type is now Function?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that thunk.isThunk is a bit confusing :)

Object state,
BaseNode.TailStatus isTail,
@Cached("create(thunk.getCallTarget())") DirectCallNode callNode,
Expand All @@ -71,9 +68,9 @@ Stateful doCached(
}
}

@Specialization(replaces = "doCached")
@Specialization(replaces = "doCached", guards = "thunk.isThunk()")
Stateful doUncached(
Thunk thunk,
Function thunk,
Object state,
BaseNode.TailStatus isTail,
@Cached IndirectCallNode callNode,
Expand All @@ -93,4 +90,50 @@ Stateful doUncached(
}
}
}

static InvokeFunctionNode buildInvokeFunctionNode(BaseNode.TailStatus tailStatus) {
var node =
InvokeFunctionNode.build(
new CallArgumentInfo[0],
InvokeCallableNode.DefaultsExecutionMode.EXECUTE,
InvokeCallableNode.ArgumentsExecutionMode.EXECUTE);
node.setTailStatus(tailStatus);
return node;
}

@Specialization(
guards = {"!fn.isThunk()", "fn.isFullyApplied()", "isTail == cachedIsTail"},
limit = "3" /* limit is 3 because that's the number of different values for isTail */)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One could define

  static int numberOfDifferentValuesForIsTail() {
    return BaseNode.TailStatus.values().length;
  }

and then use

Suggested change
limit = "3" /* limit is 3 because that's the number of different values for isTail */)
limit = "numberOfDifferentValuesForIsTail()"

Stateful doCachedFn(
Function fn,
Object state,
BaseNode.TailStatus isTail,
@Cached("isTail") BaseNode.TailStatus cachedIsTail,
@Cached("buildInvokeFunctionNode(cachedIsTail)") InvokeFunctionNode invokeFunctionNode) {
return invokeFunctionNode.execute(fn, null, state, new Object[0]);
}

@Specialization(
guards = {"!fn.isThunk()", "fn.isFullyApplied()"},
replaces = {"doCachedFn"})
Stateful doUncachedFn(
Function fn,
Object state,
BaseNode.TailStatus isTail,
@Cached IndirectInvokeFunctionNode invokeFunctionNode) {
return invokeFunctionNode.execute(
fn,
null,
state,
new Object[0],
new CallArgumentInfo[0],
InvokeCallableNode.DefaultsExecutionMode.EXECUTE,
InvokeCallableNode.ArgumentsExecutionMode.EXECUTE,
isTail);
}

@Fallback
Stateful doOther(Object thunk, Object state, BaseNode.TailStatus isTail) {
return new Stateful(state, thunk);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import org.enso.interpreter.dsl.Suspend;
import org.enso.interpreter.node.BaseNode;
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
import org.enso.interpreter.runtime.callable.argument.Thunk;
import org.enso.interpreter.runtime.state.Stateful;

@BuiltinMethod(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import org.enso.interpreter.node.BaseNode;
import org.enso.interpreter.node.callable.InvokeCallableNode;
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
import org.enso.interpreter.runtime.callable.argument.Thunk;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.state.Stateful;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import org.enso.interpreter.runtime.callable.atom.Atom;
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
import org.enso.interpreter.runtime.data.Array;
import org.enso.interpreter.runtime.type.TypesGen;

@BuiltinMethod(
type = "Meta",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import org.enso.interpreter.dsl.Suspend;
import org.enso.interpreter.node.BaseNode;
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
import org.enso.interpreter.runtime.callable.argument.Thunk;
import org.enso.interpreter.runtime.state.Stateful;

@BuiltinMethod(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import org.enso.interpreter.dsl.Suspend;
import org.enso.interpreter.node.BaseNode;
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
import org.enso.interpreter.runtime.callable.argument.Thunk;
import org.enso.interpreter.runtime.control.ThreadInterruptedException;
import org.enso.interpreter.runtime.state.Stateful;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.callable.CallerInfo;
import org.enso.interpreter.runtime.callable.argument.Thunk;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.data.text.Text;
import org.enso.interpreter.runtime.scope.LocalScope;
import org.enso.interpreter.runtime.scope.ModuleScope;
Expand Down Expand Up @@ -98,7 +98,7 @@ Stateful doCached(
"parseExpression(callerInfo.getLocalScope(), callerInfo.getModuleScope(), expressionStr)")
RootCallTarget cachedCallTarget,
@Cached("build()") ThunkExecutorNode thunkExecutorNode) {
Thunk thunk = new Thunk(cachedCallTarget, callerInfo.getFrame());
Function thunk = Function.thunk(cachedCallTarget, callerInfo.getFrame());
return thunkExecutorNode.executeThunk(thunk, state, getTailStatus());
}

Expand All @@ -114,7 +114,7 @@ Stateful doUncached(
callerInfo.getLocalScope(),
callerInfo.getModuleScope(),
toJavaStringNode.execute(expression));
Thunk thunk = new Thunk(callTarget, callerInfo.getFrame());
Function thunk = Function.thunk(callTarget, callerInfo.getFrame());
return thunkExecutorNode.executeThunk(thunk, state, getTailStatus());
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import org.enso.interpreter.runtime.callable.UnresolvedConversion;
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.argument.Thunk;
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
import org.enso.interpreter.runtime.library.dispatch.MethodDispatchLibrary;
import org.enso.interpreter.runtime.state.data.EmptyMap;
Expand Down Expand Up @@ -79,6 +78,10 @@ public Function(RootCallTarget callTarget, MaterializedFrame scope, FunctionSche
this(callTarget, scope, schema, null, null);
}

public static Function thunk(RootCallTarget callTarget, MaterializedFrame scope) {
return new Function(callTarget, scope, FunctionSchema.THUNK);
}

/**
* Creates a Function object from a {@link BuiltinRootNode} and argument definitions.
*
Expand Down Expand Up @@ -308,7 +311,7 @@ public static Object[] buildArguments(
* @param state the state to execute the thunk with
* @return an array containing the necessary information to call an Enso thunk
*/
public static Object[] buildArguments(Thunk thunk, Object state) {
public static Object[] buildArguments(Function thunk, Object state) {
return new Object[] {thunk.getScope(), null, state, new Object[0]};
}

Expand Down Expand Up @@ -456,4 +459,12 @@ static Function resolve(Function _this, AtomConstructor target, UnresolvedConver
return function;
}
}

public boolean isThunk() {
return schema == FunctionSchema.THUNK;
}

public boolean isFullyApplied() {
return schema.isFullyApplied();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,17 @@ public boolean shouldFrameBePassed() {
}
}

public static final FunctionSchema THUNK = new FunctionSchema();
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved

private final @CompilationFinal(dimensions = 1) ArgumentDefinition[] argumentInfos;
private final @CompilationFinal(dimensions = 1) boolean[] hasPreApplied;
private final @CompilationFinal(dimensions = 1) CallArgumentInfo[] oversaturatedArguments;
private final boolean hasAnyPreApplied;
private final boolean hasOversaturatedArguments;
private final CallerFrameAccess callerFrameAccess;

public final boolean isFullyApplied;
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved

/**
* Creates an {@link FunctionSchema} instance.
*
Expand Down Expand Up @@ -66,6 +70,7 @@ public FunctionSchema(

this.hasAnyPreApplied = hasAnyPreApplied;
this.hasOversaturatedArguments = this.oversaturatedArguments.length > 0;
this.isFullyApplied = isFullyApplied(InvokeCallableNode.DefaultsExecutionMode.EXECUTE);
}

/**
Expand Down Expand Up @@ -211,4 +216,8 @@ public boolean isFullyApplied(InvokeCallableNode.DefaultsExecutionMode defaultsE
}
return functionIsFullyApplied;
}

public boolean isFullyApplied() {
return isFullyApplied;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
import com.oracle.truffle.api.dsl.TypeSystem;
import com.oracle.truffle.api.interop.ArityException;
import com.oracle.truffle.api.interop.UnsupportedTypeException;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.callable.UnresolvedConversion;
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
import org.enso.interpreter.runtime.callable.argument.Thunk;
import org.enso.interpreter.runtime.callable.atom.Atom;
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
import org.enso.interpreter.runtime.callable.function.Function;
Expand Down Expand Up @@ -40,7 +38,6 @@
Function.class,
Atom.class,
AtomConstructor.class,
Thunk.class,
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved
DataflowError.class,
UnresolvedConversion.class,
UnresolvedSymbol.class,
Expand Down Expand Up @@ -124,8 +121,6 @@ public static String getName(Object value) {
return TypesGen.asAtom(value).getConstructor().getQualifiedName().toString();
} else if (TypesGen.isAtomConstructor(value)) {
return TypesGen.asAtomConstructor(value).getQualifiedName().toString();
} else if (TypesGen.isThunk(value)) {
return Constants.THUNK;
} else if (TypesGen.isDataflowError(value)) {
return Constants.ERROR;
} else if (TypesGen.isUnresolvedSymbol(value) || TypesGen.isUnresolvedConversion(value)) {
Expand Down
Loading