mirror of
https://github.com/enso-org/enso.git
synced 2024-11-22 11:52:59 +03:00
Convert Array_Like_Helpers.map
to a builtin to reduce stack size (#11363)
The ultimate goal is to reduce the method calls necessary for `Vector.map`. # Important Notes - I managed to reduce the number of Java stack frames needed for each `Vector.map` call from **150** to **22** (See https://github.com/enso-org/enso/pull/11363#issuecomment-2432996902) - Introduced `Stack_Size_Spec` regression test that will ensure that Java stack frames needed for `Vector.map` method call does not exceed **40**.
This commit is contained in:
parent
9703cb1dd0
commit
701bba6504
@ -1,5 +1,5 @@
|
|||||||
COMP_PATH=$(dirname "$0")/../component
|
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 "$@"
|
exec java --module-path $COMP_PATH $JAVA_OPTS -m org.enso.runner/org.enso.runner.Main "$@"
|
||||||
exit
|
exit
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
@echo off
|
@echo off
|
||||||
set comp-dir=%~dp0\..\component
|
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 %*
|
java --module-path %comp-dir% -Dpolyglot.compiler.IterativePartialEscape=true %JAVA_OPTS% -m org.enso.runner/org.enso.runner.Main %*
|
||||||
exit /B %errorlevel%
|
exit /B %errorlevel%
|
||||||
|
@ -173,7 +173,7 @@ type JS_Object
|
|||||||
mapper = ObjectMapper.new
|
mapper = ObjectMapper.new
|
||||||
new_object = mapper.createObjectNode
|
new_object = mapper.createObjectNode
|
||||||
keys = Vector.build builder->
|
keys = Vector.build builder->
|
||||||
pairs.map on_problems=No_Wrap pair->
|
pairs.map on_problems=No_Wrap.Value pair->
|
||||||
case pair.first of
|
case pair.first of
|
||||||
text : Text ->
|
text : Text ->
|
||||||
## Ensure that any dataflow errors that could be stored in `pair.second` are propagated.
|
## Ensure that any dataflow errors that could be stored in `pair.second` are propagated.
|
||||||
|
@ -190,7 +190,7 @@ type Statistic
|
|||||||
compute_bulk : Vector -> Vector Statistic -> Vector Any
|
compute_bulk : Vector -> Vector Statistic -> Vector Any
|
||||||
compute_bulk data statistics:Vector=[Statistic.Count, Statistic.Sum] =
|
compute_bulk data statistics:Vector=[Statistic.Count, Statistic.Sum] =
|
||||||
resolved_stats = statistics.map (r-> r:Statistic)
|
resolved_stats = statistics.map (r-> r:Statistic)
|
||||||
moment_order = resolved_stats.map on_problems=No_Wrap .order
|
moment_order = resolved_stats.map on_problems=No_Wrap.Value .order
|
||||||
has_min_max = resolved_stats.any (s-> s == Statistic.Minimum || s == Statistic.Maximum)
|
has_min_max = resolved_stats.any (s-> s == Statistic.Minimum || s == Statistic.Maximum)
|
||||||
has_product = resolved_stats.any (s-> s == Statistic.Product)
|
has_product = resolved_stats.any (s-> s == Statistic.Product)
|
||||||
max_moment_order = moment_order.filter (v-> v != Nothing) . fold 0 .max
|
max_moment_order = moment_order.filter (v-> v != Nothing) . fold 0 .max
|
||||||
@ -202,7 +202,7 @@ type Statistic
|
|||||||
Error.throw (Illegal_Argument.Error ("Can only compute " + stat.to_text + " on numerical data sets."))
|
Error.throw (Illegal_Argument.Error ("Can only compute " + stat.to_text + " on numerical data sets."))
|
||||||
|
|
||||||
if max_moment_order > 0 && counter.moments.is_nothing then report_error resolved_stats else
|
if max_moment_order > 0 && counter.moments.is_nothing then report_error resolved_stats else
|
||||||
resolved_stats.map on_problems=No_Wrap statistic-> case statistic of
|
resolved_stats.map on_problems=No_Wrap.Value statistic-> case statistic of
|
||||||
Statistic.Covariance series -> check_if_empty counter.count <| calculate_correlation_statistics data series . covariance
|
Statistic.Covariance series -> check_if_empty counter.count <| calculate_correlation_statistics data series . covariance
|
||||||
Statistic.Pearson series -> check_if_empty counter.count <| calculate_correlation_statistics data series . pearsonCorrelation
|
Statistic.Pearson series -> check_if_empty counter.count <| calculate_correlation_statistics data series . pearsonCorrelation
|
||||||
Statistic.R_Squared series -> check_if_empty counter.count <| calculate_correlation_statistics data series . rSquared
|
Statistic.R_Squared series -> check_if_empty counter.count <| calculate_correlation_statistics data series . rSquared
|
||||||
@ -229,7 +229,7 @@ type Statistic
|
|||||||
running_bulk data statistics=[Statistic.Count, Statistic.Sum] =
|
running_bulk data statistics=[Statistic.Count, Statistic.Sum] =
|
||||||
resolved_stats = statistics.map (r-> r:Statistic)
|
resolved_stats = statistics.map (r-> r:Statistic)
|
||||||
check_running_support resolved_stats <|
|
check_running_support resolved_stats <|
|
||||||
moment_order = resolved_stats.map on_problems=No_Wrap .order
|
moment_order = resolved_stats.map on_problems=No_Wrap.Value .order
|
||||||
has_min_max = resolved_stats.any (s-> s == Statistic.Minimum || s == Statistic.Maximum)
|
has_min_max = resolved_stats.any (s-> s == Statistic.Minimum || s == Statistic.Maximum)
|
||||||
has_product = resolved_stats.any (s-> s == Statistic.Product)
|
has_product = resolved_stats.any (s-> s == Statistic.Product)
|
||||||
max_moment_order = moment_order.filter (v-> v != Nothing) . fold 0 .max
|
max_moment_order = moment_order.filter (v-> v != Nothing) . fold 0 .max
|
||||||
@ -241,7 +241,7 @@ type Statistic
|
|||||||
data.fold counter current->value->
|
data.fold counter current->value->
|
||||||
result = compute_fold current value
|
result = compute_fold current value
|
||||||
|
|
||||||
row = Panic.rethrow_wrapped_if_error <| resolved_stats.map on_problems=No_Wrap s-> case s of
|
row = Panic.rethrow_wrapped_if_error <| resolved_stats.map on_problems=No_Wrap.Value s-> case s of
|
||||||
Statistic.Maximum -> if result.count == 0 then Nothing else result.maximum
|
Statistic.Maximum -> if result.count == 0 then Nothing else result.maximum
|
||||||
Statistic.Minimum -> if result.count == 0 then Nothing else result.minimum
|
Statistic.Minimum -> if result.count == 0 then Nothing else result.minimum
|
||||||
_ -> result.compute s
|
_ -> result.compute s
|
||||||
|
@ -71,7 +71,7 @@ type Vector a
|
|||||||
|
|
||||||
Vector.new my_vec.length (ix -> my_vec.at ix)
|
Vector.new my_vec.length (ix -> my_vec.at ix)
|
||||||
new : Integer -> (Integer -> Any) -> Vector Any
|
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
|
## PRIVATE
|
||||||
ADVANCED
|
ADVANCED
|
||||||
@ -700,7 +700,7 @@ type Vector a
|
|||||||
[1, 2, 3] . map +1
|
[1, 2, 3] . map +1
|
||||||
map : (Any -> Any) -> Problem_Behavior | No_Wrap -> Vector Any
|
map : (Any -> Any) -> Problem_Behavior | No_Wrap -> Vector Any
|
||||||
map self function on_problems:(Problem_Behavior | No_Wrap)=..Report_Error =
|
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
|
## ICON union
|
||||||
Applies a function to each element of the vector, returning the `Vector`
|
Applies a function to each element of the vector, returning the `Vector`
|
||||||
@ -1556,7 +1556,9 @@ type Map_Error
|
|||||||
|
|
||||||
## PRIVATE
|
## PRIVATE
|
||||||
Indicates that a method should not wrap thrown errors in `Map_Error`.
|
Indicates that a method should not wrap thrown errors in `Map_Error`.
|
||||||
|
@Builtin_Type
|
||||||
type No_Wrap
|
type No_Wrap
|
||||||
|
Value
|
||||||
|
|
||||||
## PRIVATE
|
## PRIVATE
|
||||||
Wrapped_Error.from (that : Map_Error) = Wrapped_Error.Value that that.inner_error
|
Wrapped_Error.from (that : Map_Error) = Wrapped_Error.Value that that.inner_error
|
||||||
|
@ -510,6 +510,7 @@ type Missing_Argument
|
|||||||
Error.throw (Missing_Argument.Error argument_name function_name call_location)
|
Error.throw (Missing_Argument.Error argument_name function_name call_location)
|
||||||
|
|
||||||
## Warning when additional warnings occurred.
|
## Warning when additional warnings occurred.
|
||||||
|
@Builtin_Type
|
||||||
type Additional_Warnings
|
type Additional_Warnings
|
||||||
## PRIVATE
|
## PRIVATE
|
||||||
Error (count:Integer)
|
Error (count:Integer)
|
||||||
|
@ -4,6 +4,7 @@ import project.Error.Error
|
|||||||
import project.Warning.Warning
|
import project.Warning.Warning
|
||||||
|
|
||||||
## Specifies how to handle problems.
|
## Specifies how to handle problems.
|
||||||
|
@Builtin_Type
|
||||||
type Problem_Behavior
|
type Problem_Behavior
|
||||||
## Ignore the problem and attempt to complete the operation
|
## Ignore the problem and attempt to complete the operation
|
||||||
Ignore
|
Ignore
|
||||||
|
@ -45,9 +45,6 @@ at array_like index = @Builtin_Method "Array_Like_Helpers.at"
|
|||||||
vector_to_array : (Vector | Array) -> Array
|
vector_to_array : (Vector | Array) -> Array
|
||||||
vector_to_array array_like = @Builtin_Method "Array_Like_Helpers.vector_to_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 : (Vector | Array) -> Vector
|
||||||
flatten array_like = @Builtin_Method "Array_Like_Helpers.flatten"
|
flatten array_like = @Builtin_Method "Array_Like_Helpers.flatten"
|
||||||
|
|
||||||
@ -84,33 +81,7 @@ slice vector start end = @Builtin_Method "Array_Like_Helpers.slice"
|
|||||||
- Ignore: The result is `Nothing`, and the error is
|
- Ignore: The result is `Nothing`, and the error is
|
||||||
ignored.
|
ignored.
|
||||||
vector_from_function : Integer -> (Integer -> Any) -> Problem_Behavior | No_Wrap -> Vector Any
|
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 =
|
vector_from_function length constructor on_problems = @Builtin_Method "Array_Like_Helpers.vector_from_function"
|
||||||
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
|
|
||||||
|
|
||||||
## PRIVATE
|
## PRIVATE
|
||||||
Creates a new vector where for each range, a corresponding section of the
|
Creates a new vector where for each range, a corresponding section of the
|
||||||
@ -258,7 +229,7 @@ transpose vec_of_vecs =
|
|||||||
Vector.from_polyglot_array proxy
|
Vector.from_polyglot_array proxy
|
||||||
|
|
||||||
map vector function on_problems =
|
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 =
|
map_with_index vector function on_problems =
|
||||||
vector_from_function vector.length (i-> function i (vector.at i)) on_problems
|
vector_from_function vector.length (i-> function i (vector.at i)) on_problems
|
||||||
|
@ -22,6 +22,7 @@ polyglot java import java.time.LocalDate
|
|||||||
polyglot java import java.time.LocalDateTime
|
polyglot java import java.time.LocalDateTime
|
||||||
polyglot java import java.util.function.Function
|
polyglot java import java.util.function.Function
|
||||||
polyglot java import java.lang.Exception as JException
|
polyglot java import java.lang.Exception as JException
|
||||||
|
polyglot java import java.lang.RuntimeException as JRuntimeException
|
||||||
polyglot java import java.lang.Thread
|
polyglot java import java.lang.Thread
|
||||||
polyglot java import java.lang.Thread.State
|
polyglot java import java.lang.Thread.State
|
||||||
polyglot java import java.lang.Float
|
polyglot java import java.lang.Float
|
||||||
@ -39,3 +40,4 @@ CaseFoldedString=JCaseFoldedString
|
|||||||
Text_Utils=JText_Utils
|
Text_Utils=JText_Utils
|
||||||
BreakIterator=JBreakIterator
|
BreakIterator=JBreakIterator
|
||||||
Exception=JException
|
Exception=JException
|
||||||
|
RuntimeException=JRuntimeException
|
||||||
|
@ -165,7 +165,7 @@ type HTTP
|
|||||||
# Create Unified Header list
|
# Create Unified Header list
|
||||||
boundary_header_list = if resolved_body.boundary.is_nothing then [] else [Header.multipart_form_data resolved_body.boundary]
|
boundary_header_list = if resolved_body.boundary.is_nothing then [] else [Header.multipart_form_data resolved_body.boundary]
|
||||||
all_headers = headers + boundary_header_list
|
all_headers = headers + boundary_header_list
|
||||||
mapped_headers = all_headers.map on_problems=No_Wrap .to_java_pair
|
mapped_headers = all_headers.map on_problems=No_Wrap.Value .to_java_pair
|
||||||
|
|
||||||
response = Response.Value (EnsoSecretHelper.makeRequest (self.make_client self resolved_body.hash) builder req.uri.to_java_representation mapped_headers (cache_policy.should_use_cache req))
|
response = Response.Value (EnsoSecretHelper.makeRequest (self.make_client self resolved_body.hash) builder req.uri.to_java_representation mapped_headers (cache_policy.should_use_cache req))
|
||||||
if error_on_failure_code.not || response.code.is_success then response else
|
if error_on_failure_code.not || response.code.is_success then response else
|
||||||
|
@ -30,7 +30,7 @@ type Header
|
|||||||
`Header` values.
|
`Header` values.
|
||||||
unify_vector : Vector (Header | Pair Text Text | Vector) -> Vector Header
|
unify_vector : Vector (Header | Pair Text Text | Vector) -> Vector Header
|
||||||
unify_vector headers:Vector =
|
unify_vector headers:Vector =
|
||||||
headers . map on_problems=No_Wrap h-> case h of
|
headers . map on_problems=No_Wrap.Value h-> case h of
|
||||||
_ : Vector -> Header.new (h.at 0) (h.at 1)
|
_ : Vector -> Header.new (h.at 0) (h.at 1)
|
||||||
_ : Pair -> Header.new (h.at 0) (h.at 1)
|
_ : Pair -> Header.new (h.at 0) (h.at 1)
|
||||||
_ : Function -> h:Header
|
_ : Function -> h:Header
|
||||||
|
@ -296,7 +296,7 @@ set_array value warnings = @Builtin_Method "Warning.set_array"
|
|||||||
map_attached_warnings_helper : (Any -> Maybe Any) -> Any -> Integer -> Any
|
map_attached_warnings_helper : (Any -> Maybe Any) -> Any -> Integer -> Any
|
||||||
map_attached_warnings_helper mapper value frames_to_drop =
|
map_attached_warnings_helper mapper value frames_to_drop =
|
||||||
warnings = Warning.get_all value
|
warnings = Warning.get_all value
|
||||||
mapped_warnings = warnings.map on_problems=No_Wrap warning->
|
mapped_warnings = warnings.map on_problems=No_Wrap.Value warning->
|
||||||
case mapper warning.value of
|
case mapper warning.value of
|
||||||
Maybe.Some new_payload ->
|
Maybe.Some new_payload ->
|
||||||
self_call_name = "Warning.map_attached_warnings_helper"
|
self_call_name = "Warning.map_attached_warnings_helper"
|
||||||
|
@ -71,7 +71,7 @@ run_transaction_with_tables connection (tables : Vector Transactional_Table_Desc
|
|||||||
## PRIVATE
|
## PRIVATE
|
||||||
private create_tables_inside_transaction connection (tables : Vector Transactional_Table_Description) (callback : Vector DB_Table -> Any) -> Any =
|
private create_tables_inside_transaction connection (tables : Vector Transactional_Table_Description) (callback : Vector DB_Table -> Any) -> Any =
|
||||||
connection.jdbc_connection.run_within_transaction <|
|
connection.jdbc_connection.run_within_transaction <|
|
||||||
created = tables.map on_problems=No_Wrap t-> t.create connection
|
created = tables.map on_problems=No_Wrap.Value t-> t.create connection
|
||||||
created.if_not_error <|
|
created.if_not_error <|
|
||||||
result = callback created
|
result = callback created
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ private create_tables_outside_transaction connection (tables : Vector Transactio
|
|||||||
Panic.throw caught_panic
|
Panic.throw caught_panic
|
||||||
|
|
||||||
Panic.catch Any handler=handle_panic <|
|
Panic.catch Any handler=handle_panic <|
|
||||||
created = tables.map on_problems=No_Wrap t->
|
created = tables.map on_problems=No_Wrap.Value t->
|
||||||
table = t.create connection
|
table = t.create connection
|
||||||
# We only register a table for cleanup if it was successfully created.
|
# We only register a table for cleanup if it was successfully created.
|
||||||
table.if_not_error <|
|
table.if_not_error <|
|
||||||
|
@ -160,8 +160,8 @@ type Context
|
|||||||
rewrite_internal_column column =
|
rewrite_internal_column column =
|
||||||
Internal_Column.Value column.name column.sql_type_reference (SQL_Expression.Column alias column.name)
|
Internal_Column.Value column.name column.sql_type_reference (SQL_Expression.Column alias column.name)
|
||||||
|
|
||||||
new_columns = column_lists.map on_problems=No_Wrap columns->
|
new_columns = column_lists.map on_problems=No_Wrap.Value columns->
|
||||||
columns.map on_problems=No_Wrap rewrite_internal_column
|
columns.map on_problems=No_Wrap.Value rewrite_internal_column
|
||||||
|
|
||||||
encapsulated_columns = column_lists.flat_map columns->
|
encapsulated_columns = column_lists.flat_map columns->
|
||||||
columns.map column-> [column.name, column.expression]
|
columns.map column-> [column.name, column.expression]
|
||||||
|
@ -34,7 +34,7 @@ check_target_table_for_update target_table ~action = case target_table of
|
|||||||
resolve_primary_key structure primary_key = case primary_key of
|
resolve_primary_key structure primary_key = case primary_key of
|
||||||
Nothing -> Nothing
|
Nothing -> Nothing
|
||||||
_ : Vector -> if primary_key.is_empty then Nothing else
|
_ : Vector -> if primary_key.is_empty then Nothing else
|
||||||
validated = primary_key.map on_problems=No_Wrap key->
|
validated = primary_key.map on_problems=No_Wrap.Value key->
|
||||||
if key.is_a Text then key else
|
if key.is_a Text then key else
|
||||||
Error.throw (Illegal_Argument.Error ("Primary key must be a vector of column names, instead got a " + (Meta.type_of key . to_display_text)))
|
Error.throw (Illegal_Argument.Error ("Primary key must be a vector of column names, instead got a " + (Meta.type_of key . to_display_text)))
|
||||||
validated.if_not_error <|
|
validated.if_not_error <|
|
||||||
@ -74,6 +74,6 @@ check_update_arguments_structure_match source_table target_table key_columns upd
|
|||||||
if missing_target_key_columns.not_empty then Error.throw (Missing_Input_Columns.Error missing_target_key_columns.to_vector "the target table") else
|
if missing_target_key_columns.not_empty then Error.throw (Missing_Input_Columns.Error missing_target_key_columns.to_vector "the target table") else
|
||||||
if (update_action != Update_Action.Insert) && key_columns.is_empty then Error.throw (Illegal_Argument.Error "For the `update_action = "+update_action.to_text+"`, the `key_columns` must be specified to define how to match the records.") else
|
if (update_action != Update_Action.Insert) && key_columns.is_empty then Error.throw (Illegal_Argument.Error "For the `update_action = "+update_action.to_text+"`, the `key_columns` must be specified to define how to match the records.") else
|
||||||
# Verify type matching
|
# Verify type matching
|
||||||
problems = source_table.columns.flat_map on_problems=No_Wrap check_source_column
|
problems = source_table.columns.flat_map on_problems=No_Wrap.Value check_source_column
|
||||||
problems.if_not_error <|
|
problems.if_not_error <|
|
||||||
on_problems.attach_problems_before problems action
|
on_problems.attach_problems_before problems action
|
||||||
|
@ -30,7 +30,7 @@ make_batched_insert_template connection table_name column_names =
|
|||||||
prepare_create_table_statement : Connection -> Text -> Vector Column_Description -> Vector Text -> Boolean -> Problem_Behavior -> SQL_Statement
|
prepare_create_table_statement : Connection -> Text -> Vector Column_Description -> Vector Text -> Boolean -> Problem_Behavior -> SQL_Statement
|
||||||
prepare_create_table_statement connection table_name columns primary_key temporary on_problems:Problem_Behavior =
|
prepare_create_table_statement connection table_name columns primary_key temporary on_problems:Problem_Behavior =
|
||||||
type_mapping = connection.dialect.get_type_mapping
|
type_mapping = connection.dialect.get_type_mapping
|
||||||
column_descriptors = columns.map on_problems=No_Wrap def->
|
column_descriptors = columns.map on_problems=No_Wrap.Value def->
|
||||||
sql_type = type_mapping.value_type_to_sql def.value_type on_problems
|
sql_type = type_mapping.value_type_to_sql def.value_type on_problems
|
||||||
sql_type_text = type_mapping.sql_type_to_text sql_type
|
sql_type_text = type_mapping.sql_type_to_text sql_type
|
||||||
Create_Column_Descriptor.Value def.name sql_type_text def.constraints
|
Create_Column_Descriptor.Value def.name sql_type_text def.constraints
|
||||||
|
@ -31,7 +31,7 @@ take_drop_helper take_drop table selector:(Index_Sub_Range | Range | Integer) =
|
|||||||
row_column_name = table.make_temp_column_name
|
row_column_name = table.make_temp_column_name
|
||||||
table_with_row_number = table.add_row_number name=row_column_name from=0
|
table_with_row_number = table.add_row_number name=row_column_name from=0
|
||||||
|
|
||||||
subqueries = ranges.map on_problems=No_Wrap range->
|
subqueries = ranges.map on_problems=No_Wrap.Value range->
|
||||||
generate_subquery table_with_row_number row_column_name range
|
generate_subquery table_with_row_number row_column_name range
|
||||||
combined = subqueries.reduce (a-> b-> a.union b)
|
combined = subqueries.reduce (a-> b-> a.union b)
|
||||||
combined.remove_columns row_column_name
|
combined.remove_columns row_column_name
|
||||||
|
@ -2101,7 +2101,7 @@ type Column
|
|||||||
map : (Any -> Any) -> Boolean -> Value_Type | Auto -> Column ! Invalid_Value_Type
|
map : (Any -> Any) -> Boolean -> Value_Type | Auto -> Column ! Invalid_Value_Type
|
||||||
map self function skip_nothing=True expected_value_type=Auto =
|
map self function skip_nothing=True expected_value_type=Auto =
|
||||||
new_fn = if skip_nothing then (x-> if x.is_nothing then Nothing else function x) else function
|
new_fn = if skip_nothing then (x-> if x.is_nothing then Nothing else function x) else function
|
||||||
new_st = self.to_vector.map on_problems=No_Wrap new_fn
|
new_st = self.to_vector.map on_problems=No_Wrap.Value new_fn
|
||||||
Column.from_vector self.name new_st value_type=expected_value_type
|
Column.from_vector self.name new_st value_type=expected_value_type
|
||||||
|
|
||||||
## ALIAS combine, join by row position, merge
|
## ALIAS combine, join by row position, merge
|
||||||
@ -2149,7 +2149,7 @@ type Column
|
|||||||
function x y
|
function x y
|
||||||
False -> function
|
False -> function
|
||||||
new_name = naming_helper.binary_operation_name "x" self that
|
new_name = naming_helper.binary_operation_name "x" self that
|
||||||
vec = self.to_vector.zip on_problems=No_Wrap that.to_vector new_fn
|
vec = self.to_vector.zip on_problems=No_Wrap.Value that.to_vector new_fn
|
||||||
Column.from_vector new_name vec value_type=expected_value_type
|
Column.from_vector new_name vec value_type=expected_value_type
|
||||||
|
|
||||||
## GROUP Standard.Base.Metadata
|
## GROUP Standard.Base.Metadata
|
||||||
|
@ -129,7 +129,7 @@ type Data_Formatter
|
|||||||
vector = case formats of
|
vector = case formats of
|
||||||
v : Vector -> v
|
v : Vector -> v
|
||||||
singleton -> [singleton]
|
singleton -> [singleton]
|
||||||
converted = vector.map on_problems=No_Wrap elem->
|
converted = vector.map on_problems=No_Wrap.Value elem->
|
||||||
## Ensure the element is a `Date_Time_Formatter` or is converted to it.
|
## Ensure the element is a `Date_Time_Formatter` or is converted to it.
|
||||||
We need to convert _each_ element - we cannot perform a 'bulk' conversion like `vector : Vector Date_Time_Formatter` because of erasure.
|
We need to convert _each_ element - we cannot perform a 'bulk' conversion like `vector : Vector Date_Time_Formatter` because of erasure.
|
||||||
checked = elem : Date_Time_Formatter
|
checked = elem : Date_Time_Formatter
|
||||||
@ -216,17 +216,17 @@ type Data_Formatter
|
|||||||
## PRIVATE
|
## PRIVATE
|
||||||
make_date_parser self = self.wrap_base_parser <|
|
make_date_parser self = self.wrap_base_parser <|
|
||||||
Panic.catch JException handler=(caught_panic-> Error.throw (Illegal_Argument.Error caught_panic.payload.getMessage)) <|
|
Panic.catch JException handler=(caught_panic-> Error.throw (Illegal_Argument.Error caught_panic.payload.getMessage)) <|
|
||||||
DateParser.new (self.date_formats.map on_problems=No_Wrap .get_java_formatter_for_parsing)
|
DateParser.new (self.date_formats.map on_problems=No_Wrap.Value .get_java_formatter_for_parsing)
|
||||||
|
|
||||||
## PRIVATE
|
## PRIVATE
|
||||||
make_date_time_parser self = self.wrap_base_parser <|
|
make_date_time_parser self = self.wrap_base_parser <|
|
||||||
Panic.catch JException handler=(caught_panic-> Error.throw (Illegal_Argument.Error caught_panic.payload.getMessage)) <|
|
Panic.catch JException handler=(caught_panic-> Error.throw (Illegal_Argument.Error caught_panic.payload.getMessage)) <|
|
||||||
DateTimeParser.new (self.datetime_formats.map on_problems=No_Wrap .get_java_formatter_for_parsing)
|
DateTimeParser.new (self.datetime_formats.map on_problems=No_Wrap.Value .get_java_formatter_for_parsing)
|
||||||
|
|
||||||
## PRIVATE
|
## PRIVATE
|
||||||
make_time_of_day_parser self = self.wrap_base_parser <|
|
make_time_of_day_parser self = self.wrap_base_parser <|
|
||||||
Panic.catch JException handler=(caught_panic-> Error.throw (Illegal_Argument.Error caught_panic.payload.getMessage)) <|
|
Panic.catch JException handler=(caught_panic-> Error.throw (Illegal_Argument.Error caught_panic.payload.getMessage)) <|
|
||||||
TimeOfDayParser.new (self.time_formats.map on_problems=No_Wrap .get_java_formatter_for_parsing)
|
TimeOfDayParser.new (self.time_formats.map on_problems=No_Wrap.Value .get_java_formatter_for_parsing)
|
||||||
|
|
||||||
## PRIVATE
|
## PRIVATE
|
||||||
make_identity_parser self = self.wrap_base_parser IdentityParser.new
|
make_identity_parser self = self.wrap_base_parser IdentityParser.new
|
||||||
|
@ -67,7 +67,7 @@ prepare_aggregate_columns naming_helper group_by aggregates table error_on_missi
|
|||||||
assert (resolved_keys.contains Nothing . not)
|
assert (resolved_keys.contains Nothing . not)
|
||||||
problem_builder = Problem_Builder.new error_on_missing_columns=error_on_missing_columns
|
problem_builder = Problem_Builder.new error_on_missing_columns=error_on_missing_columns
|
||||||
columns = if old_style then group_by else keys+aggregates
|
columns = if old_style then group_by else keys+aggregates
|
||||||
valid_resolved_aggregate_columns = columns.map on_problems=No_Wrap (resolve_aggregate table problem_builder) . filter x-> x.is_nothing.not
|
valid_resolved_aggregate_columns = columns.map on_problems=No_Wrap.Value (resolve_aggregate table problem_builder) . filter x-> x.is_nothing.not
|
||||||
|
|
||||||
# Grouping Key
|
# Grouping Key
|
||||||
key_columns = resolved_keys.map .column
|
key_columns = resolved_keys.map .column
|
||||||
@ -80,7 +80,7 @@ prepare_aggregate_columns naming_helper group_by aggregates table error_on_missi
|
|||||||
The second pass resolves the default names, ensuring that they do not
|
The second pass resolves the default names, ensuring that they do not
|
||||||
clash with the user-specified names (ensuring that user-specified names
|
clash with the user-specified names (ensuring that user-specified names
|
||||||
take precedence).
|
take precedence).
|
||||||
pass_1 = valid_resolved_aggregate_columns.map on_problems=No_Wrap c-> if c.as == "" then "" else
|
pass_1 = valid_resolved_aggregate_columns.map on_problems=No_Wrap.Value c-> if c.as == "" then "" else
|
||||||
# Verify if the user-provided name is valid and if not, throw an error.
|
# Verify if the user-provided name is valid and if not, throw an error.
|
||||||
naming_helper.ensure_name_is_valid c.as <|
|
naming_helper.ensure_name_is_valid c.as <|
|
||||||
unique.make_unique c.as
|
unique.make_unique c.as
|
||||||
|
@ -89,7 +89,7 @@ unpack_problem_summary problem_summary =
|
|||||||
## TODO [RW, GT] In the next iterations we will want to remove
|
## TODO [RW, GT] In the next iterations we will want to remove
|
||||||
`translate_problem` in favour of constructing Enso problem instances
|
`translate_problem` in favour of constructing Enso problem instances
|
||||||
directly in Java code. To do so, we will need https://github.com/enso-org/enso/issues/7797
|
directly in Java code. To do so, we will need https://github.com/enso-org/enso/issues/7797
|
||||||
parsed = problems_array . map on_problems=No_Wrap translate_problem
|
parsed = problems_array . map on_problems=No_Wrap.Value translate_problem
|
||||||
if count == parsed.length then parsed else
|
if count == parsed.length then parsed else
|
||||||
parsed + [Additional_Warnings.Error (count - parsed.length)]
|
parsed + [Additional_Warnings.Error (count - parsed.length)]
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ type Join_Condition_Resolver
|
|||||||
is_nothing column = case column of
|
is_nothing column = case column of
|
||||||
Nothing -> True
|
Nothing -> True
|
||||||
_ -> False
|
_ -> False
|
||||||
conditions_vector = Vector.unify_vector_or_element conditions . map on_problems=No_Wrap condition-> (condition:Join_Condition)
|
conditions_vector = Vector.unify_vector_or_element conditions . map on_problems=No_Wrap.Value condition-> (condition:Join_Condition)
|
||||||
handle_equals left_selector right_selector =
|
handle_equals left_selector right_selector =
|
||||||
left = resolve_left left_selector
|
left = resolve_left left_selector
|
||||||
right = resolve_right right_selector
|
right = resolve_right right_selector
|
||||||
@ -52,7 +52,7 @@ type Join_Condition_Resolver
|
|||||||
if left.name == right.name then
|
if left.name == right.name then
|
||||||
redundant_names.append right.name
|
redundant_names.append right.name
|
||||||
self.make_equals problem_builder left right
|
self.make_equals problem_builder left right
|
||||||
converted = conditions_vector.map on_problems=No_Wrap condition-> case condition of
|
converted = conditions_vector.map on_problems=No_Wrap.Value condition-> case condition of
|
||||||
Join_Condition.Equals left_selector right_selector ->
|
Join_Condition.Equals left_selector right_selector ->
|
||||||
right_resovled = if right_selector == "" then left_selector else right_selector
|
right_resovled = if right_selector == "" then left_selector else right_selector
|
||||||
handle_equals left_selector right_resovled
|
handle_equals left_selector right_resovled
|
||||||
|
@ -51,7 +51,7 @@ prepare_columns_for_lookup base_table lookup_table key_columns_selector add_new_
|
|||||||
problems_to_add = Builder.new
|
problems_to_add = Builder.new
|
||||||
key_columns.if_not_error <| lookup_table_key_columns.if_not_error <|
|
key_columns.if_not_error <| lookup_table_key_columns.if_not_error <|
|
||||||
key_set = Hashset.from_vector key_columns
|
key_set = Hashset.from_vector key_columns
|
||||||
my_updated_columns = base_table.columns.map on_problems=No_Wrap base_column->
|
my_updated_columns = base_table.columns.map on_problems=No_Wrap.Value base_column->
|
||||||
base_column_name = base_column.name
|
base_column_name = base_column.name
|
||||||
is_key = key_set.contains base_column_name
|
is_key = key_set.contains base_column_name
|
||||||
case is_key of
|
case is_key of
|
||||||
|
@ -582,5 +582,5 @@ replace_columns_with_transformed_columns : Table -> Text | Integer | Regex | Vec
|
|||||||
replace_columns_with_transformed_columns table selectors transformer error_on_missing_columns=True on_problems:Problem_Behavior=..Report_Warning =
|
replace_columns_with_transformed_columns table selectors transformer error_on_missing_columns=True on_problems:Problem_Behavior=..Report_Warning =
|
||||||
internal_columns = table.columns_helper.select_columns selectors Case_Sensitivity.Default reorder=False error_on_missing_columns=error_on_missing_columns on_problems=on_problems
|
internal_columns = table.columns_helper.select_columns selectors Case_Sensitivity.Default reorder=False error_on_missing_columns=error_on_missing_columns on_problems=on_problems
|
||||||
columns = internal_columns.map table.columns_helper.make_column
|
columns = internal_columns.map table.columns_helper.make_column
|
||||||
new_columns = columns.map on_problems=No_Wrap transformer
|
new_columns = columns.map on_problems=No_Wrap.Value transformer
|
||||||
replace_columns_with_columns table columns new_columns
|
replace_columns_with_columns table columns new_columns
|
||||||
|
@ -103,6 +103,6 @@ check_is_in_values operation_name values =
|
|||||||
Error.throw (Illegal_Argument.Error message)
|
Error.throw (Illegal_Argument.Error message)
|
||||||
_ -> v
|
_ -> v
|
||||||
case values of
|
case values of
|
||||||
_ : Vector -> values.map on_problems=No_Wrap check_value
|
_ : Vector -> values.map on_problems=No_Wrap.Value check_value
|
||||||
_ : Array -> values.map on_problems=No_Wrap check_value
|
_ : Array -> values.map on_problems=No_Wrap.Value check_value
|
||||||
_ -> check_value values
|
_ -> check_value values
|
||||||
|
@ -273,7 +273,7 @@ check_binary_boolean_op arg1 arg2 ~action =
|
|||||||
- action: the action to run if the arguments are compatible.
|
- action: the action to run if the arguments are compatible.
|
||||||
check_multi_argument_comparable_op column arg_or_args ~action =
|
check_multi_argument_comparable_op column arg_or_args ~action =
|
||||||
args = Vector.unify_vector_or_element arg_or_args
|
args = Vector.unify_vector_or_element arg_or_args
|
||||||
checked = args.map on_problems=No_Wrap arg->
|
checked = args.map on_problems=No_Wrap.Value arg->
|
||||||
Value_Type.expect_comparable column arg <|
|
Value_Type.expect_comparable column arg <|
|
||||||
True
|
True
|
||||||
checked.if_not_error <|
|
checked.if_not_error <|
|
||||||
|
@ -140,7 +140,7 @@ type Table
|
|||||||
new columns =
|
new columns =
|
||||||
invalid_input_shape =
|
invalid_input_shape =
|
||||||
Error.throw (Illegal_Argument.Error "Each column must be represented by a pair whose first element is the column name and the second element is a vector of elements that will constitute that column, or an existing column.")
|
Error.throw (Illegal_Argument.Error "Each column must be represented by a pair whose first element is the column name and the second element is a vector of elements that will constitute that column, or an existing column.")
|
||||||
cols = columns.map on_problems=No_Wrap c->
|
cols = columns.map on_problems=No_Wrap.Value c->
|
||||||
case c of
|
case c of
|
||||||
v : Vector ->
|
v : Vector ->
|
||||||
if v.length != 2 then invalid_input_shape else
|
if v.length != 2 then invalid_input_shape else
|
||||||
@ -1512,7 +1512,7 @@ type Table
|
|||||||
False ->
|
False ->
|
||||||
Dictionary.from_vector <| selected_columns.map c-> [c.name, True]
|
Dictionary.from_vector <| selected_columns.map c-> [c.name, True]
|
||||||
|
|
||||||
new_columns = self.columns.map on_problems=No_Wrap column-> if selected_column_names.contains_key column.name . not then column else
|
new_columns = self.columns.map on_problems=No_Wrap.Value column-> if selected_column_names.contains_key column.name . not then column else
|
||||||
Value_Type.expect_text column <|
|
Value_Type.expect_text column <|
|
||||||
storage = column.java_column.getStorage
|
storage = column.java_column.getStorage
|
||||||
new_storage = Java_Problems.with_problem_aggregator on_problems java_problem_aggregator->
|
new_storage = Java_Problems.with_problem_aggregator on_problems java_problem_aggregator->
|
||||||
@ -2732,10 +2732,10 @@ type Table
|
|||||||
merge self lookup_table:Table key_columns:(Vector (Integer | Text | Regex) | Text | Integer | Regex) add_new_columns:Boolean=False allow_unmatched_rows:Boolean=True on_problems:Problem_Behavior=..Report_Warning =
|
merge self lookup_table:Table key_columns:(Vector (Integer | Text | Regex) | Text | Integer | Regex) add_new_columns:Boolean=False allow_unmatched_rows:Boolean=True on_problems:Problem_Behavior=..Report_Warning =
|
||||||
lookup_columns = Lookup_Helpers.prepare_columns_for_lookup self lookup_table key_columns add_new_columns allow_unmatched_rows on_problems
|
lookup_columns = Lookup_Helpers.prepare_columns_for_lookup self lookup_table key_columns add_new_columns allow_unmatched_rows on_problems
|
||||||
|
|
||||||
java_descriptions = lookup_columns.map make_java_lookup_column_description on_problems=No_Wrap
|
java_descriptions = lookup_columns.map make_java_lookup_column_description on_problems=No_Wrap.Value
|
||||||
|
|
||||||
keys = lookup_columns.filter .is_key
|
keys = lookup_columns.filter .is_key
|
||||||
java_keys = keys.map on_problems=No_Wrap key_column->
|
java_keys = keys.map on_problems=No_Wrap.Value key_column->
|
||||||
Java_Join_Equals.new key_column.base_column.java_column key_column.lookup_column.java_column
|
Java_Join_Equals.new key_column.base_column.java_column key_column.lookup_column.java_column
|
||||||
|
|
||||||
handle_java_errors ~action =
|
handle_java_errors ~action =
|
||||||
@ -3205,7 +3205,7 @@ type Table
|
|||||||
normalize_group_by input = case input of
|
normalize_group_by input = case input of
|
||||||
Aggregate_Column.Group_By c _ -> c
|
Aggregate_Column.Group_By c _ -> c
|
||||||
_ : Aggregate_Column -> Error.throw (Illegal_Argument.Error "Only Aggregate_Column.Group_By can be used for cross_tab group_by clause.")
|
_ : Aggregate_Column -> Error.throw (Illegal_Argument.Error "Only Aggregate_Column.Group_By can be used for cross_tab group_by clause.")
|
||||||
_ : Vector -> input.map on_problems=No_Wrap normalize_group_by
|
_ : Vector -> input.map on_problems=No_Wrap.Value normalize_group_by
|
||||||
_ -> input
|
_ -> input
|
||||||
|
|
||||||
## validate the name and group_by columns
|
## validate the name and group_by columns
|
||||||
@ -3217,7 +3217,7 @@ type Table
|
|||||||
grouping = columns_helper.select_columns_helper (normalize_group_by group_by) Case_Sensitivity.Default True problem_builder
|
grouping = columns_helper.select_columns_helper (normalize_group_by group_by) Case_Sensitivity.Default True problem_builder
|
||||||
|
|
||||||
## Validate the values
|
## Validate the values
|
||||||
resolved_values = Vector.unify_vector_or_element values . map on_problems=No_Wrap (Aggregate_Column_Helper.resolve_aggregate self problem_builder)
|
resolved_values = Vector.unify_vector_or_element values . map on_problems=No_Wrap.Value (Aggregate_Column_Helper.resolve_aggregate self problem_builder)
|
||||||
is_group_by c = case c of
|
is_group_by c = case c of
|
||||||
Aggregate_Column.Group_By _ _ -> True
|
Aggregate_Column.Group_By _ _ -> True
|
||||||
_ -> False
|
_ -> False
|
||||||
|
@ -154,7 +154,7 @@ type Bench
|
|||||||
Duration.new seconds=total_seconds
|
Duration.new seconds=total_seconds
|
||||||
|
|
||||||
## Run the specified set of benchmarks.
|
## Run the specified set of benchmarks.
|
||||||
run_main self =
|
run_main self (filter : Text | Nothing = Nothing) =
|
||||||
count = self.total_specs
|
count = self.total_specs
|
||||||
IO.println <| "Found " + count.to_text + " cases to execute (ETA " + self.estimated_runtime.to_display_text + ")"
|
IO.println <| "Found " + count.to_text + " cases to execute (ETA " + self.estimated_runtime.to_display_text + ")"
|
||||||
|
|
||||||
@ -167,11 +167,19 @@ type Bench
|
|||||||
line = 'Label,Phase,"Invocations count","Average time (ms)","Time Stdev"'
|
line = 'Label,Phase,"Invocations count","Average time (ms)","Time Stdev"'
|
||||||
line.write f on_existing_file=Existing_File_Behavior.Backup
|
line.write f on_existing_file=Existing_File_Behavior.Backup
|
||||||
|
|
||||||
|
should_skip (bench_name : Text) -> Boolean =
|
||||||
|
if filter == Nothing then False else
|
||||||
|
bench_name.match filter . not
|
||||||
|
|
||||||
self.fold Nothing _-> g-> s->
|
self.fold Nothing _-> g-> s->
|
||||||
c = g.configuration
|
c = g.configuration
|
||||||
bench_name = g.name + "." + s.name
|
bench_name = g.name + "." + s.name
|
||||||
IO.println <| "Benchmarking '" + bench_name + "' with configuration: " + c.to_text
|
case should_skip bench_name of
|
||||||
Bench.measure bench_name c.warmup c.measure (s.code 0)
|
False ->
|
||||||
|
IO.println <| "Benchmarking '" + bench_name + "' with configuration: " + c.to_text
|
||||||
|
Bench.measure bench_name c.warmup c.measure (s.code 0)
|
||||||
|
True ->
|
||||||
|
IO.println <| "Skipping '" + bench_name + "' benchmark"
|
||||||
|
|
||||||
## Measure the amount of time it takes to execute a given computation.
|
## Measure the amount of time it takes to execute a given computation.
|
||||||
|
|
||||||
|
@ -3,4 +3,3 @@ minimum-project-manager-version: 2023.2.1-nightly.2023.11.2
|
|||||||
jvm-options:
|
jvm-options:
|
||||||
- value: "-Dgraal.PrintGraph=Network"
|
- value: "-Dgraal.PrintGraph=Network"
|
||||||
- value: "--add-opens=java.base/java.nio=ALL-UNNAMED"
|
- value: "--add-opens=java.base/java.nio=ALL-UNNAMED"
|
||||||
- value: "-Xss16M"
|
|
||||||
|
@ -65,6 +65,27 @@ sbt:runtime-benchmarks> run -w 1 -i 1 -f 1 -jvmArgs -agentlib:jdwp=transport=dt_
|
|||||||
This command will run the `importStandardLibraries` benchmark in fork waiting
|
This command will run the `importStandardLibraries` benchmark in fork waiting
|
||||||
for the debugger to attach.
|
for the debugger to attach.
|
||||||
|
|
||||||
|
### Dumping the compilation info of the benchmark
|
||||||
|
|
||||||
|
The following command enables the compilation tracing output from the Truffle
|
||||||
|
compiler:
|
||||||
|
|
||||||
|
```
|
||||||
|
sbt:runtime-benchmarks> run -jvmArgs -Dpolyglot.engine.TraceCompilation=true org.enso.interpreter.bench.benchmarks.semantic.IfVsCaseBenchmarks.ifBench6In
|
||||||
|
```
|
||||||
|
|
||||||
|
The output will contain lines like:
|
||||||
|
|
||||||
|
```
|
||||||
|
[error] [engine] opt done id=1067 ifBench6In.My_Type.Value |Tier 2|Time 22( 18+4 )ms|AST 1|Inlined 0Y 0N|IR 17/ 20|CodeSize 186|Addr 0x7acf0380f280|Timestamp 96474787822678|Src n/a
|
||||||
|
```
|
||||||
|
|
||||||
|
You can, e.g., dump Graal graphs with:
|
||||||
|
|
||||||
|
```
|
||||||
|
sbt:runtime-benchmarks> run -jvmArgs -Dgraal.Dump=Truffle:2 org.enso.interpreter.bench.benchmarks.semantic.IfVsCaseBenchmarks.ifBench6In
|
||||||
|
```
|
||||||
|
|
||||||
## Standard library benchmarks
|
## Standard library benchmarks
|
||||||
|
|
||||||
Unlike the Engine micro benchmarks, these benchmarks are written entirely in
|
Unlike the Engine micro benchmarks, these benchmarks are written entirely in
|
||||||
|
@ -4,6 +4,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import org.enso.common.MethodNames.Module;
|
import org.enso.common.MethodNames.Module;
|
||||||
import org.enso.compiler.benchmarks.Utils;
|
import org.enso.compiler.benchmarks.Utils;
|
||||||
|
import org.graalvm.polyglot.Context;
|
||||||
import org.graalvm.polyglot.Value;
|
import org.graalvm.polyglot.Value;
|
||||||
import org.openjdk.jmh.annotations.Benchmark;
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||||
@ -14,6 +15,7 @@ import org.openjdk.jmh.annotations.OutputTimeUnit;
|
|||||||
import org.openjdk.jmh.annotations.Scope;
|
import org.openjdk.jmh.annotations.Scope;
|
||||||
import org.openjdk.jmh.annotations.Setup;
|
import org.openjdk.jmh.annotations.Setup;
|
||||||
import org.openjdk.jmh.annotations.State;
|
import org.openjdk.jmh.annotations.State;
|
||||||
|
import org.openjdk.jmh.annotations.TearDown;
|
||||||
import org.openjdk.jmh.annotations.Warmup;
|
import org.openjdk.jmh.annotations.Warmup;
|
||||||
import org.openjdk.jmh.infra.BenchmarkParams;
|
import org.openjdk.jmh.infra.BenchmarkParams;
|
||||||
import org.openjdk.jmh.infra.Blackhole;
|
import org.openjdk.jmh.infra.Blackhole;
|
||||||
@ -28,10 +30,11 @@ public class TypePatternBenchmarks {
|
|||||||
private Value patternMatch;
|
private Value patternMatch;
|
||||||
private Value avg;
|
private Value avg;
|
||||||
private Value vec;
|
private Value vec;
|
||||||
|
private Context ctx;
|
||||||
|
|
||||||
@Setup
|
@Setup
|
||||||
public void initializeBenchmark(BenchmarkParams params) throws Exception {
|
public void initializeBenchmark(BenchmarkParams params) throws Exception {
|
||||||
var ctx = Utils.createDefaultContextBuilder().build();
|
ctx = Utils.createDefaultContextBuilder().build();
|
||||||
var code =
|
var code =
|
||||||
"""
|
"""
|
||||||
from Standard.Base import Integer, Vector, Any, Float
|
from Standard.Base import Integer, Vector, Any, Float
|
||||||
@ -76,6 +79,11 @@ public class TypePatternBenchmarks {
|
|||||||
this.avg = getMethod.apply("avg_pattern");
|
this.avg = getMethod.apply("avg_pattern");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TearDown
|
||||||
|
public void tearDown() {
|
||||||
|
ctx.close();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adding @ExplodeLoop in {@link
|
* Adding @ExplodeLoop in {@link
|
||||||
* org.enso.interpreter.node.controlflow.caseexpr.CatchTypeBranchNode} specialization decreases
|
* org.enso.interpreter.node.controlflow.caseexpr.CatchTypeBranchNode} specialization decreases
|
||||||
|
@ -9,6 +9,7 @@ import java.net.URI;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import org.enso.interpreter.runtime.data.Type;
|
||||||
import org.enso.interpreter.test.ValuesGenerator.Language;
|
import org.enso.interpreter.test.ValuesGenerator.Language;
|
||||||
import org.enso.test.utils.ContextUtils;
|
import org.enso.test.utils.ContextUtils;
|
||||||
import org.graalvm.polyglot.Context;
|
import org.graalvm.polyglot.Context;
|
||||||
@ -259,6 +260,11 @@ public class MetaIsATest {
|
|||||||
if (v.equals(generator().typeAny())) {
|
if (v.equals(generator().typeAny())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
var unwrappedV = ContextUtils.unwrapValue(ctx, v);
|
||||||
|
if (unwrappedV instanceof Type type && type.isEigenType()) {
|
||||||
|
// Skip singleton types
|
||||||
|
continue;
|
||||||
|
}
|
||||||
var r = isACheck.execute(v, v);
|
var r = isACheck.execute(v, v);
|
||||||
if (v.equals(generator().typeNothing())) {
|
if (v.equals(generator().typeNothing())) {
|
||||||
assertTrue("Nothing is instance of itself", r.asBoolean());
|
assertTrue("Nothing is instance of itself", r.asBoolean());
|
||||||
|
@ -16,6 +16,7 @@ import java.util.HashSet;
|
|||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.enso.common.MethodNames;
|
import org.enso.common.MethodNames;
|
||||||
|
import org.enso.interpreter.runtime.data.Type;
|
||||||
import org.enso.interpreter.runtime.type.ConstantsGen;
|
import org.enso.interpreter.runtime.type.ConstantsGen;
|
||||||
import org.enso.interpreter.test.ValuesGenerator.Language;
|
import org.enso.interpreter.test.ValuesGenerator.Language;
|
||||||
import org.enso.test.utils.ContextUtils;
|
import org.enso.test.utils.ContextUtils;
|
||||||
@ -383,6 +384,11 @@ main = Nothing
|
|||||||
// skip Nothing
|
// skip Nothing
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
var type = (Type) ContextUtils.unwrapValue(ctx, typ);
|
||||||
|
if (type.isEigenType()) {
|
||||||
|
// Skip singleton types
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
var simpleName = sn.execute(typ).asString();
|
var simpleName = sn.execute(typ).asString();
|
||||||
var metaName = typ.getMetaSimpleName() + ".type";
|
var metaName = typ.getMetaSimpleName() + ".type";
|
||||||
@ -410,6 +416,11 @@ main = Nothing
|
|||||||
if (t.isNull()) {
|
if (t.isNull()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
var type = (Type) ContextUtils.unwrapValue(ctx, t);
|
||||||
|
if (type.isEigenType()) {
|
||||||
|
// Skip checking singleton types
|
||||||
|
continue;
|
||||||
|
}
|
||||||
switch (t.getMetaSimpleName()) {
|
switch (t.getMetaSimpleName()) {
|
||||||
// represented as primitive values without meta object
|
// represented as primitive values without meta object
|
||||||
case "Float" -> {}
|
case "Float" -> {}
|
||||||
@ -432,6 +443,17 @@ main = Nothing
|
|||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
interface Check {
|
interface Check {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param v Instance of the type
|
||||||
|
* @param type Type. Nullable.
|
||||||
|
* @param expecting Set of types that are tested. The check should remove the currently tested
|
||||||
|
* type from this set.
|
||||||
|
* @param successfullyRemoved Set of types that already were tested. The check should add the
|
||||||
|
* currently tested type to this set.
|
||||||
|
* @param w StringBuilder for the error message that will be printed at the end in case of a
|
||||||
|
* failure.
|
||||||
|
*/
|
||||||
void check(
|
void check(
|
||||||
Value v, Value type, Set<Value> expecting, Set<Value> successfullyRemoved, StringBuilder w);
|
Value v, Value type, Set<Value> expecting, Set<Value> successfullyRemoved, StringBuilder w);
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,11 @@ public final class ValuesGenerator {
|
|||||||
this.languages = languages;
|
this.languages = languages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param type Either an atom or a type.
|
||||||
|
* @param check An executable that checks if the value is of the given type. Takes a single
|
||||||
|
* parameter.
|
||||||
|
*/
|
||||||
private record ValueInfo(Value type, Value check) {}
|
private record ValueInfo(Value type, Value check) {}
|
||||||
|
|
||||||
public static ValuesGenerator create(Context ctx, Language... langs) {
|
public static ValuesGenerator create(Context ctx, Language... langs) {
|
||||||
@ -61,6 +66,13 @@ public final class ValuesGenerator {
|
|||||||
return v(key, prelude, typeOrValue, key != null ? typeOrValue : null);
|
return v(key, prelude, typeOrValue, key != null ? typeOrValue : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param key Used as a key in {@link #values}. If the key is already there, nothing is created.
|
||||||
|
* Nullable.
|
||||||
|
* @param prelude Additional code inserted before {@code typeOrValue} expression, like imports.
|
||||||
|
* @param typeOrValue An expression that results in an atom or a type.
|
||||||
|
* @param typeCheck If not null, this is used as a type name and the value is checked against it.
|
||||||
|
*/
|
||||||
private ValueInfo v(String key, String prelude, String typeOrValue, String typeCheck) {
|
private ValueInfo v(String key, String prelude, String typeOrValue, String typeCheck) {
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
key = typeOrValue;
|
key = typeOrValue;
|
||||||
@ -302,6 +314,23 @@ public final class ValuesGenerator {
|
|||||||
.type();
|
.type();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Value typeNoWrap() {
|
||||||
|
return v("typeNoWrap", """
|
||||||
|
import Standard.Base.Data.Vector.No_Wrap
|
||||||
|
""", "No_Wrap")
|
||||||
|
.type();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Value typeProblemBehavior() {
|
||||||
|
return v(
|
||||||
|
"typeProblemBehavior",
|
||||||
|
"""
|
||||||
|
import Standard.Base.Errors.Problem_Behavior.Problem_Behavior
|
||||||
|
""",
|
||||||
|
"Problem_Behavior")
|
||||||
|
.type();
|
||||||
|
}
|
||||||
|
|
||||||
public Value typeMap() {
|
public Value typeMap() {
|
||||||
return v(
|
return v(
|
||||||
"typeMap",
|
"typeMap",
|
||||||
@ -823,8 +852,25 @@ public final class ValuesGenerator {
|
|||||||
collect.add(typeNothing());
|
collect.add(typeNothing());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (languages.contains(Language.JAVA)) {}
|
return collect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Value> problemBehaviors() {
|
||||||
|
var collect = new ArrayList<Value>();
|
||||||
|
if (languages.contains(Language.ENSO)) {
|
||||||
|
var prelude = "import Standard.Base.Errors.Problem_Behavior.Problem_Behavior";
|
||||||
|
collect.add(v(null, prelude, "Problem_Behavior.Report_Error").type());
|
||||||
|
collect.add(v(null, prelude, "Problem_Behavior.Ignore").type());
|
||||||
|
}
|
||||||
|
return collect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Value> noWrap() {
|
||||||
|
var collect = new ArrayList<Value>();
|
||||||
|
if (languages.contains(Language.ENSO)) {
|
||||||
|
var prelude = "import Standard.Base.Data.Vector.No_Wrap";
|
||||||
|
collect.add(v(null, prelude, "No_Wrap.Value").type());
|
||||||
|
}
|
||||||
return collect;
|
return collect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
@ -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(name = "Standard.Base.Data.Vector.No_Wrap")
|
||||||
|
public class NoWrap extends UniquelyConstructibleBuiltin {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getConstructorName() {
|
||||||
|
return "Value";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getConstructorParamNames() {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
}
|
@ -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];
|
||||||
|
}
|
||||||
|
}
|
@ -32,7 +32,10 @@ import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
|
|||||||
import org.enso.interpreter.node.expression.builtin.Nothing;
|
import org.enso.interpreter.node.expression.builtin.Nothing;
|
||||||
import org.enso.interpreter.node.expression.builtin.Polyglot;
|
import org.enso.interpreter.node.expression.builtin.Polyglot;
|
||||||
import org.enso.interpreter.node.expression.builtin.debug.Debug;
|
import org.enso.interpreter.node.expression.builtin.debug.Debug;
|
||||||
|
import org.enso.interpreter.node.expression.builtin.error.AdditionalWarnings;
|
||||||
import org.enso.interpreter.node.expression.builtin.error.CaughtPanic;
|
import org.enso.interpreter.node.expression.builtin.error.CaughtPanic;
|
||||||
|
import org.enso.interpreter.node.expression.builtin.error.NoWrap;
|
||||||
|
import org.enso.interpreter.node.expression.builtin.error.ProblemBehavior;
|
||||||
import org.enso.interpreter.node.expression.builtin.error.Warning;
|
import org.enso.interpreter.node.expression.builtin.error.Warning;
|
||||||
import org.enso.interpreter.node.expression.builtin.immutable.Vector;
|
import org.enso.interpreter.node.expression.builtin.immutable.Vector;
|
||||||
import org.enso.interpreter.node.expression.builtin.io.File;
|
import org.enso.interpreter.node.expression.builtin.io.File;
|
||||||
@ -117,6 +120,9 @@ public final class Builtins {
|
|||||||
private final Builtin timeOfDay;
|
private final Builtin timeOfDay;
|
||||||
private final Builtin timeZone;
|
private final Builtin timeZone;
|
||||||
private final Builtin warning;
|
private final Builtin warning;
|
||||||
|
private final NoWrap noWrap;
|
||||||
|
private final ProblemBehavior problemBehavior;
|
||||||
|
private final AdditionalWarnings additionalWarnings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an instance with builtin methods installed.
|
* Creates an instance with builtin methods installed.
|
||||||
@ -168,6 +174,9 @@ public final class Builtins {
|
|||||||
timeOfDay = builtins.get(org.enso.interpreter.node.expression.builtin.date.TimeOfDay.class);
|
timeOfDay = builtins.get(org.enso.interpreter.node.expression.builtin.date.TimeOfDay.class);
|
||||||
timeZone = builtins.get(org.enso.interpreter.node.expression.builtin.date.TimeZone.class);
|
timeZone = builtins.get(org.enso.interpreter.node.expression.builtin.date.TimeZone.class);
|
||||||
warning = builtins.get(Warning.class);
|
warning = builtins.get(Warning.class);
|
||||||
|
noWrap = getBuiltinType(NoWrap.class);
|
||||||
|
problemBehavior = getBuiltinType(ProblemBehavior.class);
|
||||||
|
additionalWarnings = getBuiltinType(AdditionalWarnings.class);
|
||||||
|
|
||||||
error = new Error(this, context);
|
error = new Error(this, context);
|
||||||
system = new System(this);
|
system = new System(this);
|
||||||
@ -602,6 +611,21 @@ public final class Builtins {
|
|||||||
return warning.getType();
|
return warning.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the {@code Problem_Behavior} type. */
|
||||||
|
public ProblemBehavior problemBehavior() {
|
||||||
|
return problemBehavior;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the {@code No_Wrap} atom constructor. */
|
||||||
|
public NoWrap noWrap() {
|
||||||
|
return noWrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the {@code Additional_Warnings} atom constructor. */
|
||||||
|
public AdditionalWarnings additionalWarnings() {
|
||||||
|
return additionalWarnings;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@code File} atom constructor.
|
* Returns the {@code File} atom constructor.
|
||||||
*
|
*
|
||||||
|
@ -1,18 +1,11 @@
|
|||||||
package org.enso.interpreter.runtime.data.vector;
|
package org.enso.interpreter.runtime.data.vector;
|
||||||
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
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.interop.InteropLibrary;
|
||||||
import com.oracle.truffle.api.library.CachedLibrary;
|
import com.oracle.truffle.api.library.CachedLibrary;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import org.enso.interpreter.dsl.Builtin;
|
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.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. */
|
/** Publicly available operations on array-like classes. */
|
||||||
@Builtin(pkg = "immutable", stdlibName = "Standard.Base.Internal.Array_Like_Helpers")
|
@Builtin(pkg = "immutable", stdlibName = "Standard.Base.Internal.Array_Like_Helpers")
|
||||||
@ -75,31 +68,6 @@ public final class ArrayLikeHelpers {
|
|||||||
return Array.allocate(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(
|
@Builtin.Method(
|
||||||
name = "vector_to_array",
|
name = "vector_to_array",
|
||||||
description = "Returns an Array representation of this Vector.")
|
description = "Returns an Array representation of this Vector.")
|
||||||
|
@ -0,0 +1,162 @@
|
|||||||
|
package org.enso.interpreter.runtime.data.vector;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
||||||
|
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 com.oracle.truffle.api.profiles.LoopConditionProfile;
|
||||||
|
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||||
|
import org.enso.interpreter.node.callable.dispatch.InvokeFunctionNode;
|
||||||
|
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.data.atom.AtomConstructor;
|
||||||
|
import org.enso.interpreter.runtime.error.DataflowError;
|
||||||
|
import org.enso.interpreter.runtime.error.PanicException;
|
||||||
|
import org.enso.interpreter.runtime.state.HasContextEnabledNode;
|
||||||
|
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(
|
||||||
|
guards = "getCtor(onProblemsAtom) == onProblemsAtomCtorCached",
|
||||||
|
limit = "onProblemsCtorsCount()")
|
||||||
|
Object doItCached(
|
||||||
|
VirtualFrame frame,
|
||||||
|
State state,
|
||||||
|
long length,
|
||||||
|
Function func,
|
||||||
|
Atom onProblemsAtom,
|
||||||
|
@Cached("getCtor(onProblemsAtom)") AtomConstructor onProblemsAtomCtorCached,
|
||||||
|
@Cached("processOnProblemsArg(onProblemsAtomCtorCached)") OnProblems onProblems,
|
||||||
|
@Cached("buildWithArity(1)") InvokeFunctionNode invokeFunctionNode,
|
||||||
|
@Cached("build()") AppendWarningNode appendWarningNode,
|
||||||
|
@CachedLibrary(limit = "3") WarningsLibrary warnsLib,
|
||||||
|
@Cached BranchProfile errorEncounteredProfile,
|
||||||
|
@Cached HasContextEnabledNode hasContextEnabledNode,
|
||||||
|
@Cached LoopConditionProfile loopConditionProfile) {
|
||||||
|
var ctx = EnsoContext.get(this);
|
||||||
|
var len = (int) length;
|
||||||
|
var nothing = ctx.getNothing();
|
||||||
|
var target = ArrayBuilder.newBuilder(len);
|
||||||
|
var errorsEncountered = 0;
|
||||||
|
loopConditionProfile.profileCounted(len);
|
||||||
|
for (int i = 0; loopConditionProfile.inject(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) {
|
||||||
|
case IGNORE -> valueToAdd = nothing;
|
||||||
|
case REPORT_ERROR -> {
|
||||||
|
var mapErr = ctx.getBuiltins().error().makeMapError(i, err.getPayload());
|
||||||
|
return DataflowError.withDefaultTrace(state, mapErr, this, hasContextEnabledNode);
|
||||||
|
}
|
||||||
|
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().additionalWarnings();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unreachable: The {@code doItCached} specialization has the same limit of instantiations as
|
||||||
|
* there are possible onProblems arguments. So this specialization is only reached if {@code
|
||||||
|
* onProblems} argument is an unexpected type.
|
||||||
|
*
|
||||||
|
* @return Just throws Type_Error dataflow error.
|
||||||
|
*/
|
||||||
|
@Specialization(replaces = "doItCached")
|
||||||
|
Object unreachable(
|
||||||
|
VirtualFrame frame, State state, long length, Function func, Object onProblems) {
|
||||||
|
var problemBehaviorBuiltin = EnsoContext.get(this).getBuiltins().problemBehavior();
|
||||||
|
throw makeTypeError(problemBehaviorBuiltin.getType(), onProblems, "onProblems");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected OnProblems processOnProblemsArg(AtomConstructor onProblems) {
|
||||||
|
var ctx = EnsoContext.get(this);
|
||||||
|
var problemBehaviorBuiltin = ctx.getBuiltins().problemBehavior();
|
||||||
|
var noWrapBuiltin = ctx.getBuiltins().noWrap();
|
||||||
|
if (onProblems == problemBehaviorBuiltin.getIgnore()) {
|
||||||
|
return OnProblems.IGNORE;
|
||||||
|
} else if (onProblems == problemBehaviorBuiltin.getReportError()) {
|
||||||
|
return OnProblems.REPORT_ERROR;
|
||||||
|
} else if (onProblems == problemBehaviorBuiltin.getReportWarning()) {
|
||||||
|
return OnProblems.REPORT_WARNING;
|
||||||
|
} else if (onProblems == noWrapBuiltin.getUniqueConstructor()) {
|
||||||
|
return OnProblems.NO_WRAP;
|
||||||
|
}
|
||||||
|
throw makeTypeError(problemBehaviorBuiltin.getType(), onProblems, "onProblems");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static AtomConstructor getCtor(Atom atom) {
|
||||||
|
return atom.getConstructor();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static int onProblemsCtorsCount() {
|
||||||
|
return OnProblems.values().length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@TruffleBoundary
|
||||||
|
private PanicException makeTypeError(Object expected, Object actual, String name) {
|
||||||
|
var ctx = EnsoContext.get(this);
|
||||||
|
var typeError = ctx.getBuiltins().error().makeTypeError(expected, actual, name);
|
||||||
|
return new PanicException(typeError, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** All the possible values for the {@code onProblems} argument. */
|
||||||
|
protected enum OnProblems {
|
||||||
|
IGNORE,
|
||||||
|
REPORT_ERROR,
|
||||||
|
REPORT_WARNING,
|
||||||
|
NO_WRAP
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ package org.enso.interpreter.runtime.state;
|
|||||||
import com.oracle.truffle.api.CompilerDirectives;
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
import com.oracle.truffle.api.dsl.Cached;
|
import com.oracle.truffle.api.dsl.Cached;
|
||||||
import com.oracle.truffle.api.dsl.GenerateUncached;
|
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.dsl.Specialization;
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
import org.enso.interpreter.runtime.EnsoContext;
|
import org.enso.interpreter.runtime.EnsoContext;
|
||||||
@ -18,6 +19,7 @@ public abstract class HasContextEnabledNode extends Node {
|
|||||||
return HasContextEnabledNodeGen.getUncached();
|
return HasContextEnabledNodeGen.getUncached();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NeverDefault
|
||||||
public static HasContextEnabledNode create() {
|
public static HasContextEnabledNode create() {
|
||||||
return HasContextEnabledNodeGen.create();
|
return HasContextEnabledNodeGen.create();
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import com.oracle.truffle.api.CompilerDirectives;
|
|||||||
import com.oracle.truffle.api.dsl.Cached;
|
import com.oracle.truffle.api.dsl.Cached;
|
||||||
import com.oracle.truffle.api.dsl.Cached.Shared;
|
import com.oracle.truffle.api.dsl.Cached.Shared;
|
||||||
import com.oracle.truffle.api.dsl.GenerateUncached;
|
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.dsl.Specialization;
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||||
@ -24,6 +25,7 @@ import org.enso.interpreter.runtime.error.DataflowError;
|
|||||||
@GenerateUncached
|
@GenerateUncached
|
||||||
public abstract class AppendWarningNode extends Node {
|
public abstract class AppendWarningNode extends Node {
|
||||||
|
|
||||||
|
@NeverDefault
|
||||||
public static AppendWarningNode build() {
|
public static AppendWarningNode build() {
|
||||||
return AppendWarningNodeGen.create();
|
return AppendWarningNodeGen.create();
|
||||||
}
|
}
|
||||||
|
@ -389,7 +389,7 @@ type_spec suite_builder name alter = suite_builder.group name group_builder->
|
|||||||
|
|
||||||
group_builder.specify "should allow map on_problems=No_Wrap, returning a new vector" <|
|
group_builder.specify "should allow map on_problems=No_Wrap, returning a new vector" <|
|
||||||
vec = alter [1, 2, 3, 4]
|
vec = alter [1, 2, 3, 4]
|
||||||
mapped = vec.map on_problems=No_Wrap x-> x * x
|
mapped = vec.map on_problems=No_Wrap.Value x-> x * x
|
||||||
vec.to_text.should_equal "[1, 2, 3, 4]"
|
vec.to_text.should_equal "[1, 2, 3, 4]"
|
||||||
mapped.to_text.should_equal "[1, 4, 9, 16]"
|
mapped.to_text.should_equal "[1, 4, 9, 16]"
|
||||||
|
|
||||||
@ -801,11 +801,11 @@ type_spec suite_builder name alter = suite_builder.group name group_builder->
|
|||||||
alter [] . zip [4, 5, 6] (+) . should_equal []
|
alter [] . zip [4, 5, 6] (+) . should_equal []
|
||||||
|
|
||||||
group_builder.specify "should zip elements with zip on_problems=No_Wrap" <|
|
group_builder.specify "should zip elements with zip on_problems=No_Wrap" <|
|
||||||
alter [1, 2, 3] . zip on_problems=No_Wrap [] (+) . should_equal []
|
alter [1, 2, 3] . zip on_problems=No_Wrap.Value [] (+) . should_equal []
|
||||||
alter [1, 2, 3] . zip on_problems=No_Wrap [4] (+) . should_equal [5]
|
alter [1, 2, 3] . zip on_problems=No_Wrap.Value [4] (+) . should_equal [5]
|
||||||
alter [1, 2, 3] . zip on_problems=No_Wrap [4, 5, 6] (+) . should_equal [5, 7, 9]
|
alter [1, 2, 3] . zip on_problems=No_Wrap.Value [4, 5, 6] (+) . should_equal [5, 7, 9]
|
||||||
alter [1, 2, 3] . zip on_problems=No_Wrap [4, 5, 6, 7] (+) . should_equal [5, 7, 9]
|
alter [1, 2, 3] . zip on_problems=No_Wrap.Value [4, 5, 6, 7] (+) . should_equal [5, 7, 9]
|
||||||
alter [] . zip on_problems=No_Wrap [4, 5, 6] (+) . should_equal []
|
alter [] . zip on_problems=No_Wrap.Value [4, 5, 6] (+) . should_equal []
|
||||||
|
|
||||||
group_builder.specify "should flat_map elements" <|
|
group_builder.specify "should flat_map elements" <|
|
||||||
alter [1, 2, 3] . flat_map (_ -> []) . should_equal []
|
alter [1, 2, 3] . flat_map (_ -> []) . should_equal []
|
||||||
@ -815,11 +815,11 @@ type_spec suite_builder name alter = suite_builder.group name group_builder->
|
|||||||
alter [0, 0, 0] . flat_map (i -> [i]) . should_equal [0, 0, 0]
|
alter [0, 0, 0] . flat_map (i -> [i]) . should_equal [0, 0, 0]
|
||||||
|
|
||||||
group_builder.specify "should flat_map elements with flat_map on_problems=No_Wrap" <|
|
group_builder.specify "should flat_map elements with flat_map on_problems=No_Wrap" <|
|
||||||
alter [1, 2, 3] . flat_map on_problems=No_Wrap (_ -> []) . should_equal []
|
alter [1, 2, 3] . flat_map on_problems=No_Wrap.Value (_ -> []) . should_equal []
|
||||||
alter [1, 2, 3] . flat_map on_problems=No_Wrap (_ -> [0, 1]) . should_equal [0, 1, 0, 1, 0, 1]
|
alter [1, 2, 3] . flat_map on_problems=No_Wrap.Value (_ -> [0, 1]) . should_equal [0, 1, 0, 1, 0, 1]
|
||||||
alter [1, 2, 3] . flat_map on_problems=No_Wrap (_ -> [0, [1]]) . should_equal [0, [1], 0, [1], 0, [1]]
|
alter [1, 2, 3] . flat_map on_problems=No_Wrap.Value (_ -> [0, [1]]) . should_equal [0, [1], 0, [1], 0, [1]]
|
||||||
alter [0, 1, 0] . flat_map on_problems=No_Wrap (i -> if i == 1 then [1, 1] else [i]) . should_equal [0, 1, 1, 0]
|
alter [0, 1, 0] . flat_map on_problems=No_Wrap.Value (i -> if i == 1 then [1, 1] else [i]) . should_equal [0, 1, 1, 0]
|
||||||
alter [0, 0, 0] . flat_map on_problems=No_Wrap (i -> [i]) . should_equal [0, 0, 0]
|
alter [0, 0, 0] . flat_map on_problems=No_Wrap.Value (i -> [i]) . should_equal [0, 0, 0]
|
||||||
|
|
||||||
group_builder.specify "should allow inserting elements" <|
|
group_builder.specify "should allow inserting elements" <|
|
||||||
alter [2, 3] . insert . should_equal [2, 3, Nothing]
|
alter [2, 3] . insert . should_equal [2, 3, Nothing]
|
||||||
@ -910,11 +910,11 @@ type_spec suite_builder name alter = suite_builder.group name group_builder->
|
|||||||
alter [10, 20, 30, 40] . map map_fun . should_fail_with (Map_Error.Error 2 (My_Error.Error 30)) unwrap_errors=False
|
alter [10, 20, 30, 40] . map map_fun . should_fail_with (Map_Error.Error 2 (My_Error.Error 30)) unwrap_errors=False
|
||||||
|
|
||||||
group_builder.specify "an error thrown inside map on_problems=No_Wrap should be caught as a My_Error" <|
|
group_builder.specify "an error thrown inside map on_problems=No_Wrap should be caught as a My_Error" <|
|
||||||
alter [10, 20, 30, 40] . map on_problems=No_Wrap map_fun . should_fail_with My_Error
|
alter [10, 20, 30, 40] . map on_problems=No_Wrap.Value map_fun . should_fail_with My_Error
|
||||||
|
|
||||||
group_builder.specify "an error thrown inside map_with_index on_problems=No_Wrap should be caught as a My_Error" <|
|
group_builder.specify "an error thrown inside map_with_index on_problems=No_Wrap should be caught as a My_Error" <|
|
||||||
map_with_index_fun _ a = if a == 30 then Error.throw (My_Error.Error a) else a+1
|
map_with_index_fun _ a = if a == 30 then Error.throw (My_Error.Error a) else a+1
|
||||||
alter [10, 20, 30, 40] . map_with_index on_problems=No_Wrap map_with_index_fun . should_fail_with My_Error
|
alter [10, 20, 30, 40] . map_with_index on_problems=No_Wrap.Value map_with_index_fun . should_fail_with My_Error
|
||||||
|
|
||||||
group_builder.specify "an error thrown inside map and caught (without error parameter) should be caught as a Map_Error" <|
|
group_builder.specify "an error thrown inside map and caught (without error parameter) should be caught as a Map_Error" <|
|
||||||
alter [10, 20, 30, 40] . map map_fun . catch . should_equal (Map_Error.Error 2 (My_Error.Error 30))
|
alter [10, 20, 30, 40] . map map_fun . catch . should_equal (Map_Error.Error 2 (My_Error.Error 30))
|
||||||
@ -972,16 +972,16 @@ type_spec suite_builder name alter = suite_builder.group name group_builder->
|
|||||||
Warning.get_all result wrap_errors=True . map .value . should_equal expected_warnings
|
Warning.get_all result wrap_errors=True . map .value . should_equal expected_warnings
|
||||||
|
|
||||||
group_builder.specify "map on_problems=No_Wrap does not do error wrapping" <|
|
group_builder.specify "map on_problems=No_Wrap does not do error wrapping" <|
|
||||||
alter [10, 20, 30, 40] . map on_problems=No_Wrap map_fun . catch . should_equal (My_Error.Error 30)
|
alter [10, 20, 30, 40] . map on_problems=No_Wrap.Value map_fun . catch . should_equal (My_Error.Error 30)
|
||||||
|
|
||||||
group_builder.specify "zip on_problems=No_Wrap does not do error wrapping" <|
|
group_builder.specify "zip on_problems=No_Wrap does not do error wrapping" <|
|
||||||
zip_fun a _ = if a == 30 then Error.throw (My_Error.Error a) else a+1
|
zip_fun a _ = if a == 30 then Error.throw (My_Error.Error a) else a+1
|
||||||
arr = alter [10, 20, 30, 40]
|
arr = alter [10, 20, 30, 40]
|
||||||
arr . zip on_problems=No_Wrap arr zip_fun . catch . should_equal (My_Error.Error 30)
|
arr . zip on_problems=No_Wrap.Value arr zip_fun . catch . should_equal (My_Error.Error 30)
|
||||||
|
|
||||||
group_builder.specify "flat_map on_problems=No_Wrap does not do error wrapping" <|
|
group_builder.specify "flat_map on_problems=No_Wrap does not do error wrapping" <|
|
||||||
vec = alter [1, 2, 0, 3]
|
vec = alter [1, 2, 0, 3]
|
||||||
vec.flat_map on_problems=No_Wrap (n-> Error.throw (My_Error.Error n)) . catch . should_equal (My_Error.Error 1)
|
vec.flat_map on_problems=No_Wrap.Value (n-> Error.throw (My_Error.Error n)) . catch . should_equal (My_Error.Error 1)
|
||||||
|
|
||||||
group_builder.specify "can transpose a vector of vectors" <|
|
group_builder.specify "can transpose a vector of vectors" <|
|
||||||
mat = alter [alter [0, 1, 2], alter [3, 4, 5], alter [6, 7, 8]]
|
mat = alter [alter [0, 1, 2], alter [3, 4, 5], alter [6, 7, 8]]
|
||||||
|
@ -78,6 +78,7 @@ import project.Runtime.Missing_Required_Arguments_Spec
|
|||||||
import project.Runtime.Ref_Spec
|
import project.Runtime.Ref_Spec
|
||||||
import project.Runtime.State_Spec
|
import project.Runtime.State_Spec
|
||||||
import project.Runtime.Stack_Traces_Spec
|
import project.Runtime.Stack_Traces_Spec
|
||||||
|
import project.Runtime.Stack_Size_Spec
|
||||||
|
|
||||||
import project.System.Environment_Spec
|
import project.System.Environment_Spec
|
||||||
import project.System.File_Spec
|
import project.System.File_Spec
|
||||||
@ -160,6 +161,7 @@ main filter=Nothing =
|
|||||||
Missing_Required_Arguments_Spec.add_specs suite_builder
|
Missing_Required_Arguments_Spec.add_specs suite_builder
|
||||||
Lazy_Generator_Spec.add_specs suite_builder
|
Lazy_Generator_Spec.add_specs suite_builder
|
||||||
Stack_Traces_Spec.add_specs suite_builder
|
Stack_Traces_Spec.add_specs suite_builder
|
||||||
|
Stack_Size_Spec.add_specs suite_builder
|
||||||
Text_Spec.add_specs suite_builder
|
Text_Spec.add_specs suite_builder
|
||||||
Time_Spec.add_specs suite_builder
|
Time_Spec.add_specs suite_builder
|
||||||
URI_Spec.add_specs suite_builder
|
URI_Spec.add_specs suite_builder
|
||||||
|
137
test/Base_Tests/src/Runtime/Stack_Size_Spec.enso
Normal file
137
test/Base_Tests/src/Runtime/Stack_Size_Spec.enso
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
# Tests regression of the overall stack trace size when calling nested
|
||||||
|
# `Vector.map`. It is tested by invoking a subprocess on a generated code
|
||||||
|
# that contains `n` nested `Vector.map` calls.
|
||||||
|
# The subprocess has Truffle compiler disabled with `-Dpolyglot.engine.Compiler=false`
|
||||||
|
# to ensure there are no (Java) stack frames dropped. Moreover, we
|
||||||
|
# set explicitly `-XX:MaxJavaStackTraceDepth=...` for the subprocess to overcome
|
||||||
|
# the default length (1024) of `RuntimeException.getStackTrace` which is too low.
|
||||||
|
#
|
||||||
|
# The test runs two subprocesses with different nesting and computes the
|
||||||
|
# difference of Java stack sizes. This difference must not exceed certain limit.
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
from Standard.Base import all
|
||||||
|
import Standard.Base.Runtime.Ref.Ref
|
||||||
|
import Standard.Base.System.Process.Process_Builder.Process_Result
|
||||||
|
|
||||||
|
from Standard.Test import all
|
||||||
|
|
||||||
|
|
||||||
|
## Find the Enso binary under the `built-distribution` directory
|
||||||
|
enso_bin -> File =
|
||||||
|
find_prefix dir prefix =
|
||||||
|
vec = dir.list name_filter=prefix+"*"
|
||||||
|
if vec.length == 1 then vec.at 0 else
|
||||||
|
msg = "Cannot find " + prefix + "* in " + dir.to_text + '\n'
|
||||||
|
err = dir.list.fold msg t-> f->
|
||||||
|
t + f.to_text + '\n'
|
||||||
|
Panic.throw err
|
||||||
|
|
||||||
|
project_root = File.new enso_project.root.to_text
|
||||||
|
repository_root = project_root . parent . parent
|
||||||
|
built_distribution = find_prefix repository_root "built-distribution"
|
||||||
|
enso_engine = find_prefix built_distribution "enso-engine-"
|
||||||
|
enso = find_prefix enso_engine "enso-"
|
||||||
|
bin = find_prefix enso "bin"
|
||||||
|
|
||||||
|
exe = File.new bin / if Platform.os == Platform.OS.Windows then "enso.bat" else "enso"
|
||||||
|
|
||||||
|
if exe.is_regular_file.not then Panic.throw "Cannot find "+exe.to_text
|
||||||
|
|
||||||
|
exe
|
||||||
|
|
||||||
|
## Generates code for mapping over a vector with the given nesting level.
|
||||||
|
Returns code of the main method that is meant to be pasted into a separate module.
|
||||||
|
The code prints the count of Java frames to stdout in the deepest `Vector.map` call.
|
||||||
|
|
||||||
|
Example of the code is (for nesting_level 2):
|
||||||
|
```
|
||||||
|
main =
|
||||||
|
vec = [[42]]
|
||||||
|
vec.map e0->
|
||||||
|
e0.map e1->
|
||||||
|
cnt = RuntimeException.new.getStackTrace.length
|
||||||
|
IO.println 'java_stack_frames='+cnt.to_text
|
||||||
|
```
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
- nesting_level How many times should the vector be nested
|
||||||
|
generate_code nesting_level:Integer -> Text =
|
||||||
|
bldr = Vector.Builder.new
|
||||||
|
bldr.append "from Standard.Base import all"
|
||||||
|
bldr.append "import Standard.Base.Internal.Extra_Imports.RuntimeException"
|
||||||
|
bldr.append '\n'
|
||||||
|
bldr.append <| "main = "
|
||||||
|
bldr.append <| " "
|
||||||
|
+ "vec = "
|
||||||
|
+ ("[" * nesting_level)
|
||||||
|
+ "42"
|
||||||
|
+ ("]" * nesting_level)
|
||||||
|
bldr.append <| " "
|
||||||
|
+ "vec.map e0->"
|
||||||
|
0.up_to (nesting_level - 1) . each \i ->
|
||||||
|
bldr.append <| (" " * (i + 2))
|
||||||
|
+ "e"
|
||||||
|
+ i.to_text
|
||||||
|
+ ".map e"
|
||||||
|
+ (i + 1).to_text
|
||||||
|
+ "-> "
|
||||||
|
bldr.append <| (" " * (nesting_level + 1))
|
||||||
|
+ "cnt = RuntimeException.new.getStackTrace.length"
|
||||||
|
bldr.append <| (" " * (nesting_level + 1))
|
||||||
|
+ "IO.println <| 'java_stack_frames=' + cnt.to_text"
|
||||||
|
+ '\n'
|
||||||
|
bldr.to_vector.reduce \first_line:Text second_line:Text ->
|
||||||
|
first_line + '\n' + second_line
|
||||||
|
|
||||||
|
|
||||||
|
## Runs Enso subprocess with disabled Truffle compiler, with
|
||||||
|
larger thread stack and also with larger stack trace element collected
|
||||||
|
(which is needed for `new RuntimeException().getStackTrace().length`)
|
||||||
|
as this value is by default set only to 1024.
|
||||||
|
|
||||||
|
The thread stack size is also set to a sufficiently large value
|
||||||
|
to ensure there is no StackOverflow.
|
||||||
|
run_without_compiler enso_args:Vector -> Process_Result =
|
||||||
|
java_opts = "-Dpolyglot.engine.Compilation=false "
|
||||||
|
+ "-XX:MaxJavaStackTraceDepth=18000 "
|
||||||
|
+ "-Xms16M"
|
||||||
|
args = ["JAVA_OPTS="+java_opts, enso_bin.path] + enso_args
|
||||||
|
Process.run "env" (args + enso_args)
|
||||||
|
|
||||||
|
|
||||||
|
## Runs enso as a subprocess with the specified nesting level of `Vector.map` calls.
|
||||||
|
Returns count of Java stack frames from the deepest `Vector.map` call.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
- nesting Level of nesting of `Vector.map` method calls.
|
||||||
|
run nesting:Integer -> Integer =
|
||||||
|
tmp_file = File.create_temporary_file suffix=".enso"
|
||||||
|
code = generate_code nesting
|
||||||
|
code.write tmp_file
|
||||||
|
proc_res = run_without_compiler ["--run", tmp_file.path]
|
||||||
|
# FInd and parse a specific line from the process stdout
|
||||||
|
j_frames_line = proc_res.stdout.split '\n' . find \line ->
|
||||||
|
line.contains "java_stack_frames"
|
||||||
|
j_frames_line.split '=' . last . parse_integer
|
||||||
|
|
||||||
|
|
||||||
|
only_on_linux = if System.os == "linux" then Nothing else "Test runs only on Linux"
|
||||||
|
|
||||||
|
|
||||||
|
add_specs suite_builder =
|
||||||
|
suite_builder.group "Stack size" pending=only_on_linux \group_builder ->
|
||||||
|
group_builder.specify "Java stack size of nested Vector.map should be kept reasonably low" <|
|
||||||
|
nesting_10 = run 10
|
||||||
|
nesting_11 = run 11
|
||||||
|
stack_size = nesting_11 - nesting_10
|
||||||
|
Test.with_clue ("Stack size of `Vector.map` should be low, but was " + stack_size.to_text + " ") <|
|
||||||
|
(stack_size < 40) . should_be_true
|
||||||
|
|
||||||
|
|
||||||
|
main filter=Nothing =
|
||||||
|
suite = Test.build \suite_builder ->
|
||||||
|
add_specs suite_builder
|
||||||
|
suite.run_with_filter filter
|
@ -86,4 +86,5 @@ collect_benches = Bench.build builder->
|
|||||||
State.run Number 0 <| random_vec.each stateful_fun
|
State.run Number 0 <| random_vec.each stateful_fun
|
||||||
|
|
||||||
|
|
||||||
main = collect_benches . run_main
|
main filter=Nothing =
|
||||||
|
collect_benches . run_main filter
|
||||||
|
Loading…
Reference in New Issue
Block a user