Map Implementation (#1222)

This commit is contained in:
Marcin Kostrzewa 2020-10-20 13:43:04 +02:00 committed by GitHub
parent 989aa4b7d7
commit 207aaaccf5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 517 additions and 107 deletions

View File

@ -1,3 +1,3 @@
COMP_PATH=$(dirname "$0")/../component COMP_PATH=$(dirname "$0")/../component
exec java -jar -Dtruffle.class.path.append="$COMP_PATH/runtime.jar" -Dpolyglot.engine.IterativePartialEscape=true $JAVA_OPTS $COMP_PATH/runner.jar "$@" exec java -jar -Dtruffle.class.path.append="$COMP_PATH/runtime.jar" $JAVA_OPTS $COMP_PATH/runner.jar "$@"
exit exit

View File

@ -0,0 +1,79 @@
from Base import all
import Base.Data.Map.Internal
## An error for getting a missing value from a map.
type No_Value_For_Key key
## A key-value store. This type assumes all keys are pairwise comparable,
using the `<`, `>` and `==` operators.
type Map
type Tip
type Bin s key value left right
## Checks if the map is empty.
is_empty : Boolean
is_empty = case this of
Bin _ _ _ _ _ -> False
Tip -> True
## Returns the number of entries in this map.
size : Integer
size = case this of
Bin s _ _ _ _ -> s
Tip -> 0
## Converts the map into a vector of `[key, value]` pairs.
The returned vector is sorted in the increasing order of keys.
to_vector : Vector
to_vector =
builder = Vector.new_builder
to_vector_with_builder m = case m of
Bin _ k v l r ->
to_vector_with_builder l
builder.append [k, v]
to_vector_with_builder r
Unit
Tip -> Unit
to_vector_with_builder this
result = builder.to_vector
result
## Returns a text representation of this map.
to_text : Text
to_text = this.to_vector.to_text
## Checks if this map is equal to another map.
Maps are equal when they contained the same keys and the values
associated with each key are pairwise equal.
== : Map -> Boolean
== that = this.to_vector == that.to_vector
## Maps a function over each value in this map.
map : (Any -> Any) -> Map
map function = case this of
Bin s k v l r ->
Bin s k (function v) (l.map function) (r.map function)
Tip -> Tip
## Gets the value associated with `key` in this map, or returns a
`No_Value_For_Key` error, if `key` is not present.
get : Any -> Any ! No_Value_For_Key
get key =
go map = case map of
Tip -> Error.throw (No_Value_For_Key key)
Bin _ k v l r ->
if k == key then v else
if k > key then @Tail_Call go l else @Tail_Call go r
result = go this
result
## Inserts a key-value mapping into this map. If `key` is already present,
it will be overriden with the new `value`.
insert : Any -> Any -> Map
insert key value = Internal.insert this key value
## Returns an empty map.
empty : Map
empty = Tip

View File

@ -0,0 +1,113 @@
from Base import all
from Base.Data.Map import all
## PRIVATE
Helper used in the insert operation.
insert_l key value k v l r =
new_left = here.insert l key value
here.balance_left k v new_left r
## PRIVATE
Helper used in the insert operation.
insert_r key value k v l r =
new_right = here.insert r key value
here.balance_right k v l new_right
## PRIVATE
Helper for inserting a new key-value pair into a map.
The algorithm used here is based on the paper "Implementing Sets Efficiently
in a Functional Language" by Stephen Adams.
Implementation is based on Haskell's `Data.Map.Strict` implemented in the
`containers` package.
insert map key value = case map of
Bin s k v l r ->
if key > k then @Tail_Call here.insert_r key value k v l r else
if key == k then @Tail_Call Bin s k value l r else
@Tail_Call here.insert_l key value k v l r
_ -> Bin 1 key value Tip Tip
## PRIVATE
Rebalances the map after the left subtree grows.
balance_left k x l r = case r of
Bin rs _ _ _ _ -> case l of
Bin ls lk lx ll lr ->
if ls <= Delta*rs then Bin 1+ls+rs k x l r else
lls = here.size ll
case lr of
Bin lrs lrk lrx lrl lrr ->
if lrs < Ratio*lls then Bin 1+ls+rs lk lx ll (Bin 1+rs+lrs k x lr r) else
lrls = here.size lrl
lrrs = here.size lrr
Bin 1+ls+rs lrk lrx (Bin 1+lls+lrls lk lx ll lrl) (Bin 1+rs+lrrs k x lrr r)
_ -> Bin 1+rs k x Tip r
_ -> case l of
Tip -> Bin 1 k x Tip Tip
Bin _ _ _ Tip Tip -> Bin 2 k x l Tip
Bin _ lk lx Tip (Bin _ lrk lrx _ _) -> Bin 3 lrk lrx (Bin 1 lk lx Tip Tip) (Bin 1 k x Tip Tip)
Bin _ lk lx ll Tip -> Bin 3 lk lx ll (Bin 1 k x Tip Tip)
Bin ls lk lx ll lr -> case lr of
Bin lrs lrk lrx lrl lrr ->
lls = here.size ll
if lrs < Ratio*lls then Bin 1+ls lk lx ll (Bin 1+lrs k x lr Tip) else
lrls = here.size lrl
lrrs = here.size lrr
Bin 1+ls lrk lrx (Bin 1+lls+lrls lk lx ll lrl) (Bin 1+lrrs k x lrr Tip)
## PRIVATE
Rebalances the map after the right subtree grows.
balance_right k x l r = case l of
Bin ls _ _ _ _ -> case r of
Bin rs rk rx rl rr ->
if rs <= Delta*ls then Bin 1+ls+rs k x l r else
case rl of
Bin rls rlk rlx rll rlr ->
rrs = here.size rr
if rls < Ratio*rrs then Bin 1+ls+rs rk rx (Bin 1+ls+rls k x l rl) rr else
rlls = here.size rll
rlrs = here.size rlr
Bin 1+ls+rs rlk rlx (Bin 1+ls+rlls k x l rll) (Bin 1+rrs+rlrs rk rx rlr rr)
_ -> Bin 1+ls k x l Tip
_ -> case r of
Tip -> Bin 1 k x Tip Tip
Bin _ _ _ Tip Tip -> Bin 2 k x Tip r
Bin _ rk rx Tip rr -> Bin 3 rk rx (Bin 1 k x Tip Tip) rr
Bin _ rk rx (Bin _ rlk rlx _ _) Tip -> Bin 3 rlk rlx (Bin 1 k x Tip Tip) (Bin 1 rk rx Tip Tip)
Bin rs rk rx (Bin rls rlk rlx rll rlr) rr -> case rr of
Bin rrs _ _ _ _ ->
if rls < Ratio*rrs then Bin 1+rs rk rx (Bin 1+rls k x Tip rl) rr else
srll = here.size rll
srlr = here.size rlr
Bin 1+rs rlk rlx (Bin 1+srll k x Tip rll) (Bin 1+rrs+srlr rk rx rlr rr)
## PRIVATE
Controls the difference between inner and outer siblings of a heavy subtree.
Used to decide between a double and a single rotation.
The choice of values for `ratio` and `delta` is taken from the Haskell
implementation.
ratio : Integer
ratio = 2
## PRIVATE
Controls the maximum size difference between subtrees.
The choice of values for `ratio` and `delta` is taken from the Haskell
implementation.
delta : Integer
delta = 3
## PRIVATE
Gets the size of a map.
size m = case m of
Bin s _ _ _ _ -> s
_ -> 0

View File

@ -7,11 +7,13 @@ import Base.Meta.Enso_Project
import Base.Meta.Meta import Base.Meta.Meta
import Base.Error.Extensions import Base.Error.Extensions
import Base.Polyglot.Java import Base.Polyglot.Java
import Base.Data.Map
from Builtins import Unit, Number, Integer, Any, True, False, Cons from Builtins import Unit, Number, Integer, Any, True, False, Cons
export Base.Meta.Meta export Base.Meta.Meta
from Builtins export all hiding Meta from Builtins export all hiding Meta
export Base.Data.Map
from Base.Meta.Enso_Project export all from Base.Meta.Enso_Project export all
from Base.List export Nil, Cons from Base.List export Nil, Cons
from Base.Vector export Vector from Base.Vector export Vector

View File

@ -38,7 +38,7 @@ type Verbs
equal subject argument = equal subject argument =
if subject == argument then Success else if subject == argument then Success else
msg = this.to_text + " did not equal " + that.to_text + "." msg = this.to_text + " did not equal " + argument.to_text + "."
here.fail msg here.fail msg
be subject argument = this.equal subject argument be subject argument = this.equal subject argument

View File

@ -69,6 +69,14 @@ Text.split_at separator =
Text.== : Text -> Boolean Text.== : Text -> Boolean
Text.== that = Text_Utils.equals [this, that] Text.== that = Text_Utils.equals [this, that]
## Checks if `this` is lexicographically before `that`.
Text.< : Text -> Boolean
Text.< that = Text_Utils.lt [this, that]
## Checks if `this` is lexicographically after `that`.
Text.> : Text -> Boolean
Text.> that = Text_Utils.lt [that, this]
## Returns a vector containing bytes representing the UTF-8 encoding of the ## Returns a vector containing bytes representing the UTF-8 encoding of the
input text. input text.
@ -103,4 +111,5 @@ Text.from_codepoints : Vector -> Text
Text.from_codepoints codepoints = Text_Utils.from_codepoints [codepoints.to_array] Text.from_codepoints codepoints = Text_Utils.from_codepoints [codepoints.to_array]
## Checks whether `this` starts with `prefix`. ## Checks whether `this` starts with `prefix`.
Text.starts_with : Text -> Boolean
Text.starts_with prefix = Text_Utils.starts_with [this, prefix] Text.starts_with prefix = Text_Utils.starts_with [this, prefix]

View File

@ -1,17 +1,10 @@
package org.enso.interpreter.bench.benchmarks.semantic; package org.enso.interpreter.bench.benchmarks.semantic;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.TimeUnit;
import org.enso.interpreter.bench.fixtures.semantic.RecursionFixtures; import org.enso.interpreter.bench.fixtures.semantic.RecursionFixtures;
import org.enso.interpreter.test.DefaultInterpreterRunner; import org.enso.interpreter.test.DefaultInterpreterRunner;
import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork; import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Warmup;
@BenchmarkMode(Mode.AverageTime) @BenchmarkMode(Mode.AverageTime)
@Fork(1) @Fork(1)

View File

@ -119,7 +119,7 @@ public abstract class IndirectInvokeCallableNode extends Node {
Object selfArgument = arguments[thisArgumentPosition]; Object selfArgument = arguments[thisArgumentPosition];
if (argumentsExecutionMode.shouldExecute()) { if (argumentsExecutionMode.shouldExecute()) {
Stateful selfResult = Stateful selfResult =
thisExecutor.executeThunk((Thunk) selfArgument, state, BaseNode.TailStatus.NOT_TAIL); thisExecutor.executeThunk(selfArgument, state, BaseNode.TailStatus.NOT_TAIL);
selfArgument = selfResult.getValue(); selfArgument = selfResult.getValue();
state = selfResult.getState(); state = selfResult.getState();
arguments[thisArgumentPosition] = selfArgument; arguments[thisArgumentPosition] = selfArgument;

View File

@ -185,8 +185,7 @@ public abstract class InvokeCallableNode extends BaseNode {
lock.unlock(); lock.unlock();
} }
} }
Stateful selfResult = Stateful selfResult = thisExecutor.executeThunk(selfArgument, state, TailStatus.NOT_TAIL);
thisExecutor.executeThunk((Thunk) selfArgument, state, TailStatus.NOT_TAIL);
selfArgument = selfResult.getValue(); selfArgument = selfResult.getValue();
state = selfResult.getState(); state = selfResult.getState();
arguments[thisArgumentPosition] = selfArgument; arguments[thisArgumentPosition] = selfArgument;

View File

@ -55,11 +55,11 @@ public class ArgumentSorterNode extends BaseNode {
preApplicationSchema, mapping.getPostApplicationSchema(), mapping, argumentsExecutionMode); preApplicationSchema, mapping.getPostApplicationSchema(), mapping, argumentsExecutionMode);
} }
private void initArgumentExecutors(Object[] arguments) { private void initArgumentExecutors() {
ThunkExecutorNode[] executors = ThunkExecutorNode[] executors =
new ThunkExecutorNode[mapping.getArgumentShouldExecute().length]; new ThunkExecutorNode[mapping.getArgumentShouldExecute().length];
for (int i = 0; i < mapping.getArgumentShouldExecute().length; i++) { for (int i = 0; i < mapping.getArgumentShouldExecute().length; i++) {
if (mapping.getArgumentShouldExecute()[i] && TypesGen.isThunk(arguments[i])) { if (mapping.getArgumentShouldExecute()[i]) {
executors[i] = insert(ThunkExecutorNode.build()); executors[i] = insert(ThunkExecutorNode.build());
} }
} }
@ -74,7 +74,7 @@ public class ArgumentSorterNode extends BaseNode {
lock.lock(); lock.lock();
try { try {
if (executors == null) { if (executors == null) {
initArgumentExecutors(arguments); initArgumentExecutors();
} }
} finally { } finally {
lock.unlock(); lock.unlock();
@ -82,8 +82,7 @@ public class ArgumentSorterNode extends BaseNode {
} }
for (int i = 0; i < mapping.getArgumentShouldExecute().length; i++) { for (int i = 0; i < mapping.getArgumentShouldExecute().length; i++) {
if (executors[i] != null) { if (executors[i] != null) {
Stateful result = Stateful result = executors[i].executeThunk(arguments[i], state, TailStatus.NOT_TAIL);
executors[i].executeThunk(TypesGen.asThunk(arguments[i]), state, TailStatus.NOT_TAIL);
arguments[i] = result.getValue(); arguments[i] = result.getValue();
state = result.getState(); state = result.getState();
} }

View File

@ -30,7 +30,7 @@ public abstract class ForceNode extends ExpressionNode {
@Specialization @Specialization
Object passToExecutorNode( Object passToExecutorNode(
VirtualFrame frame, VirtualFrame frame,
Thunk thunk, Object thunk,
@Cached("build()") ThunkExecutorNode thunkExecutorNode) { @Cached("build()") ThunkExecutorNode thunkExecutorNode) {
Object state = FrameUtil.getObjectSafe(frame, getStateFrameSlot()); Object state = FrameUtil.getObjectSafe(frame, getStateFrameSlot());
Stateful result = thunkExecutorNode.executeThunk(thunk, state, getTailStatus()); Stateful result = thunkExecutorNode.executeThunk(thunk, state, getTailStatus());

View File

@ -12,6 +12,7 @@ import org.enso.interpreter.runtime.callable.argument.Thunk;
import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.control.TailCallException; import org.enso.interpreter.runtime.control.TailCallException;
import org.enso.interpreter.runtime.state.Stateful; 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. */ /** Node responsible for executing (forcing) thunks passed to it as runtime values. */
@GenerateUncached @GenerateUncached
@ -37,7 +38,16 @@ public abstract class ThunkExecutorNode extends Node {
* @param isTail is the execution happening in a tail-call position * @param isTail is the execution happening in a tail-call position
* @return the return value of this thunk * @return the return value of this thunk
*/ */
public abstract Stateful executeThunk(Thunk thunk, Object state, BaseNode.TailStatus isTail); 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);
}
@Specialization( @Specialization(
guards = "callNode.getCallTarget() == thunk.getCallTarget()", guards = "callNode.getCallTarget() == thunk.getCallTarget()",

View File

@ -1,9 +1,11 @@
package org.enso.interpreter.node.controlflow; package org.enso.interpreter.node.controlflow;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.FrameUtil; import com.oracle.truffle.api.frame.FrameUtil;
import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.DirectCallNode;
import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.profiles.ConditionProfile;
import org.enso.interpreter.node.ExpressionNode; import org.enso.interpreter.node.ExpressionNode;
@ -13,19 +15,19 @@ import org.enso.interpreter.node.callable.function.CreateFunctionNode;
import org.enso.interpreter.runtime.callable.atom.Atom; import org.enso.interpreter.runtime.callable.atom.Atom;
import org.enso.interpreter.runtime.callable.atom.AtomConstructor; import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen; import org.enso.interpreter.runtime.type.TypesGen;
/** An implementation of the case expression specialised to working on booleans. */ /** An implementation of the case expression specialised to working on booleans. */
@NodeInfo(shortName = "BooleanMatch") @NodeInfo(shortName = "BooleanMatch")
public abstract class BooleanBranchNode extends BranchNode { public abstract class BooleanBranchNode extends BranchNode {
private final boolean matched; private final boolean matched;
private @Child ExpressionNode branch;
private @Child ExecuteCallNode executeCallNode = ExecuteCallNodeGen.create();
private final ConditionProfile profile = ConditionProfile.createCountingProfile(); private final ConditionProfile profile = ConditionProfile.createCountingProfile();
private @Child DirectCallNode callNode;
BooleanBranchNode(boolean matched, CreateFunctionNode branch) { BooleanBranchNode(boolean matched, RootCallTarget branch) {
this.matched = matched; this.matched = matched;
this.branch = branch; this.callNode = DirectCallNode.create(branch);
} }
/** /**
@ -35,7 +37,7 @@ public abstract class BooleanBranchNode extends BranchNode {
* @param branch the expression to be executed if (@code matcher} matches * @param branch the expression to be executed if (@code matcher} matches
* @return a node for matching in a case expression * @return a node for matching in a case expression
*/ */
public static BooleanBranchNode build(boolean matched, CreateFunctionNode branch) { public static BooleanBranchNode build(boolean matched, RootCallTarget branch) {
return BooleanBranchNodeGen.create(matched, branch); return BooleanBranchNodeGen.create(matched, branch);
} }
@ -43,17 +45,19 @@ public abstract class BooleanBranchNode extends BranchNode {
* Handles the boolean scrutinee case. * Handles the boolean scrutinee case.
* *
* @param frame the stack frame in which to execute * @param frame the stack frame in which to execute
* @param state current monadic state
* @param target the atom to destructure * @param target the atom to destructure
*/ */
@Specialization @Specialization
public void doAtom(VirtualFrame frame, boolean target) { public void doAtom(VirtualFrame frame, Object state, boolean target) {
Object state = FrameUtil.getObjectSafe(frame, getStateFrameSlot());
if (profile.profile(matched == target)) { if (profile.profile(matched == target)) {
Function function = TypesGen.asFunction(branch.executeGeneric(frame)); Stateful result =
(Stateful)
callNode.call(
Function.ArgumentsHelper.buildArguments(
frame.materialize(), state, new Object[0]));
// Note [Caller Info For Case Branches] // Note [Caller Info For Case Branches]
throw new BranchSelectedException( throw new BranchSelectedException(result);
executeCallNode.executeCall(function, null, state, new Object[0]));
} }
} }
@ -64,7 +68,7 @@ public abstract class BooleanBranchNode extends BranchNode {
* @param target the object to execute on * @param target the object to execute on
*/ */
@Fallback @Fallback
public void doFallback(VirtualFrame frame, Object target) {} public void doFallback(VirtualFrame frame, Object state, Object target) {}
/* Note [Caller Info For Case Branches] /* Note [Caller Info For Case Branches]
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -15,7 +15,8 @@ public abstract class BranchNode extends BaseNode {
* Executes the case branch. * Executes the case branch.
* *
* @param frame the stack frame in which to execute * @param frame the stack frame in which to execute
* @param state current monadic state
* @param target the object to match against * @param target the object to match against
*/ */
public abstract void execute(VirtualFrame frame, Object target); public abstract void execute(VirtualFrame frame, Object state, Object target);
} }

View File

@ -3,13 +3,12 @@ package org.enso.interpreter.node.controlflow;
import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.dsl.CachedContext; import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.ImportStatic;
import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.FrameUtil;
import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Language; import org.enso.interpreter.Language;
import org.enso.interpreter.node.ExpressionNode; import org.enso.interpreter.node.ExpressionNode;
import org.enso.interpreter.runtime.Context; import org.enso.interpreter.runtime.Context;
@ -29,7 +28,6 @@ import org.enso.interpreter.runtime.type.TypesGen;
public abstract class CaseNode extends ExpressionNode { public abstract class CaseNode extends ExpressionNode {
@Children private final BranchNode[] cases; @Children private final BranchNode[] cases;
private final BranchProfile typeErrorProfile = BranchProfile.create();
CaseNode(BranchNode[] cases) { CaseNode(BranchNode[] cases) {
this.cases = cases; this.cases = cases;
@ -74,9 +72,10 @@ public abstract class CaseNode extends ExpressionNode {
VirtualFrame frame, VirtualFrame frame,
Object object, Object object,
@CachedContext(Language.class) TruffleLanguage.ContextReference<Context> ctx) { @CachedContext(Language.class) TruffleLanguage.ContextReference<Context> ctx) {
Object state = FrameUtil.getObjectSafe(frame, getStateFrameSlot());
try { try {
for (BranchNode branchNode : cases) { for (BranchNode branchNode : cases) {
branchNode.execute(frame, object); branchNode.execute(frame, state, object);
} }
CompilerDirectives.transferToInterpreter(); CompilerDirectives.transferToInterpreter();
throw new PanicException( throw new PanicException(

View File

@ -1,15 +1,19 @@
package org.enso.interpreter.node.controlflow; package org.enso.interpreter.node.controlflow;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.frame.FrameUtil; import com.oracle.truffle.api.frame.FrameUtil;
import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.DirectCallNode;
import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.UnexpectedResultException; import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.profiles.ConditionProfile;
import org.enso.interpreter.node.ExpressionNode; import org.enso.interpreter.node.ExpressionNode;
import org.enso.interpreter.node.callable.ExecuteCallNode; import org.enso.interpreter.node.callable.ExecuteCallNode;
import org.enso.interpreter.node.callable.ExecuteCallNodeGen; import org.enso.interpreter.node.callable.ExecuteCallNodeGen;
import org.enso.interpreter.node.callable.function.CreateFunctionNode; import org.enso.interpreter.node.callable.function.CreateFunctionNode;
import org.enso.interpreter.runtime.callable.atom.Atom; import org.enso.interpreter.runtime.callable.atom.Atom;
import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen; import org.enso.interpreter.runtime.type.TypesGen;
/** /**
@ -20,11 +24,10 @@ import org.enso.interpreter.runtime.type.TypesGen;
shortName = "Catch_All", shortName = "Catch_All",
description = "An explicit catch-all branch in a case expression") description = "An explicit catch-all branch in a case expression")
public class CatchAllBranchNode extends BranchNode { public class CatchAllBranchNode extends BranchNode {
@Child private ExpressionNode functionNode; private @Child DirectCallNode callNode;
@Child private ExecuteCallNode executeCallNode = ExecuteCallNodeGen.create();
private CatchAllBranchNode(CreateFunctionNode functionNode) { private CatchAllBranchNode(RootCallTarget functionNode) {
this.functionNode = functionNode; this.callNode = DirectCallNode.create(functionNode);
} }
/** /**
@ -33,7 +36,7 @@ public class CatchAllBranchNode extends BranchNode {
* @param functionNode the function to execute in this case * @param functionNode the function to execute in this case
* @return a catch-all node * @return a catch-all node
*/ */
public static CatchAllBranchNode build(CreateFunctionNode functionNode) { public static CatchAllBranchNode build(RootCallTarget functionNode) {
return new CatchAllBranchNode(functionNode); return new CatchAllBranchNode(functionNode);
} }
@ -41,15 +44,17 @@ public class CatchAllBranchNode extends BranchNode {
* Executes the case branch on an arbitrary target. * Executes the case branch on an arbitrary target.
* *
* @param frame the stack frame in which to execute * @param frame the stack frame in which to execute
* @param state current monadic state
* @param target the object to match against * @param target the object to match against
*/ */
public void execute(VirtualFrame frame, Object target) { public void execute(VirtualFrame frame, Object state, Object target) {
// Note [Safe Casting to Function in Catch All Branches] // Note [Safe Casting to Function in Catch All Branches]
Function function = TypesGen.asFunction(functionNode.executeGeneric(frame)); Stateful result =
Object state = FrameUtil.getObjectSafe(frame, getStateFrameSlot()); (Stateful)
throw new BranchSelectedException( callNode.call(
// Note [Caller Info For Case Branches] Function.ArgumentsHelper.buildArguments(
executeCallNode.executeCall(function, null, state, new Object[] {target})); frame.materialize(), state, new Object[] {target}));
throw new BranchSelectedException(result);
} }
/* Note [Safe Casting to Function in Catch All Branches] /* Note [Safe Casting to Function in Catch All Branches]

View File

@ -1,11 +1,16 @@
package org.enso.interpreter.node.controlflow; package org.enso.interpreter.node.controlflow;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.FrameUtil; import com.oracle.truffle.api.frame.FrameUtil;
import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.DirectCallNode;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.profiles.ConditionProfile;
import org.enso.compiler.Compiler;
import org.enso.interpreter.node.ExpressionNode; import org.enso.interpreter.node.ExpressionNode;
import org.enso.interpreter.node.callable.ExecuteCallNode; import org.enso.interpreter.node.callable.ExecuteCallNode;
import org.enso.interpreter.node.callable.ExecuteCallNodeGen; import org.enso.interpreter.node.callable.ExecuteCallNodeGen;
@ -13,19 +18,19 @@ import org.enso.interpreter.node.callable.function.CreateFunctionNode;
import org.enso.interpreter.runtime.callable.atom.Atom; import org.enso.interpreter.runtime.callable.atom.Atom;
import org.enso.interpreter.runtime.callable.atom.AtomConstructor; import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen; import org.enso.interpreter.runtime.type.TypesGen;
/** An implementation of the case expression specialised to working on constructors. */ /** An implementation of the case expression specialised to working on constructors. */
@NodeInfo(shortName = "ConstructorMatch") @NodeInfo(shortName = "ConstructorMatch")
public abstract class ConstructorBranchNode extends BranchNode { public abstract class ConstructorBranchNode extends BranchNode {
private final AtomConstructor matcher; private final AtomConstructor matcher;
private @Child ExpressionNode branch; private @Child DirectCallNode callNode;
private @Child ExecuteCallNode executeCallNode = ExecuteCallNodeGen.create();
private final ConditionProfile profile = ConditionProfile.createCountingProfile(); private final ConditionProfile profile = ConditionProfile.createCountingProfile();
ConstructorBranchNode(AtomConstructor matcher, CreateFunctionNode branch) { ConstructorBranchNode(AtomConstructor matcher, RootCallTarget branch) {
this.matcher = matcher; this.matcher = matcher;
this.branch = branch; this.callNode = DirectCallNode.create(branch);
} }
/** /**
@ -35,7 +40,7 @@ public abstract class ConstructorBranchNode extends BranchNode {
* @param branch the expression to be executed if (@code matcher} matches * @param branch the expression to be executed if (@code matcher} matches
* @return a node for matching in a case expression * @return a node for matching in a case expression
*/ */
public static ConstructorBranchNode build(AtomConstructor matcher, CreateFunctionNode branch) { public static ConstructorBranchNode build(AtomConstructor matcher, RootCallTarget branch) {
return ConstructorBranchNodeGen.create(matcher, branch); return ConstructorBranchNodeGen.create(matcher, branch);
} }
@ -46,17 +51,19 @@ public abstract class ConstructorBranchNode extends BranchNode {
* all the atom's fields as arguments. * all the atom's fields as arguments.
* *
* @param frame the stack frame in which to execute * @param frame the stack frame in which to execute
* @param state current monadic state
* @param target the atom to destructure * @param target the atom to destructure
*/ */
@Specialization @Specialization
public void doAtom(VirtualFrame frame, Atom target) { public void doAtom(VirtualFrame frame, Object state, Atom target) {
Object state = FrameUtil.getObjectSafe(frame, getStateFrameSlot());
if (profile.profile(matcher == target.getConstructor())) { if (profile.profile(matcher == target.getConstructor())) {
Function function = TypesGen.asFunction(branch.executeGeneric(frame));
// Note [Caller Info For Case Branches] // Note [Caller Info For Case Branches]
throw new BranchSelectedException( Stateful result =
executeCallNode.executeCall(function, null, state, target.getFields())); (Stateful)
callNode.call(
Function.ArgumentsHelper.buildArguments(
frame.materialize(), state, target.getFields()));
throw new BranchSelectedException(result);
} }
} }
@ -67,7 +74,7 @@ public abstract class ConstructorBranchNode extends BranchNode {
* @param target the object to execute on * @param target the object to execute on
*/ */
@Fallback @Fallback
public void doFallback(VirtualFrame frame, Object target) {} public void doFallback(VirtualFrame frame, Object state, Object target) {}
/* Note [Caller Info For Case Branches] /* Note [Caller Info For Case Branches]
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -1,19 +1,17 @@
package org.enso.interpreter.node.expression.builtin; package org.enso.interpreter.node.expression.builtin;
import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.nodes.RootNode;
import org.enso.interpreter.Language; import org.enso.interpreter.Language;
import org.enso.interpreter.node.ExpressionNode; import org.enso.interpreter.node.ExpressionNode;
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.state.Stateful; import org.enso.interpreter.runtime.state.Stateful;
/** This node represents the process of instantiating an atom at runtime. */ /** This node represents the process of instantiating an atom at runtime. */
@NodeInfo(shortName = "constructor::", description = "An atom instantiation at runtime.") @NodeInfo(shortName = "constructor::", description = "An atom instantiation at runtime.")
public class InstantiateAtomNode extends RootNode { public class InstantiateAtomNode extends RootNode {
private @Node.Child ExpressionNode instantiator; private @Child ExpressionNode instantiator;
private final String name; private final String name;
private InstantiateAtomNode(Language language, String name, ExpressionNode instantiator) { private InstantiateAtomNode(Language language, String name, ExpressionNode instantiator) {
@ -22,7 +20,8 @@ public class InstantiateAtomNode extends RootNode {
this.instantiator = instantiator; this.instantiator = instantiator;
} }
/** Executes this node. /**
* Executes this node.
* *
* @param frame the language frame being executed * @param frame the language frame being executed
* @return the result of executing this node * @return the result of executing this node
@ -34,7 +33,8 @@ public class InstantiateAtomNode extends RootNode {
instantiator.executeGeneric(frame)); instantiator.executeGeneric(frame));
} }
/** Returns a string representation of this node. /**
* Returns a string representation of this node.
* *
* @return a string representation of this node * @return a string representation of this node
*/ */
@ -43,7 +43,8 @@ public class InstantiateAtomNode extends RootNode {
return "constructor::" + name; return "constructor::" + name;
} }
/** Creates an instance of this node. /**
* Creates an instance of this node.
* *
* @param language the language for which the node is created * @param language the language for which the node is created
* @param name the name of the atom being instantated * @param name the name of the atom being instantated

View File

@ -4,6 +4,7 @@ import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.profiles.ConditionProfile;
import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState; import org.enso.interpreter.dsl.MonadicState;
import org.enso.interpreter.dsl.Suspend;
import org.enso.interpreter.node.BaseNode; import org.enso.interpreter.node.BaseNode;
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode; import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
import org.enso.interpreter.runtime.callable.argument.Thunk; import org.enso.interpreter.runtime.callable.argument.Thunk;
@ -18,7 +19,11 @@ public class IfThenElseNode extends Node {
private @Child ThunkExecutorNode rightThunkExecutorNode = ThunkExecutorNode.build(); private @Child ThunkExecutorNode rightThunkExecutorNode = ThunkExecutorNode.build();
private final ConditionProfile condProfile = ConditionProfile.createCountingProfile(); private final ConditionProfile condProfile = ConditionProfile.createCountingProfile();
Stateful execute(@MonadicState Object state, boolean _this, Thunk if_true, Thunk if_false) { Stateful execute(
@MonadicState Object state,
boolean _this,
@Suspend Object if_true,
@Suspend Object if_false) {
if (condProfile.profile(_this)) { if (condProfile.profile(_this)) {
return leftThunkExecutorNode.executeThunk(if_true, state, BaseNode.TailStatus.TAIL_DIRECT); return leftThunkExecutorNode.executeThunk(if_true, state, BaseNode.TailStatus.TAIL_DIRECT);
} else { } else {

View File

@ -7,6 +7,7 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
import org.enso.interpreter.Language; import org.enso.interpreter.Language;
import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState; import org.enso.interpreter.dsl.MonadicState;
import org.enso.interpreter.dsl.Suspend;
import org.enso.interpreter.node.BaseNode; import org.enso.interpreter.node.BaseNode;
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode; import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
import org.enso.interpreter.runtime.Context; import org.enso.interpreter.runtime.Context;
@ -25,11 +26,11 @@ public abstract class IfThenNode extends Node {
return IfThenNodeGen.create(); return IfThenNodeGen.create();
} }
abstract Stateful execute(@MonadicState Object state, boolean _this, Thunk if_true); abstract Stateful execute(@MonadicState Object state, boolean _this, @Suspend Object if_true);
@Specialization @Specialization
Stateful doExecute( Stateful doExecute(
Object state, boolean _this, Thunk if_true, @CachedContext(Language.class) Context context) { Object state, boolean _this, Object if_true, @CachedContext(Language.class) Context context) {
if (condProfile.profile(_this)) { if (condProfile.profile(_this)) {
return leftThunkExecutorNode.executeThunk(if_true, state, BaseNode.TailStatus.TAIL_DIRECT); return leftThunkExecutorNode.executeThunk(if_true, state, BaseNode.TailStatus.TAIL_DIRECT);
} else { } else {

View File

@ -7,6 +7,7 @@ import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.Language; import org.enso.interpreter.Language;
import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState; import org.enso.interpreter.dsl.MonadicState;
import org.enso.interpreter.dsl.Suspend;
import org.enso.interpreter.node.BaseNode; import org.enso.interpreter.node.BaseNode;
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode; import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
import org.enso.interpreter.runtime.Context; import org.enso.interpreter.runtime.Context;
@ -26,13 +27,13 @@ public abstract class CatchPanicNode extends Node {
return CatchPanicNodeGen.create(); return CatchPanicNodeGen.create();
} }
abstract Stateful execute(@MonadicState Object state, Object _this, Thunk action); abstract Stateful execute(@MonadicState Object state, Object _this, @Suspend Object action);
@Specialization @Specialization
Stateful doExecute( Stateful doExecute(
@MonadicState Object state, @MonadicState Object state,
Object _this, Object _this,
Thunk action, Object action,
@CachedContext(Language.class) Context ctx) { @CachedContext(Language.class) Context ctx) {
try { try {
return thunkExecutorNode.executeThunk(action, state, BaseNode.TailStatus.NOT_TAIL); return thunkExecutorNode.executeThunk(action, state, BaseNode.TailStatus.NOT_TAIL);

View File

@ -4,6 +4,7 @@ import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState; import org.enso.interpreter.dsl.MonadicState;
import org.enso.interpreter.dsl.Suspend;
import org.enso.interpreter.node.BaseNode; import org.enso.interpreter.node.BaseNode;
import org.enso.interpreter.node.callable.InvokeCallableNode; import org.enso.interpreter.node.callable.InvokeCallableNode;
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo; import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
@ -27,7 +28,8 @@ public class ApplicationOperator extends Node {
invokeCallableNode.setTailStatus(BaseNode.TailStatus.TAIL_DIRECT); invokeCallableNode.setTailStatus(BaseNode.TailStatus.TAIL_DIRECT);
} }
Stateful execute(VirtualFrame frame, @MonadicState Object state, Function _this, Thunk argument) { Stateful execute(
VirtualFrame frame, @MonadicState Object state, Function _this, @Suspend Object argument) {
return invokeCallableNode.execute(_this, frame, state, new Object[] {argument}); return invokeCallableNode.execute(_this, frame, state, new Object[] {argument});
} }
} }

View File

@ -0,0 +1,70 @@
package org.enso.interpreter.node.expression.builtin.interop.generic;
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.ReportPolymorphism;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.DirectCallNode;
import com.oracle.truffle.api.nodes.IndirectCallNode;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.source.Source;
import org.enso.interpreter.Language;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode;
import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.data.text.Text;
@BuiltinMethod(
type = "Polyglot",
name = "eval",
description = "Evaluates a foreign language string.")
@ReportPolymorphism
public abstract class EvalNode extends Node {
static final int LIMIT = 10;
static EvalNode build() {
return EvalNodeGen.create();
}
abstract Object execute(Object _this, Text language, Text code);
@Specialization(
guards = {"cachedLanguage == language", "cachedCode == code"},
limit = "LIMIT")
Object doCached(
Object _this,
Text language,
Text code,
@CachedContext(Language.class) Context context,
@Cached("language") Text cachedLanguage,
@Cached("code") Text cachedCode,
@Cached("build()") ToJavaStringNode toJavaStringNode,
@Cached("parse(context, cachedLanguage, cachedCode, toJavaStringNode)") CallTarget callTarget,
@Cached("create(callTarget)") DirectCallNode callNode,
@Cached("build()") HostValueToEnsoNode hostValueToEnsoNode) {
return hostValueToEnsoNode.execute(callNode.call());
}
@Specialization(replaces = "doCached")
Object doUncached(
Object _this,
Text language,
Text code,
@CachedContext(Language.class) Context context,
@Cached IndirectCallNode callNode,
@Cached("build()") ToJavaStringNode toJavaStringNode,
@Cached("build()") HostValueToEnsoNode hostValueToEnsoNode) {
CallTarget ct = parse(context, language, code, toJavaStringNode);
return hostValueToEnsoNode.execute(callNode.call(ct));
}
CallTarget parse(Context context, Text language, Text code, ToJavaStringNode toJavaStringNode) {
String languageStr = toJavaStringNode.execute(language);
String codeStr = toJavaStringNode.execute(code);
Source source = Source.newBuilder(languageStr, codeStr, "<polyglot_eval>").build();
return context.getEnvironment().parsePublic(source);
}
}

View File

@ -8,6 +8,7 @@ import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Constants; import org.enso.interpreter.Constants;
import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode;
import org.enso.interpreter.runtime.data.Array; import org.enso.interpreter.runtime.data.Array;
import org.enso.interpreter.runtime.error.PanicException; import org.enso.interpreter.runtime.error.PanicException;
@ -18,11 +19,12 @@ import org.enso.interpreter.runtime.error.PanicException;
public class ExecuteNode extends Node { public class ExecuteNode extends Node {
private @Child InteropLibrary library = private @Child InteropLibrary library =
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
private @Child HostValueToEnsoNode hostValueToEnsoNode = HostValueToEnsoNode.build();
private final BranchProfile err = BranchProfile.create(); private final BranchProfile err = BranchProfile.create();
Object execute(Object _this, Object callable, Array arguments) { Object execute(Object _this, Object callable, Array arguments) {
try { try {
return library.execute(callable, arguments.getItems()); return hostValueToEnsoNode.execute(library.execute(callable, arguments.getItems()));
} catch (UnsupportedMessageException | ArityException | UnsupportedTypeException e) { } catch (UnsupportedMessageException | ArityException | UnsupportedTypeException e) {
err.enter(); err.enter();
throw new PanicException(e.getMessage(), this); throw new PanicException(e.getMessage(), this);

View File

@ -5,6 +5,7 @@ import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState; import org.enso.interpreter.dsl.MonadicState;
import org.enso.interpreter.dsl.Suspend;
import org.enso.interpreter.node.BaseNode; import org.enso.interpreter.node.BaseNode;
import org.enso.interpreter.node.callable.InvokeCallableNode; import org.enso.interpreter.node.callable.InvokeCallableNode;
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode; import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
@ -50,7 +51,7 @@ public abstract class BracketNode extends Node {
@MonadicState Object state, @MonadicState Object state,
VirtualFrame frame, VirtualFrame frame,
Object _this, Object _this,
Thunk constructor, @Suspend Object constructor,
Object destructor, Object destructor,
Object action); Object action);
@ -59,7 +60,7 @@ public abstract class BracketNode extends Node {
Object state, Object state,
VirtualFrame frame, VirtualFrame frame,
Object _this, Object _this,
Thunk constructor, Object constructor,
Object destructor, Object destructor,
Object action) { Object action) {
Stateful resourceStateful = Stateful resourceStateful =

View File

@ -4,6 +4,7 @@ import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState; import org.enso.interpreter.dsl.MonadicState;
import org.enso.interpreter.dsl.Suspend;
import org.enso.interpreter.node.BaseNode; import org.enso.interpreter.node.BaseNode;
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode; import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
import org.enso.interpreter.runtime.callable.argument.Thunk; import org.enso.interpreter.runtime.callable.argument.Thunk;
@ -17,7 +18,7 @@ public class NoInlineNode extends Node {
private @Child ThunkExecutorNode thunkExecutorNode = ThunkExecutorNode.build(); private @Child ThunkExecutorNode thunkExecutorNode = ThunkExecutorNode.build();
@CompilerDirectives.TruffleBoundary @CompilerDirectives.TruffleBoundary
Stateful execute(@MonadicState Object state, Object _this, Thunk action) { Stateful execute(@MonadicState Object state, Object _this, @Suspend Object action) {
return thunkExecutorNode.executeThunk(action, state, BaseNode.TailStatus.NOT_TAIL); return thunkExecutorNode.executeThunk(action, state, BaseNode.TailStatus.NOT_TAIL);
} }
} }

View File

@ -7,6 +7,7 @@ import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState; import org.enso.interpreter.dsl.MonadicState;
import org.enso.interpreter.dsl.Suspend;
import org.enso.interpreter.node.BaseNode; import org.enso.interpreter.node.BaseNode;
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode; import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
import org.enso.interpreter.runtime.callable.argument.Thunk; import org.enso.interpreter.runtime.callable.argument.Thunk;
@ -29,11 +30,15 @@ public abstract class RunStateNode extends Node {
private @Child ThunkExecutorNode thunkExecutorNode = ThunkExecutorNode.build(); private @Child ThunkExecutorNode thunkExecutorNode = ThunkExecutorNode.build();
abstract Stateful execute( abstract Stateful execute(
@MonadicState Object state, Object _this, Object key, Object local_state, Thunk computation); @MonadicState Object state,
Object _this,
Object key,
Object local_state,
@Suspend Object computation);
@Specialization @Specialization
Stateful doEmpty( Stateful doEmpty(
EmptyMap state, Object _this, Object key, Object local_state, Thunk computation) { EmptyMap state, Object _this, Object key, Object local_state, Object computation) {
SingletonMap localStateMap = new SingletonMap(key, local_state); SingletonMap localStateMap = new SingletonMap(key, local_state);
Object result = Object result =
thunkExecutorNode thunkExecutorNode
@ -44,7 +49,7 @@ public abstract class RunStateNode extends Node {
@Specialization(guards = {"state.getKey() == key"}) @Specialization(guards = {"state.getKey() == key"})
Stateful doSingletonSameKey( Stateful doSingletonSameKey(
SingletonMap state, Object _this, Object key, Object local_state, Thunk computation) { SingletonMap state, Object _this, Object key, Object local_state, Object computation) {
SingletonMap localStateContainer = new SingletonMap(state.getKey(), local_state); SingletonMap localStateContainer = new SingletonMap(state.getKey(), local_state);
Stateful res = Stateful res =
thunkExecutorNode.executeThunk( thunkExecutorNode.executeThunk(
@ -63,7 +68,7 @@ public abstract class RunStateNode extends Node {
Object _this, Object _this,
Object key, Object key,
Object local_state, Object local_state,
Thunk computation, Object computation,
@Cached("key") Object cachedNewKey, @Cached("key") Object cachedNewKey,
@Cached("state.getKey()") Object cachedOldKey, @Cached("state.getKey()") Object cachedOldKey,
@Cached(value = "buildSmallKeys(cachedNewKey, cachedOldKey)", dimensions = 1) @Cached(value = "buildSmallKeys(cachedNewKey, cachedOldKey)", dimensions = 1)
@ -77,7 +82,7 @@ public abstract class RunStateNode extends Node {
@Specialization @Specialization
Stateful doSingletonNewKeyUncached( Stateful doSingletonNewKeyUncached(
SingletonMap state, Object _this, Object key, Object local_state, Thunk computation) { SingletonMap state, Object _this, Object key, Object local_state, Object computation) {
return doSingletonNewKeyCached( return doSingletonNewKeyCached(
state, state,
_this, _this,
@ -100,7 +105,7 @@ public abstract class RunStateNode extends Node {
Object _this, Object _this,
Object key, Object key,
Object local_state, Object local_state,
Thunk computation, Object computation,
@Cached("key") Object cachedNewKey, @Cached("key") Object cachedNewKey,
@Cached(value = "state.getKeys()", dimensions = 1) Object[] cachedOldKeys, @Cached(value = "state.getKeys()", dimensions = 1) Object[] cachedOldKeys,
@Cached("state.indexOf(key)") int index, @Cached("state.indexOf(key)") int index,
@ -125,7 +130,7 @@ public abstract class RunStateNode extends Node {
Object _this, Object _this,
Object key, Object key,
Object local_state, Object local_state,
Thunk computation, Object computation,
@Cached("key") Object cachedNewKey, @Cached("key") Object cachedNewKey,
@Cached(value = "state.getKeys()", dimensions = 1) Object[] cachedOldKeys, @Cached(value = "state.getKeys()", dimensions = 1) Object[] cachedOldKeys,
@Cached("state.indexOf(key)") int index) { @Cached("state.indexOf(key)") int index) {
@ -144,7 +149,7 @@ public abstract class RunStateNode extends Node {
@Specialization @Specialization
Stateful doMultiUncached( Stateful doMultiUncached(
SmallMap state, Object _this, Object key, Object local_state, Thunk computation) { SmallMap state, Object _this, Object key, Object local_state, Object computation) {
int idx = state.indexOf(key); int idx = state.indexOf(key);
if (idx == SmallMap.NOT_FOUND) { if (idx == SmallMap.NOT_FOUND) {
return doMultiNewKeyCached( return doMultiNewKeyCached(

View File

@ -3,6 +3,7 @@ package org.enso.interpreter.node.expression.builtin.thread;
import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState; import org.enso.interpreter.dsl.MonadicState;
import org.enso.interpreter.dsl.Suspend;
import org.enso.interpreter.node.BaseNode; import org.enso.interpreter.node.BaseNode;
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode; import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
import org.enso.interpreter.runtime.callable.argument.Thunk; import org.enso.interpreter.runtime.callable.argument.Thunk;
@ -18,7 +19,7 @@ public class WithInterruptHandlerNode extends Node {
private @Child ThunkExecutorNode handlerExecutorNode = ThunkExecutorNode.build(); private @Child ThunkExecutorNode handlerExecutorNode = ThunkExecutorNode.build();
Stateful execute( Stateful execute(
@MonadicState Object state, Object _this, Thunk action, Thunk interrupt_handler) { @MonadicState Object state, Object _this, @Suspend Object action, @Suspend Object interrupt_handler) {
try { try {
return actExecutorNode.executeThunk(action, state, BaseNode.TailStatus.NOT_TAIL); return actExecutorNode.executeThunk(action, state, BaseNode.TailStatus.NOT_TAIL);
} catch (ThreadInterruptedException e) { } catch (ThreadInterruptedException e) {

View File

@ -65,6 +65,7 @@ public class Polyglot {
scope.registerMethod(polyglot, "execute", ExecuteMethodGen.makeFunction(language)); scope.registerMethod(polyglot, "execute", ExecuteMethodGen.makeFunction(language));
scope.registerMethod(polyglot, "invoke", InvokeMethodGen.makeFunction(language)); scope.registerMethod(polyglot, "invoke", InvokeMethodGen.makeFunction(language));
scope.registerMethod(polyglot, "new", InstantiateMethodGen.makeFunction(language)); scope.registerMethod(polyglot, "new", InstantiateMethodGen.makeFunction(language));
scope.registerMethod(polyglot, "eval", EvalMethodGen.makeFunction(language));
scope.registerMethod(polyglot, "get_member", GetMemberMethodGen.makeFunction(language)); scope.registerMethod(polyglot, "get_member", GetMemberMethodGen.makeFunction(language));
scope.registerMethod(polyglot, "get_members", GetMembersMethodGen.makeFunction(language)); scope.registerMethod(polyglot, "get_members", GetMembersMethodGen.makeFunction(language));
} }

View File

@ -8,6 +8,7 @@ import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.CachedContext; import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.ArityException; import com.oracle.truffle.api.interop.ArityException;
import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.TruffleObject;
@ -83,8 +84,7 @@ public final class Function implements TruffleObject {
* @param args argument definitons * @param args argument definitons
* @return a Function object with specified behavior and arguments * @return a Function object with specified behavior and arguments
*/ */
public static Function fromBuiltinRootNode( public static Function fromBuiltinRootNode(BuiltinRootNode node, ArgumentDefinition... args) {
BuiltinRootNode node, ArgumentDefinition... args) {
RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(node); RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(node);
FunctionSchema schema = new FunctionSchema(args); FunctionSchema schema = new FunctionSchema(args);
return new Function(callTarget, null, schema); return new Function(callTarget, null, schema);
@ -103,8 +103,7 @@ public final class Function implements TruffleObject {
public static Function fromBuiltinRootNodeWithCallerFrameAccess( public static Function fromBuiltinRootNodeWithCallerFrameAccess(
BuiltinRootNode node, ArgumentDefinition... args) { BuiltinRootNode node, ArgumentDefinition... args) {
RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(node); RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(node);
FunctionSchema schema = FunctionSchema schema = new FunctionSchema(FunctionSchema.CallerFrameAccess.FULL, args);
new FunctionSchema(FunctionSchema.CallerFrameAccess.FULL, args);
return new Function(callTarget, null, schema); return new Function(callTarget, null, schema);
} }
@ -288,6 +287,19 @@ public final class Function implements TruffleObject {
return new Object[] {function.getScope(), callerInfo, state, positionalArguments}; return new Object[] {function.getScope(), callerInfo, state, positionalArguments};
} }
/**
* Generates an array of arguments using the schema to be passed to a call target.
*
* @param frame the frame becoming the lexical scope
* @param state the state to execute the thunk with
* @param positionalArguments the positional arguments to the call target
* @return an array containing the necessary information to call an Enso function
*/
public static Object[] buildArguments(
MaterializedFrame frame, Object state, Object[] positionalArguments) {
return new Object[] {frame, null, state, positionalArguments};
}
/** /**
* Generates an array of arguments using the schema to be passed to a call target. * Generates an array of arguments using the schema to be passed to a call target.
* *

View File

@ -596,7 +596,10 @@ class IrToTruffle(
.toArray[BranchNode] .toArray[BranchNode]
// Note [Pattern Match Fallbacks] // Note [Pattern Match Fallbacks]
val matchExpr = CaseNode.build(scrutineeNode, cases) val matchExpr = CaseNode.build(
scrutineeNode,
cases
)
setLocation(matchExpr, location) setLocation(matchExpr, location)
} else { } else {
val invalidBranches = maybeCases.collect { val invalidBranches = maybeCases.collect {
@ -644,7 +647,8 @@ class IrToTruffle(
branch.location branch.location
) )
val branchNode = CatchAllBranchNode.build(branchCodeNode) val branchNode =
CatchAllBranchNode.build(branchCodeNode.getCallTarget)
Right(branchNode) Right(branchNode)
case cons @ Pattern.Constructor(constructor, _, _, _, _) => case cons @ Pattern.Constructor(constructor, _, _, _, _) =>
@ -704,11 +708,14 @@ class IrToTruffle(
val bool = context.getBuiltins.bool() val bool = context.getBuiltins.bool()
val branchNode: BranchNode = val branchNode: BranchNode =
if (atomCons == bool.getTrue) { if (atomCons == bool.getTrue) {
BooleanBranchNode.build(true, branchCodeNode) BooleanBranchNode.build(true, branchCodeNode.getCallTarget)
} else if (atomCons == bool.getFalse) { } else if (atomCons == bool.getFalse) {
BooleanBranchNode.build(false, branchCodeNode) BooleanBranchNode.build(false, branchCodeNode.getCallTarget)
} else { } else {
ConstructorBranchNode.build(atomCons, branchCodeNode) ConstructorBranchNode.build(
atomCons,
branchCodeNode.getCallTarget
)
} }
branchNode branchNode
@ -1170,11 +1177,17 @@ class IrToTruffle(
) )
.unsafeAs[AliasAnalysis.Info.Scope.Child] .unsafeAs[AliasAnalysis.Info.Scope.Child]
val shouldSuspend = shouldBeSuspended.getOrElse( val shouldSuspend = value match {
case _: IR.Name => false
case _: IR.Literal.Text => false
case _: IR.Literal.Number => false
case _ =>
shouldBeSuspended.getOrElse(
throw new CompilerError( throw new CompilerError(
"Demand analysis information missing from call argument." "Demand analysis information missing from call argument."
) )
) )
}
val childScope = if (shouldSuspend) { val childScope = if (shouldSuspend) {
scope.createChild(scopeInfo.scope) scope.createChild(scopeInfo.scope)

View File

@ -279,7 +279,6 @@ class CodeLocationsTest extends InterpreterTest {
instrumenter.assertNodeExists(55, 67, classOf[CaseNode]) instrumenter.assertNodeExists(55, 67, classOf[CaseNode])
instrumenter.assertNodeExists(60, 1, classOf[ReadLocalVariableNode]) instrumenter.assertNodeExists(60, 1, classOf[ReadLocalVariableNode])
instrumenter.assertNodeExists(103, 3, classOf[IntegerLiteralNode]) instrumenter.assertNodeExists(103, 3, classOf[IntegerLiteralNode])
instrumenter.assertNodeExists(73, 33, classOf[CreateFunctionNode])
eval(code) shouldEqual 100 eval(code) shouldEqual 100
} }

View File

@ -0,0 +1,11 @@
package org.enso.interpreter.dsl;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** An interface marking an argument as suspended. */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.SOURCE)
public @interface Suspend {}

View File

@ -2,6 +2,7 @@ package org.enso.interpreter.dsl.model;
import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState; import org.enso.interpreter.dsl.MonadicState;
import org.enso.interpreter.dsl.Suspend;
import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.*; import javax.lang.model.element.*;
@ -119,7 +120,10 @@ public class MethodDefinition {
"The execute method does not take `this` argument. At least one positional argument must be named `_this`.", "The execute method does not take `this` argument. At least one positional argument must be named `_this`.",
element); element);
} }
return definesThis;
boolean argsValid = arguments.stream().allMatch(arg -> arg.validate(processingEnvironment));
return definesThis && argsValid;
} }
/** @return the package name this method was declared in. */ /** @return the package name this method was declared in. */
@ -188,7 +192,9 @@ public class MethodDefinition {
private final boolean isState; private final boolean isState;
private final boolean isFrame; private final boolean isFrame;
private final boolean isCallerInfo; private final boolean isCallerInfo;
private final boolean isSuspended;
private final int position; private final int position;
private final VariableElement element;
/** /**
* Creates a new instance of this class. * Creates a new instance of this class.
@ -197,17 +203,32 @@ public class MethodDefinition {
* @param position the position (0-indexed) of this argument in the arguments list. * @param position the position (0-indexed) of this argument in the arguments list.
*/ */
public ArgumentDefinition(VariableElement element, int position) { public ArgumentDefinition(VariableElement element, int position) {
this.element = element;
type = element.asType(); type = element.asType();
String[] typeNameSegments = type.toString().split("\\."); String[] typeNameSegments = type.toString().split("\\.");
typeName = typeNameSegments[typeNameSegments.length - 1]; typeName = typeNameSegments[typeNameSegments.length - 1];
String originalName = element.getSimpleName().toString(); String originalName = element.getSimpleName().toString();
name = originalName.equals("_this") ? "this" : originalName; name = originalName.equals("_this") ? "this" : originalName;
isState = element.getAnnotation(MonadicState.class) != null && type.toString().equals(OBJECT); isState = element.getAnnotation(MonadicState.class) != null && type.toString().equals(OBJECT);
isSuspended = element.getAnnotation(Suspend.class) != null;
isFrame = type.toString().equals(VIRTUAL_FRAME); isFrame = type.toString().equals(VIRTUAL_FRAME);
isCallerInfo = type.toString().equals(CALLER_INFO); isCallerInfo = type.toString().equals(CALLER_INFO);
this.position = position; this.position = position;
} }
public boolean validate(ProcessingEnvironment processingEnvironment) {
if (type.toString().equals(THUNK)) {
processingEnvironment
.getMessager()
.printMessage(
Diagnostic.Kind.ERROR,
"Argument must not be typed as Thunk. Use @Suspend Object instead.",
element);
return false;
}
return true;
}
/** @return whether this argument should be passed the monadic state. */ /** @return whether this argument should be passed the monadic state. */
public boolean isState() { public boolean isState() {
return isState; return isState;
@ -265,7 +286,7 @@ public class MethodDefinition {
/** @return whether this argument is expected to be passed suspended. */ /** @return whether this argument is expected to be passed suspended. */
public boolean isSuspended() { public boolean isSuspended() {
return type.toString().equals(THUNK); return isSuspended;
} }
} }
} }

View File

@ -95,4 +95,15 @@ public class Text_Utils {
public static boolean starts_with(String str, String prefix) { public static boolean starts_with(String str, String prefix) {
return str.startsWith(prefix); return str.startsWith(prefix);
} }
/**
* Checks whether {@code a} is lexicographically before {@code b}.
*
* @param a the left operand
* @param b the right operand
* @return whether {@code a} is before {@code b}.
*/
public static boolean lt(String a, String b) {
return a.compareTo(b) < 0;
}
} }

View File

@ -2,6 +2,8 @@ from Base import all
import Builtins import Builtins
import Base.Bench_Utils import Base.Bench_Utils
polyglot java import java.util.Random
gen_list len = 0.upto len . fold Nil (l -> i -> Cons i+1 l) gen_list len = 0.upto len . fold Nil (l -> i -> Cons i+1 l)
sum_list_meta list = sum_list_meta list =
@ -14,6 +16,12 @@ sum_list_meta list =
res = folder 0 list res = folder 0 list
res res
sum_recur n = if n == 0 then 0 else 1 + here.sum_recur n-1
build_map size =
rand = Random.new [].to_array
0.upto size . fold Map.empty (m -> i -> m.insert (rand.nextInt [10000]) i)
main = main =
mil = 1000000 mil = 1000000
list = here.gen_list mil list = here.gen_list mil
@ -23,3 +31,4 @@ main =
Bench_Utils.measure (list.fold 0 (+)) "list fold" 1000 10 Bench_Utils.measure (list.fold 0 (+)) "list fold" 1000 10
Bench_Utils.measure (vec.fold 0 (+)) "vector fold" 1000 10 Bench_Utils.measure (vec.fold 0 (+)) "vector fold" 1000 10
Bench_Utils.measure (vec_decimal.fold 0 (+)) "vector decimal fold" 1000 10 Bench_Utils.measure (vec_decimal.fold 0 (+)) "vector decimal fold" 1000 10
Bench_Utils.measure (here.build_map 10000) "build a map" 100 10

View File

@ -41,7 +41,8 @@ sum_co_state_body =
acc = State.get Sum acc = State.get Sum
State.put Counter n-1 State.put Counter n-1
State.put Sum acc+n State.put Sum acc+n
if n == 0 then acc else @Tail_Call here.sum_co_state_body if n == 0 then acc else
@Tail_Call here.sum_co_state_body
sum_co_state n = sum_co_state n =
res = State.run Counter n (State.run Sum 0 here.sum_co_state_body) res = State.run Counter n (State.run Sum 0 here.sum_co_state_body)
@ -67,7 +68,6 @@ sum_co n =
main = main =
hundred_mil = 100000000 hundred_mil = 100000000
IO.println (here.sum_co 1000)
IO.println "Measuring Sum TCO Corecursive" IO.println "Measuring Sum TCO Corecursive"
Bench_Utils.measure (here.sum_co hundred_mil) "sum_tco_corecursive" 100 10 Bench_Utils.measure (here.sum_co hundred_mil) "sum_tco_corecursive" 100 10
IO.println "Measuring Sum TCO Decimal" IO.println "Measuring Sum TCO Decimal"

View File

@ -0,0 +1,14 @@
from Base import all
import Base.Test
spec = describe "Maps" <|
it "should allow inserting and looking up values" <|
m = Map.empty . insert "foo" 134 . insert "bar" 654 . insert "baz" "spam"
m.get "foo" . should equal 134
m.get "bar" . should equal 654
m.get "baz" . should equal "spam"
m.get "nope" . catch e->e . should_equal (Map.No_Value_For_Key "nope")
it "should convert the whole map to a vector" <|
m = Map.empty . insert 0 0 . insert 3 -5 . insert 1 2
m.to_vector.should equal [[0, 0], [1, 2], [3, -5]]

View File

@ -8,6 +8,7 @@ import Test.Semantic.Names_Spec
import Test.Semantic.Meta_Spec import Test.Semantic.Meta_Spec
import Test.List_Spec import Test.List_Spec
import Test.Data.Map_Spec
import Test.Number_Spec import Test.Number_Spec
import Test.Process_Spec import Test.Process_Spec
import Test.Vector.Spec as Vector_Spec import Test.Vector.Spec as Vector_Spec
@ -31,3 +32,4 @@ main = Test.Suite.runMain <|
Time_Spec.spec Time_Spec.spec
File_Spec.spec File_Spec.spec
Meta_Spec.spec Meta_Spec.spec
Map_Spec.spec

View File

@ -16,6 +16,7 @@ library:
- base - base
- deepseq - deepseq
- containers - containers
- random
benchmarks: benchmarks:
haskell-benchmark: haskell-benchmark:

View File

@ -4,8 +4,10 @@ import Prelude
import qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
import Control.Monad (foldM)
import Data.Int (Int64) import Data.Int (Int64)
import Data.List (foldl') import Data.List (foldl')
import System.Random (randomRIO)
------------------ ------------------
@ -69,4 +71,7 @@ myFoldl f z (Cons x xs) = let z' = z `f` x
in seq z' $ myFoldl f z' xs in seq z' $ myFoldl f z' xs
buildMap :: Integer -> Map.Map Integer Integer buildMap :: Integer -> Map.Map Integer Integer
buildMap i = foldl' (\m i -> Map.insert i i m) Map.empty [0..i] buildMap n = foldl' (\m i -> Map.insert i i m) Map.empty [0..n]
buildRandomMap :: Integer -> IO (Map.Map Integer Integer)
buildRandomMap n = foldM (\m i -> fmap (\key -> Map.insert key i m) $ randomRIO (0, 10000)) Map.empty [0..n]

View File

@ -10,6 +10,7 @@ main :: IO ()
main = defaultMain main = defaultMain
[ [
bench "buildMap" $ whnf Fixtures.buildMap Fixtures.tenThousand, bench "buildMap" $ whnf Fixtures.buildMap Fixtures.tenThousand,
bench "buildMapRandom" $ whnfIO $ Fixtures.buildRandomMap Fixtures.tenThousand,
bench "sumTCO" $ whnf Fixtures.sumTCO Fixtures.hundredMillion, bench "sumTCO" $ whnf Fixtures.sumTCO Fixtures.hundredMillion,
bench "sumList" $ whnf Fixtures.sumList Fixtures.millionElementList, bench "sumList" $ whnf Fixtures.sumList Fixtures.millionElementList,
bench "reverseList" $ whnf Fixtures.reverseList Fixtures.millionElementList, bench "reverseList" $ whnf Fixtures.reverseList Fixtures.millionElementList,