Skip to content

Computation does not resume after cancel. #9

@indicee-michald

Description

@indicee-michald

To trigger, we want to evaluate test in ICE, interrupt it with enter then retry evaluating it.

test :: Boolean;
test = isEven (makeNat 100000000) True;

isEven :: Nat -> Boolean -> Boolean;
isEven !x !accum =
    case x of
    Zero -> accum;
    OnePlus x ->
        isEven x (not accum);
    ;

makeNat :: Int -> Nat;
makeNat !x =
    if x > 0 then
        OnePlus (makeNat (x-1))
    else
        Zero;

data Nat
    = Zero
    | OnePlus x :: Nat // Must be lazy to prevent stack overflow in makeNat().
    ;

The key to having a reproducible test case is to generate code that will call a long running compuation so that RTValue.lastRef() is called somewhere. In this case the call is made in Is_Even.RTAppS.setResult(). I think a similar thing can happen if a supercombinator gets called via f() and not f_S() or f_L().

Here is the stack trace:

java.lang.NullPointerException
    at org.openquark.cal_Cal_Test_Core_PlingTest.Is_Even.f2S(Is_Even.java)
    at org.openquark.cal_Cal_Test_Core_PlingTest.Is_Even$RTAppS.reduce(Is_Even.java)
    at org.openquark.cal.internal.runtime.lecc.RTResultFunction.unsynchronizedEvaluate(RTResultFunction.java:136)
    at org.openquark.cal.internal.runtime.lecc.RTResultFunction.evaluate(RTResultFunction.java:103)
    at org.openquark.cal_Cal_Test_Core_PlingTest.Io__iceruntarget__0__0.f(Io__iceruntarget__0__0.java)
    at org.openquark.cal.internal.runtime.lecc.RTFullApp$General$_0.reduce(RTFullApp.java:225)
    at org.openquark.cal.internal.runtime.lecc.RTResultFunction.unsynchronizedEvaluate(RTResultFunction.java:136)
    at org.openquark.cal.internal.runtime.lecc.RTResultFunction.evaluate(RTResultFunction.java:103)
    at org.openquark.cal_Cal_Core_Prelude.Id.f(Id.java)
    at org.openquark.cal.internal.runtime.lecc.RTApplication.reduce(RTApplication.java:156)
    at org.openquark.cal.internal.runtime.lecc.RTResultFunction.unsynchronizedEvaluate(RTResultFunction.java:136)
    at org.openquark.cal.internal.runtime.lecc.RTResultFunction.evaluate(RTResultFunction.java:103)
    at org.openquark.cal.internal.machine.lecc.Executor.exec(Executor.java:173)
    at org.openquark.cal.ICE$FunctionRunThread.run(ICE.java:7234)
    at java.lang.Thread.run(Thread.java:679)

Here are my notes on what Rich had to say prior to having a reproducible test case:

+ Interaction of how graph is reduced and cancellation function takes a couple args.
+ Suppose we have a two argument recursive function:
  + function is represented as a class with 3 fields : arg1, arg2, result
    + if result != NULL, then we have evaluated the function and that is the result.
  + Function initially not evaluated, when time to evaluate (simple approach):
  + ask function to evaluate
  + apply application
  + replace node w/ full application
  + Problem: the fact that we're holding onto the two arguments casuses extra memory usage
      since they are never going to be needed. Everything needed to compute the result is passed to
      the recusive function.
    + Basically, the function object is holding onto stale objects. Kindof like holding onto the
       beginning of the list.
  + Optimized approach:
    + arg1, arg2 := NULL
    + proceed with evaluation of recursive case (somehow storing the values stored by the two args if
        required by recursive call).
  + Problem with optimized approach:
    + notice cancel flag > throw exception > unwind stack > leave object with 2 null arguments.

The simplest solution is to keep track of in progress CAFs for each context and remove the corresponding entry for the context in the CAF's RTCAF.$instancesMap. However, this will need support from RTFullApp.General._0 (or more likely a special implementation for CAFs).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions