Skip to content

Commit

Permalink
Implement prepare_custom_contract natively (#2008)
Browse files Browse the repository at this point in the history
After the rework of the contract system that sets enum as the default
return type of most custom and builtin contracts, some additional glue
code was needed to post-process such enums (and raise blame
accordingly). This has been implemented in the new internal function
`$prepare_custom_contract`.

While this function wasn't very long or involved, measurements showed
that contract application is a code path that is taken so much that this
additional blob of pure Nickel slowed down real world example by
potentially a huge factor (up to 5-6x).

While this is the symptom of other inefficiencies related to the
contract system in general (related to pattern matching, missed caching
opportunities for contract generation, etc.), bringing back the logic of
`$prepare_custom_contract` to native code brings back the overhead
(master compared to latest stable 1.7) to something like 1.1x or 1.2x.

This commit implements this strategy, by introducing two new primops:

- `%contract/postprocess_result%` which takes an enum `[| 'Ok value,
  'Error error_data |]` and either unwrap `'Ok`, or modify the label
  using the `error_data` and then blame
- `%label/with_error_data%`, which is used in the previous primop
  implementation but can be useful as a stand alone primop and stdlib
  wrapper in the future, which takes a value `{message, notes}`, a
  label, and update the label's data with the corresponding diagnostic
  message and notes

Additionally, this commit tries to avoid generating terms at run-time,
but rather setup the stack directly, to further make this hot path
faster.
  • Loading branch information
yannham authored Jul 26, 2024
1 parent 74fea84 commit a7dc359
Show file tree
Hide file tree
Showing 6 changed files with 293 additions and 149 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,8 @@ error: contract broken by the caller
1 │ "a"
│ --- evaluated to this value

note:
┌─ [INPUTS_PATH]/errors/function_contract_domain_violation.ncl:5:31
5 │ let Foo = Number -> Number in ((fun x => x) | Foo) "a"
│ ------------------------ (1) calling <func>

note:
┌─ [INPUTS_PATH]/errors/function_contract_domain_violation.ncl:5:32
5 │ let Foo = Number -> Number in ((fun x => x) | Foo) "a"
│ ------------ (2) calling <func>


│ ^^^^^^^^^^^^ While calling to x
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,3 @@ note:
3let f | forall r. { ; r } -> { x: Number; r } = fun r => %record/insert% "x" r 1 in f { x = 0 }
^^^^^^^^^^^^^^^^^^^^^^^ While calling to r

note:
┌─ [INPUTS_PATH]/errors/record_forall_constraints_contract.ncl:3:85
3let f | forall r. { ; r } -> { x: Number; r } = fun r => %record/insert% "x" r 1 in f { x = 0 }
----------- (1) calling f

note:
┌─ [INPUTS_PATH]/errors/record_forall_constraints_contract.ncl:3:49
3let f | forall r. { ; r } -> { x: Number; r } = fun r => %record/insert% "x" r 1 in f { x = 0 }
-------------------------------- (2) calling <func>
Loading

0 comments on commit a7dc359

Please sign in to comment.