Implement a test framework and test case for running lowered coroutines with HHVM
commit346340d23c4d70b68e2e82e98f9fb3770268765e
authorMichael Tingley <tingley@fb.com>
Wed, 21 Jun 2017 00:25:44 +0000 (20 17:25 -0700)
committerHhvm Bot <hhvm-bot@users.noreply.github.com>
Wed, 21 Jun 2017 00:27:40 +0000 (20 17:27 -0700)
tree33bd77f44c2ce4a2e490b1106715702ef2d4b27f
parent635a355decf8be1437e640afef4702bd72c1103e
Implement a test framework and test case for running lowered coroutines with HHVM

Summary:
= run_hhvm.py

First off, let's talk about the `run_hhvm.py` tool. This is used in unit tests, but it's quite useful as a standalone tool.

```
$ buck run mode/dbg hphp/hack/test/facebook/coroutine:run_hhvm -- --help

Performs the HHVM execution pipeline for coroutine source files.

Given a source file using the coroutines feature and an HHI directory of the
coroutine standard library, performs the following pipeline:

  1. Concatenate the HHI sources with test_path source.
  2. Lower the combined source.
  3. Compile the lowered combined source into hhas.
  4. Execute the hhas using HHVM.
  5. Print out the result.

positional arguments:
  test_path

optional arguments:
  -h, --help            show this help message and exit
  --compiler-program COMPILER_PROGRAM
                        Path to compiler program executable. (default:
                        /data/users/tingley/fbsource/fbcode/buck-out/bin/hphp/
                        hack/src/hh_single_compile/hh_single_compile.opt)
  --coroutine-program COROUTINE_PROGRAM
                        Path to coroutine program executable. (default:
                        /data/users/tingley/fbsource/fbcode/buck-out/bin/hphp/
                        hack/test/facebook/coroutine/coroutine/coroutine.opt)
  --hhi-dir HHI_DIR     Path to (coroutines) hhi directory. (default: /data/us
                        ers/tingley/fbsource/fbcode/hphp/hack/hhi/coroutine)
  --hhvm-program HHVM_PROGRAM
                        Path to hhvm program executable. (default:
                        /data/users/tingley/fbsource/fbcode/buck-
                        out/gen/hphp/hhvm/hhvm/hhvm)
  --verbose
```

You'll notice that the default values for the external programs are all configured reasonably. That means you can lower a coroutine source file and it will "just work":

  $ buck run mode/dbg hphp/hack/test/facebook/coroutine:run_hhvm -- $test_file

It will pull in the HHI coroutine files, combine the sources, lowered coroutines from the combined sources, compile the resulting source into hhas using Hack's `hh_single_compile`r, run the hhas using HHVM, and output the result of the execution.

  - If there are errors during any of these steps, they will be output.
  - It is **very** useful to add the `--verbose` flag to this script. That will cause it to output the paths of all of the intermediate representations. This way, you can manually inspect the lowered and combined source, or, if you're extremely masochistic, the compiled hhas.
  - The script is modular, so you can plug in different schemes to each part. You can pull it more or fewer HHI files. You can change out the HHVM runtime, so that you could use the production HHVM runtime, instead of an internally-built version. You could even change out the compiler (source --> hhas) or coroutine lowerer (source --> lowered source), although we don't yet have good substitutes for these.
  - It's worth noting that HHVM's compiler **does not** handle some of our lowered code correctly for compilation! So if we took lowered code and sent that to HHVM, it would not like all of it. For example, it rejects jumping into or out of loops, while `hh_single_compile` allows this.
  - It's also worth noting that the production HHVM runtime doesn't like our lowered hhas. I have a big comment in `run_hhvm.py` about this, which also explains why it makes me (and our build times) unhappy. This has caused me to mark the test with `tags = ['slow']`. You can read more about what this does in the comment that I've added to the TARGETS file.

= sequence_sample.php

Now, let's talk about the test sample. I ported this from ericlippert's diff. This is a very basic `SequenceBuilder`, which yields two strings, `First` and `Second`, and prints them.

Some notes on organization:

  1. `coroutine/classes.hhi` has been expanded, and contains the classes related to the coroutine standard library. Framework developers should use these utilities to build coroutine-utilizing frameworks.
  2. `sequence_sample.php` contains code specific to the `IteratorCoroutine`. It is a customer of the coroutines feature. This code is purely test code, so no one will ever get to use it, except for our tests!

There are many, many TODOs here. Let's go through some of them:

  1. **`SafeContinuation`.** `SafeContinuation` is **not** included in this diff. I had some questions about it, that I will isolate in another diff.
  2. Since `SafeContinuation` isn't in this diff, the following are not, either:
    1. `CreateCoroutine::withReceiver`
    2. `SuspendCoroutine::suspend`
  3. Since `SafeContinuation` isn't in this diff, the customer is required to use `CreateCoroutine::uncheckedWithReceiver` and `SuspendCoroutine::suspendUnchecked`.
  4. **Resugaring.** Some things have been resugared. Some things have not. Why? Basically, there are lots and lots of places where we would like to write `coroutine function (Arg): Result`, as a type annotation. However, we don't desugar type annotations! Instead, I've written such an annotation out in full-form as `function (CoroutineContinuation<Result>, Arg): CoroutineResult<Result>`.
  5. As an interesting consequence to the previous point, we have some very interesting situations where we are **`suspend`ing** on a non-coroutine function! We can `suspend` on an ordinary function, and the compiler will do the rewriting as appropriate. Since the function //just so happens// to have been manually desugared to the right type, this will both type check and execute correctly. Unfortunately, this only works because we're not nesting lots and lots of coroutines. This is a huge limitation, and therefore will be the thing that I work on next!

 ---

Reviewed By: ericlippert

Differential Revision: D5178566

fbshipit-source-id: 6c7abede26ca6d249b443b0f211f308dcf5d86b5
hphp/hack/hhi/coroutine/classes.hhi
hphp/hack/test/.gitignore