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

Convert Array_Like_Helpers.map to a builtin to reduce stack size #11363

Merged
merged 39 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
1a0f946
[WIP] Add Stack_Size_Spec
Akirathan Oct 18, 2024
695eeb3
Problem_Behavior is builtin type
Akirathan Oct 21, 2024
8753d07
No_Wrap is builtin type
Akirathan Oct 21, 2024
400f0fb
vector_from_function is builtin method
Akirathan Oct 21, 2024
a0fb709
vector_from_function accepts No_Wrap as onProblems argument
Akirathan Oct 21, 2024
0487d00
Stack_Size_Spec will be a regression test
Akirathan Oct 21, 2024
6e0c7f8
Report_Error unwraps payload
Akirathan Oct 22, 2024
935fbdc
Report_Error returns DataflowError
Akirathan Oct 22, 2024
3e32eb4
No_Wrap immediately returns error
Akirathan Oct 22, 2024
d1eb427
Report_Warning correctly attaches warning
Akirathan Oct 22, 2024
f026654
Attach additional warnings when limit is reached
Akirathan Oct 22, 2024
1eb8edc
Remove unused code
Akirathan Oct 22, 2024
847c496
vector_from_function is builtin
Akirathan Oct 23, 2024
990ee6a
Convert Stack_Size_Spec to (regression) test
Akirathan Oct 23, 2024
6de3d1b
Add clue to the test
Akirathan Oct 24, 2024
e0063aa
Vector.map and Array_Like_Helpers.map are tail calls
Akirathan Oct 24, 2024
9c3d18f
Revert "Set stack size to 16M (#11327)"
Akirathan Oct 24, 2024
544dfc7
Merge branch 'develop' into wip/akirathan/11329-map-reduce-stack
Akirathan Oct 24, 2024
6e23ed6
Fix after merge
Akirathan Oct 24, 2024
ece75fb
Builtins.getBuiltinType method call is behind truffle boundary
Akirathan Oct 24, 2024
e76a6bd
Remove NeverDefault warning
Akirathan Oct 24, 2024
e16961f
MetaObjectTest.compareQualifiedAndSimpleTypeName skips singleton types
Akirathan Oct 25, 2024
bf28a12
singleton builtin types are skipped in other tests as well
Akirathan Oct 25, 2024
ea6b09f
Add instances of Problem_Behavior to meta tests
Akirathan Oct 25, 2024
204d5fb
No_Wrap and Problem_Behavior are builtins in EnsoContext
Akirathan Oct 25, 2024
fcbb60a
type error panic is hidden behind TruffleBoundary
Akirathan Oct 25, 2024
3949ed8
Stack_Size_Spec runs only on LInux
Akirathan Oct 28, 2024
eb38c35
Fix native image run tests - add java.lang.RuntimeException to NI
Akirathan Oct 28, 2024
a445a31
Skip singleton builtin types in MetaIsATest
Akirathan Oct 28, 2024
89b5e59
Cache onProblems parameter
Akirathan Oct 29, 2024
6ac51d7
Add filtering for benchmarks
Akirathan Oct 29, 2024
e13a77a
Add docs for tracing compilation for runtime-benchmarks
Akirathan Oct 30, 2024
ab27a4d
Close context in TypePatternBenchmarks
Akirathan Nov 4, 2024
5b96444
No_Wrap is an uniquely constructible builtin
Akirathan Nov 4, 2024
d2dcc04
VectorFromFunctionNode caches onProblems atom ctor and uses loop profile
Akirathan Nov 4, 2024
dee9abe
Merge branch 'develop' into wip/akirathan/11329-map-reduce-stack
Akirathan Nov 4, 2024
cd3e04b
Add value for No_Wrap to meta tests
Akirathan Nov 5, 2024
2cbc1e9
onProblems is No_Wrap.Value
Akirathan Nov 5, 2024
7f22096
Merge branch 'develop' into wip/akirathan/11329-map-reduce-stack
Akirathan Nov 6, 2024
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: 1 addition & 1 deletion distribution/bin/enso
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
COMP_PATH=$(dirname "$0")/../component

JAVA_OPTS="--add-opens=java.base/java.nio=ALL-UNNAMED -Xss16M $JAVA_OPTS"
JAVA_OPTS="--add-opens=java.base/java.nio=ALL-UNNAMED $JAVA_OPTS"
exec java --module-path $COMP_PATH $JAVA_OPTS -m org.enso.runner/org.enso.runner.Main "$@"
exit
2 changes: 1 addition & 1 deletion distribution/bin/enso.bat
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@echo off
set comp-dir=%~dp0\..\component
set JAVA_OPTS=%JAVA_OPTS% --add-opens=java.base/java.nio=ALL-UNNAMED -Xss16M
set JAVA_OPTS=%JAVA_OPTS% --add-opens=java.base/java.nio=ALL-UNNAMED
java --module-path %comp-dir% -Dpolyglot.compiler.IterativePartialEscape=true %JAVA_OPTS% -m org.enso.runner/org.enso.runner.Main %*
exit /B %errorlevel%
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ type Vector a

Vector.new my_vec.length (ix -> my_vec.at ix)
new : Integer -> (Integer -> Any) -> Vector Any
new length constructor = Array_Like_Helpers.vector_from_function length constructor
new length constructor = Array_Like_Helpers.vector_from_function length constructor Problem_Behavior.Report_Error

## PRIVATE
ADVANCED
Expand Down Expand Up @@ -700,7 +700,7 @@ type Vector a
[1, 2, 3] . map +1
map : (Any -> Any) -> Problem_Behavior | No_Wrap -> Vector Any
map self function on_problems:(Problem_Behavior | No_Wrap)=..Report_Error =
Array_Like_Helpers.map self function on_problems
@Tail_Call Array_Like_Helpers.map self function on_problems

## ICON union
Applies a function to each element of the vector, returning the `Vector`
Expand Down Expand Up @@ -1548,6 +1548,7 @@ type Map_Error

## PRIVATE
Indicates that a method should not wrap thrown errors in `Map_Error`.
@Builtin_Type
type No_Wrap

## PRIVATE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ type Missing_Argument
Error.throw (Missing_Argument.Error argument_name function_name call_location)

## Warning when additional warnings occurred.
@Builtin_Type
type Additional_Warnings
## PRIVATE
Error (count:Integer)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import project.Error.Error
import project.Warning.Warning

## Specifies how to handle problems.
@Builtin_Type
type Problem_Behavior
## Ignore the problem and attempt to complete the operation
Ignore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@ at array_like index = @Builtin_Method "Array_Like_Helpers.at"
vector_to_array : (Vector | Array) -> Array
vector_to_array array_like = @Builtin_Method "Array_Like_Helpers.vector_to_array"

vector_from_function_primitive : Integer -> (Integer -> Any) -> Vector Any
vector_from_function_primitive length constructor = @Builtin_Method "Array_Like_Helpers.vector_from_function"

flatten : (Vector | Array) -> Vector
flatten array_like = @Builtin_Method "Array_Like_Helpers.flatten"

Expand Down Expand Up @@ -84,33 +81,7 @@ slice vector start end = @Builtin_Method "Array_Like_Helpers.slice"
- Ignore: The result is `Nothing`, and the error is
ignored.
vector_from_function : Integer -> (Integer -> Any) -> Problem_Behavior | No_Wrap -> Vector Any
vector_from_function length function on_problems:(Problem_Behavior | No_Wrap)=..Report_Error =
num_errors = Ref.new 0
wrapped_function i =
result = function i
if result.is_error.not then result else
case on_problems of
Problem_Behavior.Ignore ->
Nothing
Problem_Behavior.Report_Error ->
result.catch_primitive caught->
Error.throw (Map_Error.Error i caught)
No_Wrap -> result
Problem_Behavior.Report_Warning ->
with_error_maybe = if num_errors.get >= MAX_MAP_WARNINGS then Nothing else
result.catch_primitive caught->
Warning.attach caught Nothing
num_errors.modify (_+1)
with_error_maybe
results = vector_from_function_primitive length wrapped_function
if num_errors.get <= MAX_MAP_WARNINGS then results else
err = Additional_Warnings.Error num_errors.get-MAX_MAP_WARNINGS
Warning.attach err results

## PRIVATE
The maximum number of warnings attached to result values in
`vector_from_function`.
MAX_MAP_WARNINGS = 10
vector_from_function length constructor on_problems = @Builtin_Method "Array_Like_Helpers.vector_from_function"

## PRIVATE
Creates a new vector where for each range, a corresponding section of the
Expand Down Expand Up @@ -258,7 +229,7 @@ transpose vec_of_vecs =
Vector.from_polyglot_array proxy

map vector function on_problems =
vector_from_function vector.length (i-> function (vector.at i)) on_problems
@Tail_Call vector_from_function vector.length (i-> function (vector.at i)) on_problems

map_with_index vector function on_problems =
vector_from_function vector.length (i-> function i (vector.at i)) on_problems
Expand Down
1 change: 0 additions & 1 deletion distribution/manifest.template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@ minimum-project-manager-version: 2023.2.1-nightly.2023.11.2
jvm-options:
- value: "-Dgraal.PrintGraph=Network"
- value: "--add-opens=java.base/java.nio=ALL-UNNAMED"
- value: "-Xss16M"
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.enso.interpreter.node.expression.builtin.error;

import java.util.List;
import org.enso.interpreter.dsl.BuiltinType;
import org.enso.interpreter.node.expression.builtin.UniquelyConstructibleBuiltin;

@BuiltinType
public class AdditionalWarnings extends UniquelyConstructibleBuiltin {

@Override
protected String getConstructorName() {
return "Error";
}

@Override
protected List<String> getConstructorParamNames() {
return List.of("count");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.enso.interpreter.node.expression.builtin.error;

import org.enso.interpreter.dsl.BuiltinType;
import org.enso.interpreter.node.expression.builtin.Builtin;

@BuiltinType(name = "Standard.Base.Data.Vector.No_Wrap")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Off-topic, but I'd like to know the answer: What is name attribute optional? It is specified on some of the builtins, but not on all. Shouldn't it be specified all the time? I am asking because of

the proposed Standard.Prelude should include all the builtins and their methods, but we want to have their names exactly the same as in Standard.Base - can we generate such a Prelude.enso from these annotations?

public class NoWrap extends Builtin {
// Empty on purpose - does not have any constructors
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.enso.interpreter.node.expression.builtin.error;

import java.util.List;
import org.enso.interpreter.dsl.BuiltinType;
import org.enso.interpreter.node.expression.builtin.Builtin;
import org.enso.interpreter.runtime.data.atom.AtomConstructor;

@BuiltinType(name = "Standard.Base.Errors.Problem_Behavior.Problem_Behavior")
public class ProblemBehavior extends Builtin {

@Override
protected List<Cons> getDeclaredConstructors() {
return List.of(new Cons("Ignore"), new Cons("Report_Warning"), new Cons("Report_Error"));
}

public AtomConstructor getIgnore() {
return getConstructors()[0];
}

public AtomConstructor getReportWarning() {
return getConstructors()[1];
}

public AtomConstructor getReportError() {
return getConstructors()[2];
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
package org.enso.interpreter.runtime.data.vector;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.library.CachedLibrary;
import java.nio.ByteBuffer;
import org.enso.interpreter.dsl.Builtin;
import org.enso.interpreter.node.callable.dispatch.InvokeFunctionNode;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.data.EnsoObject;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.state.State;
import org.enso.interpreter.runtime.warning.WarningsLibrary;

/** Publicly available operations on array-like classes. */
@Builtin(pkg = "immutable", stdlibName = "Standard.Base.Internal.Array_Like_Helpers")
Expand Down Expand Up @@ -75,31 +68,6 @@ public static EnsoObject allocate(long size) {
return Array.allocate(size);
}

@Builtin.Method(
name = "vector_from_function",
description = "Creates new Vector with given length and provided elements.",
autoRegister = false)
@Builtin.Specialize()
@SuppressWarnings("generic-enso-builtin-type")
public static Object vectorFromFunction(
VirtualFrame frame,
long length,
Function fun,
State state,
@Cached("buildWithArity(1)") InvokeFunctionNode invokeFunctionNode,
@CachedLibrary(limit = "3") WarningsLibrary warnings) {
var len = Math.toIntExact(length);
var target = ArrayBuilder.newBuilder(len);
for (int i = 0; i < len; i++) {
var value = invokeFunctionNode.execute(fun, frame, state, new Long[] {(long) i});
if (value instanceof DataflowError) {
return value;
}
target.add(value, warnings);
}
return target.asVector(true);
}

@Builtin.Method(
name = "vector_to_array",
description = "Returns an Array representation of this Vector.")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package org.enso.interpreter.runtime.data.vector;

import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.callable.dispatch.InvokeFunctionNode;
import org.enso.interpreter.node.expression.builtin.error.AdditionalWarnings;
import org.enso.interpreter.node.expression.builtin.error.NoWrap;
import org.enso.interpreter.node.expression.builtin.error.ProblemBehavior;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.data.atom.Atom;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
import org.enso.interpreter.runtime.state.State;
import org.enso.interpreter.runtime.warning.AppendWarningNode;
import org.enso.interpreter.runtime.warning.Warning;
import org.enso.interpreter.runtime.warning.WarningsLibrary;

@BuiltinMethod(
type = "Array_Like_Helpers",
name = "vector_from_function",
description = "Creates a vector from a function.")
public abstract class VectorFromFunctionNode extends Node {
public static VectorFromFunctionNode build() {
return VectorFromFunctionNodeGen.create();
}

private static final int MAX_MAP_WARNINGS = 10;

/**
* @param length Length of the vector to create.
* @param func Callback function called with index as argument.
* @param onProblems Can be either an atom of type {@code Problem_Behavior} or {@code No_Wrap}
* type.
* @return Vector constructed from the given function.
*/
abstract Object execute(
VirtualFrame frame, State state, long length, Function func, Object onProblems);

@Specialization
Object doIt(
VirtualFrame frame,
State state,
long length,
Function func,
Object onProblemsAtom,
@Cached("buildWithArity(1)") InvokeFunctionNode invokeFunctionNode,
@Cached("build()") AppendWarningNode appendWarningNode,
@CachedLibrary(limit = "3") WarningsLibrary warnsLib,
@CachedLibrary(limit = "3") TypesLibrary typesLib,
@Cached BranchProfile errorEncounteredProfile) {
var ctx = EnsoContext.get(this);
var onProblems = processOnProblemsArg(onProblemsAtom, typesLib);
var len = Math.toIntExact(length);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What will happen on ArithmeticException? It shouldn't crash the interpreter.

var nothing = ctx.getNothing();
var target = ArrayBuilder.newBuilder(len);
var errorsEncountered = 0;
for (int i = 0; i < len; i++) {
var value = invokeFunctionNode.execute(func, frame, state, new Long[] {(long) i});
Object valueToAdd = value;
if (value instanceof DataflowError err) {
errorEncounteredProfile.enter();
switch (onProblems) {
Akirathan marked this conversation as resolved.
Show resolved Hide resolved
case IGNORE -> valueToAdd = nothing;
case REPORT_ERROR -> {
var mapErr = ctx.getBuiltins().error().makeMapError(i, err.getPayload());
return DataflowError.withDefaultTrace(state, mapErr, this);
}
case REPORT_WARNING -> {
errorsEncountered++;
if (errorsEncountered > MAX_MAP_WARNINGS) {
valueToAdd = nothing;
} else {
var wrappedInWarn =
Warning.attach(ctx, nothing, err.getPayload(), null, appendWarningNode);
valueToAdd = wrappedInWarn;
}
}
case NO_WRAP -> {
return err;
}
}
}
target.add(valueToAdd, warnsLib);
}
var vector = target.asVector(true);
if (errorsEncountered >= MAX_MAP_WARNINGS) {
var additionalWarnsBuiltin = ctx.getBuiltins().getBuiltinType(AdditionalWarnings.class);
long additionalWarnsCnt = errorsEncountered - MAX_MAP_WARNINGS;
var additionalWarns = additionalWarnsBuiltin.newInstance(additionalWarnsCnt);
var vecWithAdditionalWarns =
Warning.attach(ctx, vector, additionalWarns, null, appendWarningNode);
return vecWithAdditionalWarns;
} else {
return vector;
}
}

private OnProblems processOnProblemsArg(Object onProblems, TypesLibrary typesLib) {
var ctx = EnsoContext.get(this);
var problemBehaviorBuiltin = ctx.getBuiltins().getBuiltinType(ProblemBehavior.class);
var noWrapBuiltin = ctx.getBuiltins().getBuiltinType(NoWrap.class);
var typeError =
Akirathan marked this conversation as resolved.
Show resolved Hide resolved
ctx.getBuiltins()
.error()
.makeTypeError(problemBehaviorBuiltin.getType(), onProblems, "onProblems");
if (onProblems instanceof Atom onProblemsAtom) {
if (isIgnore(onProblemsAtom, problemBehaviorBuiltin)) {
return OnProblems.IGNORE;
} else if (isReportError(onProblemsAtom, problemBehaviorBuiltin)) {
return OnProblems.REPORT_ERROR;
} else if (isReportWarning(onProblemsAtom, problemBehaviorBuiltin)) {
return OnProblems.REPORT_WARNING;
}
}
if (!typesLib.hasType(onProblems)) {
throw new PanicException(typeError, this);
}
var onProblemsType = typesLib.getType(onProblems);
if (onProblemsType == noWrapBuiltin.getType()) {
return OnProblems.NO_WRAP;
}
throw new PanicException(typeError, this);
}

private static boolean isReportWarning(Atom onProblems, ProblemBehavior problemBehaviorBuiltin) {
return onProblems.getConstructor() == problemBehaviorBuiltin.getReportWarning();
}

private static boolean isReportError(Atom onProblems, ProblemBehavior problemBehaviorBuiltin) {
return onProblems.getConstructor() == problemBehaviorBuiltin.getReportError();
}

private static boolean isIgnore(Atom onProblems, ProblemBehavior problemBehaviorBuiltin) {
return onProblems.getConstructor() == problemBehaviorBuiltin.getIgnore();
}

private enum OnProblems {
IGNORE,
REPORT_ERROR,
REPORT_WARNING,
NO_WRAP
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Cached.Shared;
import com.oracle.truffle.api.dsl.GenerateUncached;
import com.oracle.truffle.api.dsl.NeverDefault;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.InteropLibrary;
Expand All @@ -24,6 +25,7 @@
@GenerateUncached
public abstract class AppendWarningNode extends Node {

@NeverDefault
public static AppendWarningNode build() {
return AppendWarningNodeGen.create();
}
Expand Down
Loading
Loading