Skip to content
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

Removing Unsafe.set_atom_field #4023

Merged
merged 27 commits into from
Jan 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6cc81c6
Removing test that relies on Unsafe
JaroslavTulach Jan 4, 2023
983c37e
Replacing set_atom_field with Meta.lazy_atom
JaroslavTulach Jan 4, 2023
ff7a474
invokeMember instead of execute
JaroslavTulach Jan 4, 2023
f3449b8
With incremental compilation there may not be any input files
JaroslavTulach Jan 5, 2023
e3840fb
Removing Unsafe from micro-distribution
JaroslavTulach Jan 5, 2023
3df23b3
Make fill function really a function that can be called
JaroslavTulach Jan 5, 2023
ba603af
Unit test to check basic functionality
JaroslavTulach Jan 5, 2023
c185161
Generate Uninitialized_State.Error if lazy_atom isn't used
JaroslavTulach Jan 5, 2023
f584555
Fail if non-atom is created
JaroslavTulach Jan 5, 2023
85c8cde
Allow only one lazy_atom in an Atom
JaroslavTulach Jan 5, 2023
c51714b
Speculate the hole index remains the same
JaroslavTulach Jan 5, 2023
28ca763
Specify the exact type for instanceof
JaroslavTulach Jan 5, 2023
eaeadf2
ListTest to verify behavior of operations that need @Tail_Call annota…
JaroslavTulach Jan 6, 2023
9222ff5
Renaming to Meta.atom_with_hole and returning Pair
JaroslavTulach Jan 6, 2023
dc9e60f
Formatting
JaroslavTulach Jan 6, 2023
11d7143
Adding also List.to_text test
JaroslavTulach Jan 6, 2023
73dfc7f
Merge branch 'develop' into wip/jtulach/NoSetAtomField_183578531
JaroslavTulach Jan 6, 2023
695775b
Benchmark to measure performance of List.map
JaroslavTulach Jan 6, 2023
b383ace
Using InvokeCallableNode instead of InteropLibrary
JaroslavTulach Jan 6, 2023
72255fa
Note about Meta.atom_with_hole in the changelog
JaroslavTulach Jan 6, 2023
9484ae0
Avoid allocating Vector at all. Expose object with value and fill pro…
JaroslavTulach Jan 6, 2023
8ccbecb
Make sure all List operation handle "infinite" lists
JaroslavTulach Jan 6, 2023
bfe5338
Pair import is no longer needed
JaroslavTulach Jan 6, 2023
a0906d0
Make sure List.init works for one, two and three elements
JaroslavTulach Jan 6, 2023
a8cd2bf
Using (Cons x _) per James suggestion
JaroslavTulach Jan 6, 2023
b883b2c
Merge branch 'develop' into wip/jtulach/NoSetAtomField_183578531
mergify[bot] Jan 6, 2023
0ee4225
Merging with develop branch
JaroslavTulach Jan 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@
- [IGV can jump to JMH sources & more][4008]
- [Basic support of VSCode integration][4014]
- [Sync language server with file system after VCS restore][4020]
- [Introducing Meta.atom_with_hole][4023]
- [Report failures in name resolution in type signatures][4030]

[3227]: https://github.com/enso-org/enso/pull/3227
Expand Down Expand Up @@ -580,6 +581,7 @@
[4008]: https://github.com/enso-org/enso/pull/4008
[4014]: https://github.com/enso-org/enso/pull/4014
[4020]: https://github.com/enso-org/enso/pull/4020
[4023]: https://github.com/enso-org/enso/pull/4023
[4030]: https://github.com/enso-org/enso/pull/4030

# Enso 2.0.0-alpha.18 (2021-10-12)
Expand Down
90 changes: 56 additions & 34 deletions distribution/lib/Standard/Base/0.0.0-dev/src/Data/List.enso
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import project.Data.Vector.Vector
import project.Error.Error
import project.Function.Function
import project.Nothing.Nothing
import project.Runtime.Unsafe
import project.Meta

from project.Data.Boolean import Boolean, True, False

Expand Down Expand Up @@ -185,13 +185,19 @@ type List
filter : (Filter_Condition | (Any -> Boolean)) -> Vector Any
filter self filter = case filter of
_ : Filter_Condition -> self.filter filter.to_predicate
predicate : Function ->
go_filter list = case list of
Nil -> Nil
Cons h t ->
rest = go_filter t
if predicate h then Cons h rest else rest
go_filter self
predicate : Function -> case self of
Nil -> Nil
Cons x xs -> if predicate x . not then @Tail_Call xs.filter filter else
go list fill = case list of
Nil -> fill Nil
Cons h t -> if predicate h . not then @Tail_Call go t fill else
res = Meta.atom_with_hole (Cons h _)
fill res.value
@Tail_Call go t res.fill

res = Meta.atom_with_hole (Cons x _)
go xs res.fill
res.value

## Applies a function to each element of the list, returning the list of
results.
Expand All @@ -209,9 +215,18 @@ type List
map self f = case self of
Nil -> Nil
Cons h t ->
res = Cons (f h) Nil
map_helper t res f
res
go : List -> Any -> (Any -> Any) -> Nothing
go list fill = case list of
Nil -> fill Nil
Cons h t ->
v = f h
res = Meta.atom_with_hole (Cons v _)
fill res.value
@Tail_Call go t res.fill
v = f h
res = Meta.atom_with_hole (Cons v _)
go t res.fill
res.value

## Applies a function to each element of the list.

Expand Down Expand Up @@ -281,7 +296,16 @@ type List
take_start : Integer -> List
take_start self count = if count <= 0 then Nil else case self of
Nil -> Nil
Cons a b -> Cons a (b.take_start count-1)
Cons a b ->
go c l fill = if c <= 0 then fill Nil else case l of
Nil -> fill Nil
Cons a b ->
res = Meta.atom_with_hole (Cons a _)
fill res.value
@Tail_Call go c-1 b res.fill
res = Meta.atom_with_hole (Cons a _)
go count-1 b res.fill
res.value

## Get the first element from the list.

Expand Down Expand Up @@ -319,12 +343,21 @@ type List
example_init = Examples.list.init
init : List ! Empty_Error
init self =
init_fn x y = case y of
Nil -> Nil
Cons a b -> Cons x (init_fn a b)
case self of
Nil -> Error.throw Empty_Error
Cons a b -> init_fn a b
Cons _ Nil -> Nil
Cons a b ->
go l fill = case l of
Cons x xs -> case xs of
Nil -> fill Nil
Cons _ _ ->
res = Meta.atom_with_hole (Cons x _)
fill res.value
@Tail_Call go xs res.fill

res = Meta.atom_with_hole (Cons a _)
go b res.fill
res.value

## Get the last element of the list.

Expand Down Expand Up @@ -369,6 +402,13 @@ type List
builder.append elem
builder.to_vector

to_text : Text
to_text self =
go l t = case l of
Nil -> t + "Nil"
Cons x xs -> @Tail_Call go xs (t + "Cons " + x.to_text + " ")
go self ""

## UNSTABLE

An error representing that the list is empty.
Expand All @@ -379,21 +419,3 @@ type Empty_Error
to_display_text : Text
to_display_text self = "The List is empty."

## PRIVATE
A helper for the `map` function.

Arguments:
- list: The list to map over.
- cons: The current field to set.
- f: The function to apply to the value.

Uses unsafe field mutation under the hood, to rewrite `map` in
a tail-recursive manner. The mutation is purely internal and does not leak
to the user-facing API.
map_helper : List -> Any -> (Any -> Any) -> Nothing
map_helper list cons f = case list of
Nil -> Unsafe.set_atom_field cons 1 Nil
Cons h t ->
res = Cons (f h) Nil
Unsafe.set_atom_field cons 1 res
@Tail_Call map_helper t res f
11 changes: 11 additions & 0 deletions distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,17 @@ get_constructor_name atom_constructor = @Builtin_Method "Meta.get_constructor_na
new_atom : Any -> Array -> Atom
new_atom constructor fields = @Builtin_Method "Meta.new_atom"

JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved
## PRIVATE

Constructs a new atom with a "hole". Returns an object with `value` and
`fill` properties. Value contains the created atom and `fill` holds a
function to "fill the hole" later.

Arguments:
- factory: a function that takes the "hole" element and returns newly created atom
atom_with_hole : (Any -> Atom) -> Any
atom_with_hole factory = @Builtin_Method "Meta.atom_with_hole_builtin"

## UNSTABLE
ADVANCED

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package org.enso.interpreter.bench.benchmarks.semantic;

import java.io.ByteArrayOutputStream;
import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.BenchmarkParams;
import org.openjdk.jmh.infra.Blackhole;


@BenchmarkMode(Mode.AverageTime)
@Fork(1)
@Warmup(iterations = 3)
@Measurement(iterations = 5)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
public class ListBenchmarks {
private final int LENGTH_OF_EXPERIMENT = 1_000_000;
private Value list;
private Value plusOne;
private Value self;
private Value sum;
private Value oldSum;

@Setup
public void initializeBenchmark(BenchmarkParams params) throws Exception {
var ctx = Context.newBuilder()
.allowExperimentalOptions(true)
.allowIO(true)
.allowAllAccess(true)
.logHandler(new ByteArrayOutputStream())
.option(
"enso.languageHomeOverride",
Paths.get("../../distribution/component").toFile().getAbsolutePath()
).build();

var benchmarkName = params.getBenchmark().replaceFirst(".*\\.", "");
var code = """
from Standard.Base.Data.List.List import Cons, Nil
import Standard.Base.IO

plus_one list = list.map (x -> x + 1)

sum list acc =
case list of
Nil -> acc
Cons x xs -> @Tail_Call sum xs acc+x

generator n =
go x v l = if x > n then l else
@Tail_Call go x+1 v+1 (Cons v l)
go 1 1 Nil
""";

var module = ctx.eval(SrcUtil.source(benchmarkName, code));

this.self = module.invokeMember("get_associated_type");
Function<String,Value> getMethod = (name) -> module.invokeMember("get_method", self, name);

Value longList = getMethod.apply("generator").execute(self, LENGTH_OF_EXPERIMENT);

this.plusOne = getMethod.apply("plus_one");
this.sum = getMethod.apply("sum");

switch (benchmarkName) {
case "mapOverList": {
this.list = longList;
this.oldSum = sum.execute(self, longList, 0);
if (!this.oldSum.fitsInLong()) {
throw new AssertionError("Expecting a number " + this.oldSum);
}
break;
}
default:
throw new IllegalStateException("Unexpected benchmark: " + params.getBenchmark());
}
}

@Benchmark
public void mapOverList(Blackhole matter) {
performBenchmark(matter);
}

private void performBenchmark(Blackhole hole) throws AssertionError {
var newList = plusOne.execute(self, list);
var newSum = sum.execute(self, newList, 0);

var result = newSum.asLong() - oldSum.asLong();
if (result != LENGTH_OF_EXPERIMENT) {
throw new AssertionError("Unexpected result " + result);
}
hole.consume(result);
}
}

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.enso.interpreter.bench.benchmarks.semantic;
package org.enso.interpreter.bench.benchmarks.semantic;

import java.io.ByteArrayOutputStream;
import java.nio.file.Paths;
Expand Down
Loading