-
Notifications
You must be signed in to change notification settings - Fork 328
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
Use BuiltinRootNode.ArgNode
to extract argument for a builtin method
#12201
Changes from 15 commits
e261e8d
5847b0f
b646932
20fa9c3
731f3bb
ecb74c5
0925fa2
24fe8da
f60457c
feb75d0
8f652cb
01be17a
f0480f7
e2571a1
91d3584
847bd99
7be3262
d6d859a
4ca2226
13fc5fe
3579139
934deae
e3ee0ea
f211c19
54751cb
68a654b
7364a34
0a3ec13
21d9bc3
e6af654
560e6b7
5443128
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,39 @@ | ||
package org.enso.interpreter.node.expression.builtin; | ||
|
||
import com.oracle.truffle.api.CompilerDirectives; | ||
import com.oracle.truffle.api.dsl.Cached; | ||
import com.oracle.truffle.api.dsl.Fallback; | ||
import com.oracle.truffle.api.dsl.Specialization; | ||
import com.oracle.truffle.api.frame.VirtualFrame; | ||
import com.oracle.truffle.api.interop.TruffleObject; | ||
import com.oracle.truffle.api.interop.UnsupportedMessageException; | ||
import com.oracle.truffle.api.nodes.Node; | ||
import com.oracle.truffle.api.nodes.NodeInfo; | ||
import com.oracle.truffle.api.nodes.RootNode; | ||
import org.enso.interpreter.EnsoLanguage; | ||
import org.enso.interpreter.runtime.EnsoContext; | ||
import org.enso.interpreter.runtime.data.EnsoMultiValue; | ||
import org.enso.interpreter.runtime.data.Type; | ||
import org.enso.interpreter.runtime.data.hash.EnsoHashMap; | ||
import org.enso.interpreter.runtime.data.hash.HashMapInsertAllNode; | ||
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.warning.AppendWarningNode; | ||
import org.enso.interpreter.runtime.warning.WarningsLibrary; | ||
import org.enso.interpreter.runtime.warning.WithWarnings; | ||
import org.enso.pkg.QualifiedName; | ||
|
||
/** Root node for use by all the builtin functions. */ | ||
@NodeInfo(shortName = "BuiltinRoot", description = "Root node for builtin functions.") | ||
public abstract class BuiltinRootNode extends RootNode { | ||
private QualifiedName moduleName; | ||
private QualifiedName typeName; | ||
|
||
protected BuiltinRootNode(EnsoLanguage language) { | ||
super(language); | ||
} | ||
|
||
protected QualifiedName moduleName = null; | ||
protected QualifiedName typeName = null; | ||
|
||
/** Get the module name where the builtin is defined. */ | ||
public QualifiedName getModuleName() { | ||
return moduleName; | ||
|
@@ -52,4 +70,161 @@ public void setTypeName(QualifiedName typeName) { | |
*/ | ||
@Override | ||
public abstract String getName(); | ||
|
||
protected static final class ArgContext { | ||
private TruffleObject returnValue; | ||
private EnsoHashMap warnings; | ||
|
||
public ArgContext() {} | ||
|
||
public TruffleObject getReturnValue() { | ||
return returnValue; | ||
} | ||
|
||
public boolean hasWarnings() { | ||
return this.warnings != null; | ||
} | ||
|
||
private void addWarnings( | ||
VirtualFrame frame, HashMapInsertAllNode insertNode, EnsoHashMap newWarnings) { | ||
if (this.warnings == null) { | ||
this.warnings = newWarnings; | ||
} else { | ||
int maxWarnings = EnsoContext.get(insertNode).getWarningsLimit(); | ||
this.warnings = insertNode.executeInsertAll(frame, this.warnings, newWarnings, maxWarnings); | ||
} | ||
} | ||
} | ||
|
||
protected abstract static class ArgNode extends Node { | ||
private static final byte IS_SELF = 0x01; | ||
private static final byte IS_ARRAY = 0x02; | ||
private static final byte REQUIRES_CAST = 0x04; | ||
private static final byte CHECK_ERRORS = 0x08; | ||
private static final byte CHECK_PANIC_SENTINEL = 0x10; | ||
private static final byte CHECK_WARNINGS = 0x20; | ||
private final byte flags; | ||
@CompilerDirectives.CompilationFinal private Type ensoType; | ||
|
||
@Child private WarningsLibrary warnings; | ||
@Child private AppendWarningNode appendWarningNode; | ||
@Child private HashMapInsertAllNode mapInsertAllNode; | ||
|
||
ArgNode(byte flags) { | ||
this.flags = flags; | ||
if (is(CHECK_WARNINGS)) { | ||
this.warnings = WarningsLibrary.getFactory().createDispatched(5); | ||
} | ||
} | ||
|
||
private boolean is(byte what) { | ||
return (flags & what) != 0; | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
public final <T> T processArgument( | ||
VirtualFrame frame, Class<T> type, Object value, ArgContext context) { | ||
assert value != null; | ||
if (is(CHECK_ERRORS) && value instanceof DataflowError err) { | ||
context.returnValue = err; | ||
return null; | ||
} | ||
if (is(CHECK_PANIC_SENTINEL) && value instanceof PanicSentinel sentinel) { | ||
throw sentinel.getPanic(); | ||
} | ||
if (warnings != null) { | ||
if (value instanceof WithWarnings ww) { | ||
if (mapInsertAllNode == null) { | ||
CompilerDirectives.transferToInterpreterAndInvalidate(); | ||
this.mapInsertAllNode = insert(HashMapInsertAllNode.build()); | ||
} | ||
if (this.mapInsertAllNode != null) { | ||
JaroslavTulach marked this conversation as resolved.
Show resolved
Hide resolved
|
||
try { | ||
context.addWarnings(frame, mapInsertAllNode, warnings.getWarnings(value, false)); | ||
value = warnings.removeWarnings(value); | ||
} catch (UnsupportedMessageException ex) { | ||
throw raise(RuntimeException.class, ex); | ||
} | ||
} | ||
} | ||
} | ||
if (is(REQUIRES_CAST)) { | ||
var ctx = EnsoContext.get(this); | ||
if (this.ensoType == null) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The first time Opinions? |
||
CompilerDirectives.transferToInterpreterAndInvalidate(); | ||
var builtin = ctx.getBuiltins().getByRepresentationType(type); | ||
if (builtin == null) { | ||
this.ensoType = ctx.getBuiltins().any(); | ||
} else { | ||
this.ensoType = builtin.getType(); | ||
} | ||
} | ||
var conv = executeConversion(value); | ||
if (conv == null) { | ||
CompilerDirectives.transferToInterpreter(); | ||
var err = ctx.getBuiltins().error().makeTypeError(this.ensoType, value, type.getName()); | ||
throw new PanicException(err, this); | ||
} | ||
return type.cast(conv); | ||
} else { | ||
return type.cast(value); | ||
} | ||
} | ||
|
||
public final Object processWarnings(VirtualFrame frame, Object result, ArgContext context) { | ||
assert context.warnings != null; | ||
if (this.appendWarningNode == null) { | ||
CompilerDirectives.transferToInterpreterAndInvalidate(); | ||
this.appendWarningNode = insert(AppendWarningNode.build()); | ||
} | ||
return appendWarningNode.executeAppend(frame, result, context.warnings); | ||
} | ||
|
||
abstract Object executeConversion(Object obj); | ||
|
||
@Specialization | ||
final Object extractMultiValue(EnsoMultiValue emv, @Cached EnsoMultiValue.CastToNode castTo) { | ||
var extracted = castTo.findTypeOrNull(ensoType, emv, false, false); | ||
return extracted; | ||
} | ||
|
||
@Fallback | ||
final Object justReturnIt(Object obj) { | ||
return obj; | ||
} | ||
|
||
public static ArgNode create( | ||
boolean isSelf, | ||
JaroslavTulach marked this conversation as resolved.
Show resolved
Hide resolved
|
||
boolean isArray, | ||
boolean requiresCast, | ||
boolean checkErrors, | ||
boolean checkPanicSentinel, | ||
boolean checkWarnings) { | ||
byte flags = 0x00; | ||
if (isSelf) { | ||
flags |= IS_SELF; | ||
} | ||
if (isArray) { | ||
flags |= IS_ARRAY; | ||
JaroslavTulach marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
if (requiresCast) { | ||
flags |= REQUIRES_CAST; | ||
} | ||
if (checkErrors) { | ||
flags |= CHECK_ERRORS; | ||
} | ||
if (checkPanicSentinel) { | ||
flags |= CHECK_PANIC_SENTINEL; | ||
} | ||
if (checkWarnings) { | ||
flags |= CHECK_WARNINGS; | ||
} | ||
return BuiltinRootNodeFactory.ArgNodeGen.create(flags); | ||
} | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
private static <E extends Exception> E raise(Class<E> clazz, Throwable t) throws E { | ||
throw (E) t; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,4 +3,8 @@ | |
import org.enso.interpreter.dsl.BuiltinType; | ||
|
||
@BuiltinType | ||
public class Polyglot extends Builtin {} | ||
public final class Polyglot extends Builtin { | ||
public Polyglot() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd say we have way too many |
||
super(Object.class); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now we attempt to provide a
representationType
to eachBuiltin
. That way we can deduce from signature methods having argument likeboolean
that the desired builtin isBoolean
and the Enso type should beStandard.Base.Data.Boolean.Boolean
. With that information we can extract (viaCastToNode
) such a type fromEnsoMultiValue
....