Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
342 additions
and
15 deletions.
There are no files selected for viewing
218 changes: 218 additions & 0 deletions
218
...untime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeConversionNode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,218 @@ | ||
package org.enso.interpreter.node.callable; | ||
|
||
import com.oracle.truffle.api.TruffleLanguage; | ||
import com.oracle.truffle.api.dsl.*; | ||
import com.oracle.truffle.api.frame.MaterializedFrame; | ||
import com.oracle.truffle.api.frame.VirtualFrame; | ||
import com.oracle.truffle.api.interop.InteropLibrary; | ||
import com.oracle.truffle.api.interop.UnsupportedMessageException; | ||
import com.oracle.truffle.api.library.CachedLibrary; | ||
import com.oracle.truffle.api.nodes.ExplodeLoop; | ||
import com.oracle.truffle.api.nodes.Node; | ||
import com.oracle.truffle.api.profiles.BranchProfile; | ||
import com.oracle.truffle.api.profiles.ConditionProfile; | ||
import org.enso.interpreter.Language; | ||
import org.enso.interpreter.node.BaseNode; | ||
import org.enso.interpreter.node.callable.dispatch.IndirectInvokeFunctionNode; | ||
import org.enso.interpreter.node.callable.resolver.AnyResolverNode; | ||
import org.enso.interpreter.node.callable.resolver.DataflowErrorResolverNode; | ||
import org.enso.interpreter.node.callable.resolver.HostMethodCallNode; | ||
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode; | ||
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.CallArgumentInfo; | ||
import org.enso.interpreter.runtime.callable.function.Function; | ||
import org.enso.interpreter.runtime.data.text.Text; | ||
import org.enso.interpreter.runtime.error.DataflowError; | ||
import org.enso.interpreter.runtime.error.PanicException; | ||
import org.enso.interpreter.runtime.error.PanicSentinel; | ||
import org.enso.interpreter.runtime.library.dispatch.MethodDispatchLibrary; | ||
import org.enso.interpreter.runtime.state.Stateful; | ||
|
||
@GenerateUncached | ||
@ReportPolymorphism | ||
@ImportStatic({HostMethodCallNode.PolyglotCallType.class, HostMethodCallNode.class}) | ||
public abstract class IndirectInvokeConversionNode extends Node { | ||
|
||
/** @return a new indirect method invocation node */ | ||
public static IndirectInvokeConversionNode build() { | ||
return IndirectInvokeConversionNodeGen.create(); | ||
} | ||
|
||
public abstract Stateful execute( | ||
MaterializedFrame frame, | ||
Object state, | ||
UnresolvedConversion conversion, | ||
Object _this, | ||
Object that, | ||
Object[] arguments, | ||
CallArgumentInfo[] schema, | ||
InvokeCallableNode.DefaultsExecutionMode defaultsExecutionMode, | ||
InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode, | ||
BaseNode.TailStatus isTail); | ||
|
||
@Specialization(guards = "dispatch.canConvertFrom(that)") | ||
Stateful doConvertFrom( | ||
MaterializedFrame frame, | ||
Object state, | ||
UnresolvedConversion conversion, | ||
Object _this, | ||
Object that, | ||
Object[] arguments, | ||
CallArgumentInfo[] schema, | ||
InvokeCallableNode.DefaultsExecutionMode defaultsExecutionMode, | ||
InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode, | ||
BaseNode.TailStatus isTail, | ||
@CachedLibrary(limit = "10") MethodDispatchLibrary dispatch, | ||
@CachedContext(Language.class) TruffleLanguage.ContextReference<Context> ctx, | ||
@Cached ConditionProfile atomProfile, | ||
@Cached ConditionProfile atomConstructorProfile, | ||
@Cached IndirectInvokeFunctionNode indirectInvokeFunctionNode) { | ||
try { | ||
Function function = | ||
dispatch.getConversionFunction( | ||
that, | ||
InvokeConversionNode.extractConstructor( | ||
this, _this, ctx, atomConstructorProfile, atomProfile), | ||
conversion); | ||
return indirectInvokeFunctionNode.execute( | ||
function, | ||
frame, | ||
state, | ||
arguments, | ||
schema, | ||
defaultsExecutionMode, | ||
argumentsExecutionMode, | ||
isTail); | ||
} catch (MethodDispatchLibrary.NoSuchConversionException e) { | ||
throw new PanicException( | ||
ctx.get().getBuiltins().error().makeNoSuchConversionError(_this, that, conversion), this); | ||
} | ||
} | ||
|
||
@Specialization | ||
Stateful doDataflowError( | ||
MaterializedFrame frame, | ||
Object state, | ||
UnresolvedConversion conversion, | ||
Object _this, | ||
DataflowError that, | ||
Object[] arguments, | ||
CallArgumentInfo[] schema, | ||
InvokeCallableNode.DefaultsExecutionMode defaultsExecutionMode, | ||
InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode, | ||
BaseNode.TailStatus isTail, | ||
@CachedLibrary(limit = "10") MethodDispatchLibrary dispatch, | ||
@CachedContext(Language.class) TruffleLanguage.ContextReference<Context> ctx, | ||
@Cached BranchProfile profile, | ||
@Cached ConditionProfile atomProfile, | ||
@Cached ConditionProfile atomConstructorProfile, | ||
@Cached IndirectInvokeFunctionNode indirectInvokeFunctionNode) { | ||
try { | ||
Function function = | ||
dispatch.getConversionFunction( | ||
that, | ||
InvokeConversionNode.extractConstructor( | ||
this, _this, ctx, atomConstructorProfile, atomProfile), | ||
conversion); | ||
return indirectInvokeFunctionNode.execute( | ||
function, | ||
frame, | ||
state, | ||
arguments, | ||
schema, | ||
defaultsExecutionMode, | ||
argumentsExecutionMode, | ||
isTail); | ||
} catch (MethodDispatchLibrary.NoSuchConversionException e) { | ||
profile.enter(); | ||
return new Stateful(state, that); | ||
} | ||
} | ||
|
||
@Specialization | ||
Stateful doPanicSentinel( | ||
MaterializedFrame frame, | ||
Object state, | ||
UnresolvedConversion conversion, | ||
Object _this, | ||
PanicSentinel that, | ||
Object[] arguments, | ||
CallArgumentInfo[] schema, | ||
InvokeCallableNode.DefaultsExecutionMode defaultsExecutionMode, | ||
InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode, | ||
BaseNode.TailStatus isTail) { | ||
throw that; | ||
} | ||
|
||
@Specialization(guards = "interop.isString(that)") | ||
Stateful doConvertText( | ||
MaterializedFrame frame, | ||
Object state, | ||
UnresolvedConversion conversion, | ||
Object _this, | ||
Object that, | ||
Object[] arguments, | ||
CallArgumentInfo[] schema, | ||
InvokeCallableNode.DefaultsExecutionMode defaultsExecutionMode, | ||
InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode, | ||
BaseNode.TailStatus isTail, | ||
@CachedLibrary(limit = "10") MethodDispatchLibrary methods, | ||
@CachedLibrary(limit = "1") MethodDispatchLibrary textDispatch, | ||
@CachedLibrary(limit = "10") InteropLibrary interop, | ||
@Cached ConditionProfile atomProfile, | ||
@Cached ConditionProfile atomConstructorProfile, | ||
@CachedContext(Language.class) TruffleLanguage.ContextReference<Context> ctx, | ||
@Cached IndirectInvokeFunctionNode indirectInvokeFunctionNode) { | ||
try { | ||
String str = interop.asString(that); | ||
Text txt = Text.create(str); | ||
Function function = | ||
textDispatch.getConversionFunction( | ||
txt, | ||
InvokeConversionNode.extractConstructor( | ||
this, _this, ctx, atomConstructorProfile, atomProfile), | ||
conversion); | ||
arguments[0] = txt; | ||
return indirectInvokeFunctionNode.execute( | ||
function, | ||
frame, | ||
state, | ||
arguments, | ||
schema, | ||
defaultsExecutionMode, | ||
argumentsExecutionMode, | ||
isTail); | ||
} catch (UnsupportedMessageException e) { | ||
throw new IllegalStateException("Impossible, that is guaranteed to be a string."); | ||
} catch (MethodDispatchLibrary.NoSuchConversionException e) { | ||
throw new PanicException( | ||
ctx.get().getBuiltins().error().makeNoSuchConversionError(_this, that, conversion), this); | ||
} | ||
} | ||
|
||
@Specialization( | ||
guards = { | ||
"!methods.canConvertFrom(that)", | ||
"!interop.isString(that)", | ||
"!methods.hasSpecialConversion(that)" | ||
}) | ||
Stateful doFallback( | ||
MaterializedFrame frame, | ||
Object state, | ||
UnresolvedConversion conversion, | ||
Object _this, | ||
Object that, | ||
Object[] arguments, | ||
CallArgumentInfo[] schema, | ||
InvokeCallableNode.DefaultsExecutionMode defaultsExecutionMode, | ||
InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode, | ||
BaseNode.TailStatus isTail, | ||
@CachedLibrary(limit = "10") MethodDispatchLibrary methods, | ||
@CachedLibrary(limit = "10") InteropLibrary interop, | ||
@CachedContext(Language.class) Context ctx) { | ||
throw new PanicException( | ||
ctx.getBuiltins().error().makeNoSuchConversionError(_this, that, conversion), this); | ||
} | ||
} |
102 changes: 102 additions & 0 deletions
102
...e/runtime/src/main/java/org/enso/interpreter/node/callable/InteropConversionCallNode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
package org.enso.interpreter.node.callable; | ||
|
||
import com.oracle.truffle.api.CompilerDirectives; | ||
import com.oracle.truffle.api.dsl.Cached; | ||
import com.oracle.truffle.api.dsl.CachedContext; | ||
import com.oracle.truffle.api.dsl.GenerateUncached; | ||
import com.oracle.truffle.api.dsl.Specialization; | ||
import com.oracle.truffle.api.interop.ArityException; | ||
import com.oracle.truffle.api.nodes.ExplodeLoop; | ||
import com.oracle.truffle.api.nodes.Node; | ||
import com.oracle.truffle.api.nodes.NodeInfo; | ||
import org.enso.interpreter.Constants; | ||
import org.enso.interpreter.Language; | ||
import org.enso.interpreter.node.BaseNode.TailStatus; | ||
import org.enso.interpreter.node.callable.InvokeCallableNode.ArgumentsExecutionMode; | ||
import org.enso.interpreter.node.callable.InvokeCallableNode.DefaultsExecutionMode; | ||
import org.enso.interpreter.node.callable.InvokeConversionNode; | ||
import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode; | ||
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.CallArgumentInfo; | ||
|
||
/** A helper node to handle conversion application for the interop library. */ | ||
@GenerateUncached | ||
@NodeInfo(description = "Helper node to handle conversion application through the interop library.") | ||
public abstract class InteropConversionCallNode extends Node { | ||
|
||
public static InteropConversionCallNode build() { | ||
return InteropConversionCallNodeGen.create(); | ||
} | ||
|
||
public abstract Object execute(UnresolvedConversion conversion, Object state, Object[] arguments) | ||
throws ArityException; | ||
|
||
@CompilerDirectives.TruffleBoundary | ||
CallArgumentInfo[] buildSchema(int length) { | ||
CallArgumentInfo[] args = new CallArgumentInfo[length]; | ||
for (int i = 0; i < length; i++) { | ||
args[i] = new CallArgumentInfo(); | ||
} | ||
return args; | ||
} | ||
|
||
@CompilerDirectives.TruffleBoundary | ||
InvokeConversionNode buildInvoker(int length) { | ||
CallArgumentInfo[] args = buildSchema(length); | ||
return InvokeConversionNode.build( | ||
args, | ||
DefaultsExecutionMode.EXECUTE, | ||
ArgumentsExecutionMode.PRE_EXECUTED); | ||
} | ||
|
||
@Specialization( | ||
guards = {"!context.isInlineCachingDisabled()", "arguments.length == cachedArgsLength"}, | ||
limit = Constants.CacheSizes.FUNCTION_INTEROP_LIBRARY) | ||
@ExplodeLoop | ||
Object callCached( | ||
UnresolvedConversion conversion, | ||
Object state, | ||
Object[] arguments, | ||
@CachedContext(Language.class) Context context, | ||
@Cached("arguments.length") int cachedArgsLength, | ||
@Cached("buildInvoker(cachedArgsLength)") InvokeConversionNode invokerNode, | ||
@Cached("build()") HostValueToEnsoNode hostValueToEnsoNode) | ||
throws ArityException { | ||
Object[] args = new Object[cachedArgsLength]; | ||
for (int i = 0; i < cachedArgsLength; i++) { | ||
args[i] = hostValueToEnsoNode.execute(arguments[i]); | ||
} | ||
if (cachedArgsLength < 2) throw ArityException.create(2, cachedArgsLength); | ||
return invokerNode.execute(null, state, conversion, args[0], args[1], args).getValue(); | ||
} | ||
|
||
@Specialization(replaces = "callCached") | ||
Object callUncached( | ||
UnresolvedConversion conversion, | ||
Object state, | ||
Object[] arguments, | ||
@Cached IndirectInvokeConversionNode indirectInvokeConversionNode, | ||
@Cached("build()") HostValueToEnsoNode hostValueToEnsoNode) | ||
throws ArityException { | ||
Object[] args = new Object[arguments.length]; | ||
for (int i = 0; i < arguments.length; i++) { | ||
args[i] = hostValueToEnsoNode.execute(arguments[i]); | ||
} | ||
if (arguments.length < 2) throw ArityException.create(2, arguments.length); | ||
return indirectInvokeConversionNode | ||
.execute( | ||
null, | ||
state, | ||
conversion, | ||
args[0], | ||
args[1], | ||
args, | ||
buildSchema(arguments.length), | ||
DefaultsExecutionMode.EXECUTE, | ||
ArgumentsExecutionMode.PRE_EXECUTED, | ||
TailStatus.NOT_TAIL) | ||
.getValue(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.