From c8857960403e8a904f9240cac64de45f138c1ebd Mon Sep 17 00:00:00 2001 From: Alex Zerntev Date: Fri, 29 Mar 2024 15:20:58 +0200 Subject: [PATCH] (Truffle optimizations) Final truffle optimizations (#379) - Separated pure records from records with duplicate keys - Made more PE friendly nullables and tryables - Fixed record operations to have a specialization instance per field per operation (as truffle docs suggest) - Added toString() overrides for better debugging - Merged TreeMap implementation to get and put with one walk - Added missing TruffleBoundaries - Removed language and context storage from runtime objects. It can be accessed from inside the nodes (also made it cached) --- .../rql2/tests/benchmark/BenchmarkTests.scala | 657 ++++++++---------- .../collection/CollectionRangeTest.scala | 4 + ...ql2TruffleCompilerServiceTestContext.scala | 38 + snapi-truffle/src/main/java/module-info.java | 9 +- .../snapi/truffle/TruffleEmitter.java | 4 +- .../snapi/truffle/TruffleEntryExtension.java | 21 +- .../TruffleCountCollectionEntry.java | 19 +- .../TruffleDistinctCollectionEntry.java | 22 +- .../TruffleExistsCollectionEntry.java | 30 +- .../TruffleFilterCollectionEntry.java | 26 +- .../TruffleGroupCollectionEntry.java | 23 +- ...ruffleInternalEquiJoinCollectionEntry.java | 39 +- .../TruffleInternalJoinCollectionEntry.java | 39 +- .../TruffleLastCollectionEntry.java | 19 +- .../TruffleMaxCollectionEntry.java | 19 +- .../TruffleMinCollectionEntry.java | 19 +- .../TruffleMkStringCollectionEntry.java | 27 +- .../TruffleOrderByCollectionEntry.java | 44 +- .../TruffleSumCollectionEntry.java | 19 +- .../TruffleTupleAvgCollectionEntry.java | 17 +- .../builtin/json_extension/JsonParser.java | 54 +- .../TruffleExistsListEntry.java | 27 +- .../TruffleFilterListEntry.java | 40 +- .../list_extension/TruffleFromListEntry.java | 32 +- .../list_extension/TruffleGroupListEntry.java | 36 +- .../list_extension/TruffleMaxListEntry.java | 23 +- .../list_extension/TruffleMinListEntry.java | 23 +- .../list_extension/TruffleSumListEntry.java | 23 +- .../TruffleTransformListEntry.java | 37 +- .../TruffleUnsafeFromListEntry.java | 33 +- .../TruffleRecordBuildEntry.java | 19 +- .../TruffleStrictArgsTestEntry.java | 8 +- .../test_extension/TruffleValueArg.java | 4 +- .../xml_extension/TruffleParseXmlEntry.java | 65 +- .../xml_extension/TruffleReadXmlEntry.java | 64 +- .../truffle/compiler/SnapiTruffleEmitter.java | 4 +- .../raw/runtime/truffle/ExpressionNode.java | 12 +- .../raw/runtime/truffle/PropertyType.java | 48 ++ .../java/raw/runtime/truffle/RawContext.java | 14 +- .../java/raw/runtime/truffle/RawLanguage.java | 25 +- .../raw/runtime/truffle/RawLanguageCache.java | 4 + .../java/raw/runtime/truffle/RawTypes.java | 6 +- .../truffle/ast/ProgramExpressionNode.java | 5 + .../raw/runtime/truffle/ast/TypeGuards.java | 27 +- .../truffle/ast/controlflow/ExpBlockNode.java | 5 + .../aggregation/AggregateMultipleNode.java | 93 +++ .../aggregation/AggregateSingleNode.java | 91 +++ .../aggregation/Aggregations.java} | 5 +- .../aggregation}/AggregatorNodes.java | 28 +- .../ast/expressions/binary/AndNode.java | 9 +- .../ast/expressions/binary/OrNode.java | 9 +- .../aws_package/AwsV4SignedRequestNode.java | 403 ++++++----- .../binary_package/BinaryReadNode.java | 13 +- .../EnvironmentParameterNode.java | 191 ++++- .../EnvironmentScopesNode.java | 14 +- .../EnvironmentSecretNode.java | 13 +- .../builtin/http_package/HttpReadNode.java | 50 +- .../LocationDescribeNode.java | 64 +- .../location_package/LocationLlNode.java | 64 +- .../string_package/StringReadLinesNode.java | 15 +- .../string_package/StringReadNode.java | 14 +- .../ast/expressions/function/MethodNode.java | 4 +- .../iterable/ArrayOperationNodes.java | 201 ++++++ .../collection/CollectionCountNode.java | 42 -- .../collection/CollectionDistinctNode.java | 24 +- .../collection/CollectionEquiJoinNode.java | 30 +- .../collection/CollectionExistsNode.java | 100 ++- .../collection/CollectionFilterNode.java | 38 +- .../collection/CollectionGroupByNode.java | 28 +- .../collection/CollectionJoinNode.java | 56 +- .../collection/CollectionLastNode.java | 54 -- .../collection/CollectionMaxNode.java | 40 -- .../collection/CollectionMinNode.java | 41 -- .../collection/CollectionMkStringNode.java | 103 ++- .../collection/CollectionOrderByNode.java | 20 +- .../collection/CollectionSumNode.java | 41 -- .../collection/CollectionTupleAvgNode.java | 68 +- .../iterable/list/ListExistsNode.java | 107 ++- .../iterable/list/ListFilterNode.java | 142 +++- .../iterable/list/ListFromNode.java | 359 +++------- .../iterable/list/ListFromUnsafe.java | 340 +++------ .../iterable/list/ListGroupByNode.java | 179 +++-- .../iterable/list/ListMaxNode.java | 39 -- .../iterable/list/ListMinNode.java | 39 -- .../iterable/list/ListSumNode.java | 39 -- .../iterable/list/ListTransformNode.java | 375 ++-------- .../expressions/option/OptionFlatMapNode.java | 24 +- .../option/OptionGetOrElseNode.java | 13 +- .../option/OptionIsDefinedNode.java | 8 +- .../ast/expressions/option/OptionMapNode.java | 24 +- .../option/OptionUnsafeGetNode.java | 12 +- .../record/RecordAddFieldNode.java | 59 +- .../expressions/record/RecordBuildNode.java | 39 +- .../expressions/record/RecordConcatNode.java | 80 ++- .../expressions/record/RecordFieldsNode.java | 28 +- .../expressions/record/RecordProjNode.java | 13 +- .../record/RecordRemoveFieldNode.java | 72 +- .../record/RecordStaticInitializers.java | 52 ++ .../expressions/record/RecordWriteNode.java | 44 -- .../tryable/TryableFlatMapNode.java | 24 +- .../tryable/TryableGetFailureNode.java | 8 +- .../tryable/TryableIsFailureNode.java | 8 +- .../tryable/TryableIsSuccessNode.java | 8 +- .../expressions/tryable/TryableMapNode.java | 24 +- .../tryable/TryableNullableFlatMapNode.java | 35 +- .../tryable/TryableUnsafeGetNode.java | 19 +- .../ast/io/binary/BinaryWriterNode.java | 10 +- .../io/binary/NullableBinaryWriterNode.java | 9 +- .../io/binary/TryableBinaryWriterNode.java | 15 +- .../reader/parser/IterableParseCsvFile.java | 17 +- .../reader/parser/IterableParseCsvString.java | 11 +- .../csv/reader/parser/RecordParseCsvNode.java | 28 +- .../io/csv/writer/CsvIterableWriterNode.java | 5 +- .../ast/io/csv/writer/CsvListWriterNode.java | 5 +- .../writer/internal/NullableWriteCsvNode.java | 9 +- .../writer/internal/RecordWriteCsvNode.java | 14 +- .../writer/internal/TryableWriteCsvNode.java | 15 +- .../truffle/ast/io/jdbc/JdbcQueryNode.java | 3 +- .../ast/io/jdbc/RecordReadJdbcQuery.java | 46 +- .../ast/io/json/reader/JsonParserNodes.java | 49 +- .../json/reader/JsonReadCollectionNode.java | 6 +- .../ast/io/json/reader/JsonReadValueNode.java | 8 +- .../json/reader/parser/ListParseJsonNode.java | 379 +++------- .../reader/parser/NullableParseJsonNode.java | 4 +- .../json/reader/parser/OrParseJsonNode.java | 6 +- .../reader/parser/RecordParseJsonNode.java | 82 ++- .../ast/io/json/writer/JsonWriteNodes.java | 76 +- .../ast/io/json/writer/JsonWriterNode.java | 9 +- .../internal/NullableWriteJsonNode.java | 9 +- .../writer/internal/RecordWriteJsonNode.java | 28 +- .../internal/TryableUnsafeWriteJsonNode.java | 15 +- .../writer/internal/TryableWriteJsonNode.java | 15 +- .../truffle/ast/io/kryo/KryoFromNode.java | 3 +- .../ast/io/xml/parser/RecordParseXmlNode.java | 50 +- .../io/xml/parser/XmlParseCollectionNode.java | 2 +- .../io/xml/parser/XmlReadCollectionNode.java | 5 +- .../ast/io/xml/parser/XmlReadValueNode.java | 7 +- .../truffle/ast/osr/OSRGeneratorNode.java | 49 ++ .../OSRCollectionEquiJoinInitBodyNode.java | 63 ++ .../bodies/OSRCollectionFilterBodyNode.java | 69 ++ .../bodies/OSRCollectionJoinInitBodyNode.java | 58 ++ .../bodies/OSRCollectionMkStringBodyNode.java | 57 ++ .../bodies/OSRDistinctGetGeneratorNode.java | 56 ++ .../osr/bodies/OSREquiJoinNextBodyNode.java | 106 +++ .../ast/osr/bodies/OSRExistsBodyNode.java | 65 ++ .../ast/osr/bodies/OSRJoinNextBodyNode.java | 160 +++++ .../bodies/OSRListEquiJoinInitBodyNode.java | 63 ++ .../ast/osr/bodies/OSRListFilterBodyNode.java | 69 ++ .../ast/osr/bodies/OSRListFromBodyNode.java | 48 ++ .../osr/bodies/OSRListParseJsonBodyNode.java | 48 ++ .../osr/bodies/OSRListTransformBodyNode.java | 70 ++ .../bodies/OSRMultiAggregationBodyNode.java | 59 ++ .../bodies/OSROrderByGetGeneratorNode.java | 74 ++ .../bodies/OSRSingleAggregationBodyNode.java | 59 ++ .../ast/osr/bodies/OSRToArrayBodyNode.java | 72 ++ .../OSRCollectionFilterConditionNode.java | 47 ++ .../conditions/OSRExistsConditionNode.java | 46 ++ .../conditions/OSRFromBodyConditionNode.java | 36 + .../conditions/OSRHasNextConditionNode.java | 43 ++ .../OSRIsLessThanSizeConditionNode.java | 40 ++ .../OSRListParseJsonConditionNode.java | 45 ++ .../runtime/aggregation/AggregationNodes.java | 96 --- .../runtime/aggregation/MultiAggregation.java | 25 - .../aggregation/SingleAggregation.java | 25 - .../treemap/TreeMapIterator.java | 74 ++ .../data_structures/treemap/TreeMapNode.java | 44 ++ .../data_structures/treemap/TreeMapNodes.java | 140 ++++ .../treemap/TreeMapObject.java | 245 +++++++ .../treemap/TreeMapStatic.java | 72 ++ .../generator/collection/GeneratorNodes.java | 93 +-- .../collection/StaticInitializers.java | 122 ++++ .../compute_next/ComputeNextNodes.java | 426 ++++++------ .../operations/EquiJoinComputeNext.java | 68 +- .../operations/FilterComputeNext.java | 42 +- .../operations/JoinComputeNext.java | 76 +- .../operations/ZipComputeNext.java | 11 +- .../sources/CsvReadComputeNext.java | 8 - .../sources/JsonReadComputeNext.java | 14 +- .../sources/ReadLinesComputeNext.java | 2 + .../sources/XmlReadComputeNext.java | 8 - .../input_buffer/GroupByInputBuffer.java | 2 + .../input_buffer/InputBufferNodes.java | 54 +- .../input_buffer/OrderByInputBuffer.java | 2 + .../off_heap/OffHeapNodes.java | 324 ++++----- .../distinct/DistinctMemoryGenerator.java | 6 +- .../off_heap/distinct/OffHeapDistinct.java | 44 +- .../group_by/GroupByMemoryGenerator.java | 10 +- .../off_heap/group_by/OffHeapGroupByKey.java | 58 +- .../off_heap/order_by/OffHeapGroupByKeys.java | 62 +- .../order_by/OrderByMemoryGenerator.java | 10 +- .../record_shaper/RecordShaper.java | 11 +- .../record_shaper/RecordShaperNodes.java | 53 +- .../runtime/iterable/IterableNodes.java | 150 ++-- .../operations/DistinctCollection.java | 38 +- .../operations/EquiJoinCollection.java | 35 +- .../iterable/operations/FilterCollection.java | 36 +- .../operations/GroupByCollection.java | 45 +- .../iterable/operations/JoinCollection.java | 40 +- .../operations/OrderByCollection.java | 44 +- .../iterable/operations/ZipCollection.java | 7 - .../iterable/sources/CsvCollection.java | 8 +- .../iterable/sources/JsonReadCollection.java | 11 +- .../iterable/sources/XmlParseCollection.java | 6 +- .../iterable/sources/XmlReadCollection.java | 8 +- .../truffle/runtime/kryo/KryoNodes.java | 217 +++--- .../runtime/operators/OperatorNodes.java | 133 ++-- ...ordObject.java => DuplicateKeyRecord.java} | 147 ++-- .../record/DuplicateKeyRecordNodes.java | 289 ++++++++ .../truffle/runtime/record/KeysObject.java | 52 ++ .../truffle/runtime/record/PureRecord.java | 115 +++ .../runtime/record/PureRecordNodes.java | 304 ++++++++ .../truffle/runtime/record/RecordNodes.java | 187 +++-- .../runtime/record/RecordStorageObject.java | 24 - .../truffle/tryable_nullable/Tryable.java | 8 +- .../tryable_nullable/TryableNullable.java | 36 - .../TryableNullableNodes.java | 151 ++++ 216 files changed, 8150 insertions(+), 4522 deletions(-) create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/PropertyType.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/aggregation/AggregateMultipleNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/aggregation/AggregateSingleNode.java rename snapi-truffle/src/main/java/raw/runtime/truffle/{runtime/aggregation/aggregator/Aggregators.java => ast/expressions/aggregation/Aggregations.java} (81%) rename snapi-truffle/src/main/java/raw/runtime/truffle/{runtime/aggregation/aggregator => ast/expressions/aggregation}/AggregatorNodes.java (80%) create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/ArrayOperationNodes.java delete mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionCountNode.java delete mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionLastNode.java delete mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionMaxNode.java delete mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionMinNode.java delete mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionSumNode.java delete mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListMaxNode.java delete mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListMinNode.java delete mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListSumNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordStaticInitializers.java delete mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordWriteNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/OSRGeneratorNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRCollectionEquiJoinInitBodyNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRCollectionFilterBodyNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRCollectionJoinInitBodyNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRCollectionMkStringBodyNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRDistinctGetGeneratorNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSREquiJoinNextBodyNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRExistsBodyNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRJoinNextBodyNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListEquiJoinInitBodyNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListFilterBodyNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListFromBodyNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListParseJsonBodyNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListTransformBodyNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRMultiAggregationBodyNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSROrderByGetGeneratorNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRSingleAggregationBodyNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRToArrayBodyNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRCollectionFilterConditionNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRExistsConditionNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRFromBodyConditionNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRHasNextConditionNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRIsLessThanSizeConditionNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRListParseJsonConditionNode.java delete mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/runtime/aggregation/AggregationNodes.java delete mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/runtime/aggregation/MultiAggregation.java delete mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/runtime/aggregation/SingleAggregation.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapIterator.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapNode.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapNodes.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapObject.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapStatic.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/StaticInitializers.java rename snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/{RecordObject.java => DuplicateKeyRecord.java} (51%) create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/DuplicateKeyRecordNodes.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/KeysObject.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/PureRecord.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/PureRecordNodes.java delete mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/RecordStorageObject.java delete mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/tryable_nullable/TryableNullable.java create mode 100644 snapi-truffle/src/main/java/raw/runtime/truffle/tryable_nullable/TryableNullableNodes.java diff --git a/snapi-client/src/test/scala/raw/compiler/rql2/tests/benchmark/BenchmarkTests.scala b/snapi-client/src/test/scala/raw/compiler/rql2/tests/benchmark/BenchmarkTests.scala index bc3f1277b..304bb49c2 100644 --- a/snapi-client/src/test/scala/raw/compiler/rql2/tests/benchmark/BenchmarkTests.scala +++ b/snapi-client/src/test/scala/raw/compiler/rql2/tests/benchmark/BenchmarkTests.scala @@ -16,410 +16,307 @@ import raw.compiler.rql2.tests.CompilerTestContext trait BenchmarkTests extends CompilerTestContext { - val shouldBeExecuted = false + property("raw.training-wheels", "false") - val numberOfRuns = 10 + // testing if the code is running +// test( + // """let + // | lineitemsType = type collection(record(l_orderkey: int, l_payedammount: double)), + // | customerType = type record(customer: collection(record(c_custkey: string))), + // | ordersType = type collection(record(o_orderkey: int, o_custkey: int)), + // | lineitems = PostgreSQL.Query( + // | "postgres", + // | "select l_orderkey, (l_extendedprice * (1 - l_discount)) as l_payedammount from tpch1.lineitem", + // | lineitemsType, + // | host = "localhost:44444", + // | username = "postgres", + // | password = "1234" + // | ), + // | customers = Json.Read("file:///home/ld/workspace/TPCH/1GB/customer.json", customerType), // an object with an array inside + // | orders = Csv.Read("file:///home/ld/workspace/TPCH/1GB/orders.csv", ordersType, delimiter = "\t"), + // | customersOrders = Collection.EquiJoin(customers.customer, orders, (c) -> Int.From(c.c_custkey), (o) -> o.o_custkey), + // | customerOrdersItems = Collection.EquiJoin( + // | customersOrders, + // | lineitems, + // | (co) -> Int.From(co.o_orderkey), + // | (oi) -> oi.l_orderkey + // | ), + // | grouped = Collection.GroupBy(customerOrdersItems, (c) -> c.c_custkey), + // | result = Collection.Transform(grouped, (g) -> {id: g, total_payed: Collection.Sum(g.group.l_payedammount)}), + // | finalResult = Collection.Filter(result, (r) -> r.total_payed > 6000000) + // |in + // | Collection.Count(finalResult)""".stripMargin + // )(_ should evaluateTo("9L")) - test("Range Count test") { _ => - assume(shouldBeExecuted, "This test is disabled by default") - - fastExecute("""let a = "hello" in a """) // some random query - fastExecute("""let a = 2 + 2 in a """) // some random query - fastExecute("""let a = 2/2 in a """) // some random query - - val prog = """// Utility functions - |min(a: double, b: double) = if(a<=b) then a else b - |max(a: double, b: double) = if(a>=b) then a else b - |//dayOfYear(d: date):int = Int.From(Interval.ToMillis(Date.Subtract(d, Date.Build(Date.Year(d), 1, 1))) / 8.64e+7) + 1 - |dayOfYear(d: date) = - |let - | getDaysOfMonth(year:int, month:int)= - | let - | start=Date.Build(year,month,1), - | end=Date.FromTimestamp(Date.SubtractInterval(Date.Build(year, month+1, 1), Interval.Build(days=1))) - | in - | Interval.Days(Date.Subtract(end, start))+1 - | , - | - | rec m2(d:date, month:int):int = - | let - | year=Date.Year(d), - | i1=Date.Subtract(d, Date.Build(year, month, 1)), - | mondiff=Interval.Months(i1), - | daysDiff=Interval.Days(i1), - | output = - | if(mondiff<0) then 0 - | else if(mondiff==0) then daysDiff - | else getDaysOfMonth(year, month)+m2(d, month+1) - | in - | output - | , - | output=m2(d,1)+1 + test("Debugging") { _ => + assume(false, "This test is disabled by default") + + val prog = """let + | col1 = Collection.Transform(Long.Range(0, 10000000), (i) -> {a1: i, b1: String.From(i)}), + | col2 = Collection.Transform(Long.Range(0, 1000000), (i) -> {a2: i, b2: String.From(i)}), + | col3 = Collection.Transform(Long.Range(0, 1000000), (i) -> {a3: i, b3: String.From(i)}), + | result1 = Collection.EquiJoin(col1, col2, i -> i.a1, i->i.a2), + | result2 = Collection.EquiJoin(result1, col3, i -> i.a1, i->i.a3) |in - | output - | - |isLeapYear(year: int) = - | if (year % 4 == 0 and year % 100 != 0 ) or (year % 400 == 0) then true - | else false - | - |// Normalization functions - |// we saw that some watt numbers where actually kilowatts, so we simply divided by 1000 - also negative watts numbers become zeros - |normalizeWatt(a: double) = if(a>=1000) then a/1000.0 else max(0,a) - |normalizeTemperature(a: double) = a - | - |// Calculate PDC for a given time slot - |find_I_panel_pdc(r: record(timestamp: timestamp, watt: int, temperature: double), angle: double, method: string) = - | let - | std=1367.00, - | year=Timestamp.Year(r.timestamp), - | days_of_year=if(isLeapYear(year)) then 366.0 else 365.0, - | day_of_year=dayOfYear(Date.FromTimestamp(r.timestamp)), - | cur_time=Time.Build(Timestamp.Hour(r.timestamp), Timestamp.Minute(r.timestamp)), - | latitude=37.97385, - | time_math=Time.Hour(cur_time)+Time.Minute(cur_time)/Double.From(60.00), - | beta=(360.00*(day_of_year-1.00))/days_of_year, - | delta=23.45*Math.Sin(Math.Radians(360.00*(284.00+day_of_year)/days_of_year)), - | e_min=229.2*(0.000075+(0.001868*Math.Cos(Math.Radians(beta)))-(0.032077*Math.Sin(Math.Radians(beta)))-(0.014615*Math.Cos(Math.Radians(2.00*beta)))-(0.04089*Math.Sin(Math.Radians(2.00*beta)))), - | t_solar=time_math+e_min/60.00+4.00*(30.00-23.78743)/60.00, - | omega=15.00*(t_solar-12.00), - | sin_beta=(Math.Sin(Math.Radians(delta)))*Math.Sin(Math.Radians(latitude))+(Math.Cos(Math.Radians(delta)))*Math.Cos(Math.Radians(latitude))*Math.Cos(Math.Radians(omega)), - | b_m=Math.Asin(sin_beta)*180.00/Math.Pi(), - | e_o=1.0001+(0.034221*Math.Cos(Math.Radians(beta)))+(0.00128*Math.Sin(Math.Radians(beta)))+(0.000719*Math.Cos(Math.Radians(2.0*beta)))+(0.000077*Math.Sin(Math.Radians(2.0*beta))), - | g_extraterrestrial=e_o*std, - | g_global_h_oa_na=e_o*std*sin_beta, - | g_global_h_oa=max(0,g_global_h_oa_na), - | k_t_base=r.watt/g_global_h_oa, - | k_t= - | if(g_global_h_oa<=0) - | then 0 - | else - | if(k_t_base>1) - | then 1 - | else k_t_base, - | kappa=k_t, - | kappa_d= - | if(method=="erbs") - | then - | if(kappa<=0.22) - | then 1.0-0.09*kappa - | else if(kappa>=0.8) - | then 0.165 - | else 0.9511-0.1604*kappa+4.388*Math.Power(kappa,2)-16.638*Math.Power(kappa,3)+12.336*Math.Power(kappa,4) - | else if(method=="karatasou") - | then - | (if(kappa<=0.78) - | then 0.9995-0.05*kappa-2.4156*Math.Power(kappa,2) +1.4926*Math.Power(kappa,3) - | else 0.20) - | else Error.Build("Illegal method. Valid methods are 'erbs' and 'karatasou'") - | , - | g_beam_h_10min=(if(sin_beta>0) then (r.watt*(1-kappa_d)) else 0), - | g_diff_10min=r.watt-g_beam_h_10min, - | g_beam_i_10min=(if(g_beam_h_10min*Math.Sin(Math.Radians(angle+b_m))/Math.Sin(Math.Radians(b_m))>g_extraterrestrial) then 0 else (g_beam_h_10min*Math.Sin(Math.Radians((angle+b_m)))/Math.Sin(Math.Radians(b_m)))), - | g_diff_i_10min=g_diff_10min*(1+Math.Cos(Math.Radians(angle)))/2.00, - | g_albedo_i_10min=r.watt*0.2*(1-Math.Cos(Math.Radians(angle)))/2.00, - | g_glogal_i_10min=g_beam_i_10min+g_diff_i_10min+g_albedo_i_10min, - | output=g_glogal_i_10min/6000 - | in - | output - | //Debugging: {timestamp:r.timestamp,sin_beta:sin_beta, e_o: e_o, g_global_h_oa: g_global_h_oa, k_t: k_t, kappa_d:kappa_d, g_diff_10min:g_diff_10min, g_beam_i_10min: g_beam_i_10min, g_diff_i_10min: g_diff_i_10min, g_albedo_i_10min: g_albedo_i_10min, t_cell: t_cell, p_dc: p_dc} - | - | - |// Main method - |main(min_date_inclusive: date = Date.Build(1998,12,11), max_date_inclusive: date = Date.Build(2009,09,01), method: string = "erbs") = - | let - | // Iterate through angles [0..89] - | min_angle=0, - | max_angle=90, - | - | output= - | // Valid time period is [1998-12-11 .. 2009-09-01) - | if(Date.Build(1998,12,11)>min_date_inclusive or max_date_inclusive>Date.Build(2009,09,01)) then Error.Build("Illegal period. Permissible period is [1999/01/01 .. 2009/09/01]") - | else - | let - | angles=List.From(Int.Range(min_angle, max_angle)), - | - | // Get temperatures from meteo (uploaded to a public site) - | temperature_raw=Csv.InferAndRead("file:/home/ld/Downloads/truffle_data/dataset_temperature_athens.csv"), - | // Consider only temperature measurements that are within the valid time period and normalize them - | temperature_data= - | List.From(Collection.Transform( - | Collection.Filter( - | temperature_raw, - | c -> Date.FromTimestamp(c._1)>=min_date_inclusive and Date.FromTimestamp(c._1)<=max_date_inclusive - | ), - | c -> {timestamp: c._1, temperature: normalizeTemperature(c._2)} - | )), - | - | // Get solar radiation from meteo (uploaded to a public site) - | solar_radiation_raw=Csv.InferAndRead("file:/home/ld/Downloads/truffle_data/dataset_solar_radiation_athens_v2.csv"), - | // Consider only solar radiation measurements that are within the valid time period and normalize them - | solar_radiation_data= - | Collection.Transform( - | Collection.Filter( - | solar_radiation_raw, - | c -> Date.FromTimestamp(c._1)>=min_date_inclusive and Date.FromTimestamp(c._1)<=max_date_inclusive - | ), - | c -> {timestamp: c._1, watt: Int.From(normalizeWatt(c._2)*1000)} - | ), - | solar_radiation_list=List.From(solar_radiation_data), - | - | // Join solar radiation and temperature lists, based on their timestamps - | combined_data= - | List.Transform(List.EquiJoin(temperature_data, solar_radiation_list, a -> a.timestamp, b -> b.timestamp), - | r -> {timestamp: Record.GetFieldByIndex(r, 1), watt:r.watt, temperature: r.temperature} - | ), - | - | // For each angle [0..89] calculate the total output - | output=List.Transform(angles, angle -> - | { - | angle: Double.From(angle), - | H: - | List.Sum(List.Transform(combined_data, r -> find_I_panel_pdc(r, Double.From(angle), method))) - | } - | ) - | in - | output - | in - | // Sort angles by higher output - | //List.OrderBy(output, r -> r.H, "DESC") - | output - | - | - |// Test run: entire 2006 - |main(min_date_inclusive=Date.Build(2008,2,1), max_date_inclusive=Date.Build(2008,2,1)) - |//dayOfYear(Date.Build(2006,3,1)) - |//isLeapYear(2008)""".stripMargin - - //Warmup + | Collection.Count(result2)""".stripMargin + + val startedIn = System.currentTimeMillis() fastExecute(prog) + val elapsedIn = System.currentTimeMillis() + logger.info("++++++++++ First run: " + (elapsedIn - startedIn)) + + val numberOfRuns = 0 + + val values = Array.fill(numberOfRuns)(0L) + + val lastIdx = numberOfRuns - 1 + + for (i <- 0 to lastIdx) { + val startedIn = System.currentTimeMillis() + fastExecute(prog) + val elapsedIn = System.currentTimeMillis() + values(i) = elapsedIn - startedIn + logger.info("++++++++++ Next run: " + values(i)) + } + + val mean = (values.sum) / 1 + + var standardDeviation = 0.0 + for (num <- values) { + standardDeviation += Math.pow(num - mean, 2) + } + + logger.info("++++++++++ Average execution time: " + mean) + logger.info("++++++++++ Standard deviation is: " + Math.sqrt(standardDeviation / numberOfRuns)) + } + + test("Range Join File with db test tpch1") { _ => + assume(false, "This test is disabled by default") + + val prog = """let + | lineitemsType = type collection(record(l_orderkey: int, l_payedammount: double)), + | customerType = type record(customer: collection(record(c_custkey: string))), + | ordersType = type collection(record(o_orderkey: int, o_custkey: int)), + | lineitems = PostgreSQL.Query( + | "postgres", + | "select l_orderkey, (l_extendedprice * (1 - l_discount)) as l_payedammount from tpch1.lineitem", + | lineitemsType, + | host = "localhost:44444", + | username = "postgres", + | password = "1234" + | ), + | customers = Json.Read("file:///home/ld/workspace/TPCH/1GB/customer.json", customerType), // an object with an array inside + | orders = Csv.Read("file:///home/ld/workspace/TPCH/1GB/orders.csv", ordersType, delimiter = "\t"), + | customersOrders = Collection.EquiJoin(customers.customer, orders, (c) -> Int.From(c.c_custkey), (o) -> o.o_custkey), + | customerOrdersItems = Collection.EquiJoin( + | customersOrders, + | lineitems, + | (co) -> Int.From(co.o_orderkey), + | (oi) -> oi.l_orderkey + | ), + | grouped = Collection.GroupBy(customerOrdersItems, (c) -> c.c_custkey), + | result = Collection.Transform(grouped, (g) -> {id: g, total_payed: Collection.Sum(g.group.l_payedammount)}), + | finalResult = Collection.Filter(result, (r) -> r.total_payed > 6000000) + |in + | Collection.Count(finalResult)""".stripMargin + + val startedIn = System.currentTimeMillis() fastExecute(prog) + val elapsedIn = System.currentTimeMillis() + logger.info("++++++++++ First run: " + (elapsedIn - startedIn)) + + val numberOfRuns = 10 + + val values = Array.fill(numberOfRuns)(0L) + + val lastIdx = numberOfRuns - 1 + + for (i <- 0 to lastIdx) { + val startedIn = System.currentTimeMillis() + fastExecute(prog) + val elapsedIn = System.currentTimeMillis() + values(i) = elapsedIn - startedIn + logger.info("++++++++++ Next run: " + values(i)) + } + + val mean = (values.sum) / numberOfRuns + + var standardDeviation = 0.0 + for (num <- values) { + standardDeviation += Math.pow(num - mean, 2) + } + + logger.info("++++++++++ Average execution time: " + mean) + logger.info("++++++++++ Standard deviation is: " + Math.sqrt(standardDeviation / numberOfRuns)) + } + + test("Range Join File with db test tpch10") { _ => + assume(false, "This test is disabled by default") + + val prog = """let + | lineitemsType = type collection(record(l_orderkey: int, l_payedammount: double)), + | customerType = type record(customer: collection(record(c_custkey: string))), + | ordersType = type collection(record(o_orderkey: int, o_custkey: int)), + | lineitems = PostgreSQL.Query( + | "postgres", + | "select l_orderkey, (l_extendedprice * (1 - l_discount)) as l_payedammount from tpch10.lineitem", + | lineitemsType, + | host = "localhost:44444", + | username = "postgres", + | password = "1234" + | ), + | customers = Json.Read("file:///home/ld/workspace/TPCH/10GB/customer.json", customerType), // an object with an array inside + | orders = Csv.Read("file:///home/ld/workspace/TPCH/10GB/orders.csv", ordersType, delimiter = "|"), + | customersOrders = Collection.EquiJoin(customers.customer, orders, (c) -> Int.From(c.c_custkey), (o) -> o.o_custkey), + | customerOrdersItems = Collection.EquiJoin( + | customersOrders, + | lineitems, + | (co) -> Int.From(co.o_orderkey), + | (oi) -> oi.l_orderkey + | ), + | grouped = Collection.GroupBy(customerOrdersItems, (c) -> c.c_custkey), + | result = Collection.Transform(grouped, (g) -> {id: g, total_payed: Collection.Sum(g.group.l_payedammount)}), + | finalResult = Collection.Filter(result, (r) -> r.total_payed > 6000000) + |in + | Collection.Count(finalResult)""".stripMargin + + val startedIn = System.currentTimeMillis() fastExecute(prog) - val started = System.currentTimeMillis() - for (i <- 0 to numberOfRuns) { + val elapsedIn = System.currentTimeMillis() + logger.info("++++++++++ First run: " + (elapsedIn - startedIn)) + + val numberOfRuns = 0 + + val values = Array.fill(numberOfRuns)(0L) + + val lastIdx = numberOfRuns - 1 + + for (i <- 0 to lastIdx) { + val startedIn = System.currentTimeMillis() fastExecute(prog) + val elapsedIn = System.currentTimeMillis() + values(i) = elapsedIn - startedIn + logger.info("++++++++++ Next run: " + values(i)) + } + + val mean = (values.sum) / 1 + + var standardDeviation = 0.0 + for (num <- values) { + standardDeviation += Math.pow(num - mean, 2) } - val elapsed = System.currentTimeMillis() - logger.info("++++++++++ Average execution time time: " + ((elapsed - started) / numberOfRuns)) + logger.info("++++++++++ Average execution time: " + mean) + logger.info("++++++++++ Standard deviation is: " + Math.sqrt(standardDeviation / numberOfRuns)) } - // A.Z. this one I use for the _experimental package test just to see how it works - // test("""Math.Power(1,1)""")(it => it should run) - // test("""{a: {a: {a: {a: {a: {a: {a: {a: {a: {a: {a: {a: 1, b: 2}, b: 2}, b: 2}, b: 2}, b: 2}}}}}}}}""")(it => it should run) - -// test("Json Writer range test") { _ => - // val started = System.currentTimeMillis() - // fastExecute( - // """let a = Int.Range(0,21474836,step=1), b = Collection.Transform(a, x -> x + 1) in b""" - // ) - // val elapsed = System.currentTimeMillis() - // - // logger.info("++++++++++ Average execution time time: " + (elapsed - started)) - // } - -// test("bug-test") { _ => -// executeQuery("""main(url: string) = -// | let gpxType = type record( -// | trk: record( -// | trkseg: record( -// | trkpt: collection(record(`@lat`: double, `@lon`: double))))), -// | gpx = Xml.Read(url, type gpxType) -// | in gpx -// | -// |main("file:/home/ld/Downloads/Route Touristique du Champagne Montagne de Reims.gpx")""".stripMargin) -// } - -// test("bug-test") { _ => -// executeQuery("""main(url: string) = -// | let gpxType = type record( -// | trk: record( -// | trkseg: record( -// | trkpt: collection(record(`@lat`: double, `@lon`: double))))), -// | gpx = Xml.Read(url, type gpxType), -// | size = 100, -// | wpt = gpx.trk.trkseg.trkpt, -// | minLat = Collection.Min(wpt.`@lat`), -// | maxLat = Collection.Max(wpt.`@lat`), -// | minLon = Collection.Min(wpt.`@lon`), -// | maxLon = Collection.Max(wpt.`@lon`), -// | maxBoth = List.Max([maxLon - minLon, maxLat - minLat]), -// | normalizedCoordinates = Collection.Transform(wpt, -// | r -> { -// | x: (r.`@lon` - minLon) / maxBoth * size, -// | y: (r.`@lat` - minLat) / maxBoth * size -// | } -// | ), -// | intCoordinates = Collection.Transform(normalizedCoordinates, r -> { -// | x: Int.From(r.x), -// | y: Int.From(r.y) -// | }), -// | // dim100 = Collection.Range(0, 100), -// | dim10 = Collection.Build(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), -// | dim100 = Collection.Unnest(dim10, n1 -> Collection.Transform(dim10, n2 -> n1*10 + n2)), -// | map = Collection.Transform(dim100, -// | y -> Collection.Transform(dim100, -// | x -> -// | // check 100 - y to make the map upside down -// | if Nullable.IsNull(Collection.First(Collection.Filter(intCoordinates, r -> r.x == x and r.y == 100 - y))) -// | then "-" -// | else "+" -// | ) -// | ) -// | in map -// | -// |main("file:/home/ld/Downloads/Route Touristique du Champagne Montagne de Reims.gpx")""".stripMargin) -// } - -// test("bug-test") { _ => -// val started = System.currentTimeMillis() -// fastExecute("""getAuth0Users( -// | email: string = null, -// | start_date: date = Date.FromTimestamp(Date.SubtractInterval(Date.Now(), Interval.Build(months = 1))), -// | last_login_since: date = Date.FromTimestamp(Date.SubtractInterval(Date.Now(), Interval.Build(years = 1))), -// | end_date: date = Date.FromTimestamp(Date.AddInterval(Date.Now(), Interval.Build(days = 1))), -// | organization: string = null) = -// | let -// | auth0_user_type = type record( -// | created_at: string, -// | email: string, -// | email_verified: bool, -// | user_id: string, -// | last_login: string, -// | last_ip: string, -// | logins_count: int, -// | app_metadata: record( -// | rawOrg: collection(string), -// | raw_clients: collection(undefined) -// | ) -// | ), -// | auth0_users_type = type collection(record( -// | created_at: string, -// | email: string, -// | email_verified: bool, -// | user_id: string, -// | last_login: string, -// | last_ip: string, -// | logins_count: int, -// | app_metadata: record( -// | rawOrg: collection(string), -// | raw_clients: collection(undefined) -// | ) -// | )), -// | -// | rec getUserPage(page: int = 1): auth0_users_type = -// | let -// | payload = -// | if(page>10 or page<0) -// | then -// | Error.Build("Illegal page number. Valid pages are [1..10]") -// | else if(page==10) -// | then -// | Collection.Empty(auth0_user_type) -// | else -// | Collection.Union( -// | Json.Read( -// | Http.Get( -// | "https://raw.eu.auth0.com/api/v2/users", -// | token="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlFUaERPVGc1TXpkQ1FUbENRVGd6TVRsRU1URTFOVFl3TVRrM1JUTkdRall6TWtNME1qSkZPUSJ9.eyJpc3MiOiJodHRwczovL3Jhdy5ldS5hdXRoMC5jb20vIiwic3ViIjoiZ2ttZGxnYTRqeEt4cmFoYVVwT3Q0YkJaTElBeXk0ZDZAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vcmF3LmV1LmF1dGgwLmNvbS9hcGkvdjIvIiwiaWF0IjoxNjkzODMxNzkwLCJleHAiOjExNjkzODMxNzg5LCJhenAiOiJna21kbGdhNGp4S3hyYWhhVXBPdDRiQlpMSUF5eTRkNiIsInNjb3BlIjoicmVhZDpjbGllbnRfZ3JhbnRzIGNyZWF0ZTpjbGllbnRfZ3JhbnRzIGRlbGV0ZTpjbGllbnRfZ3JhbnRzIHVwZGF0ZTpjbGllbnRfZ3JhbnRzIHJlYWQ6dXNlcnMgdXBkYXRlOnVzZXJzIGRlbGV0ZTp1c2VycyBjcmVhdGU6dXNlcnMgcmVhZDp1c2Vyc19hcHBfbWV0YWRhdGEgdXBkYXRlOnVzZXJzX2FwcF9tZXRhZGF0YSBkZWxldGU6dXNlcnNfYXBwX21ldGFkYXRhIGNyZWF0ZTp1c2Vyc19hcHBfbWV0YWRhdGEgY3JlYXRlOnVzZXJfdGlja2V0cyByZWFkOmNsaWVudHMgdXBkYXRlOmNsaWVudHMgZGVsZXRlOmNsaWVudHMgY3JlYXRlOmNsaWVudHMgcmVhZDpjbGllbnRfa2V5cyB1cGRhdGU6Y2xpZW50X2tleXMgZGVsZXRlOmNsaWVudF9rZXlzIGNyZWF0ZTpjbGllbnRfa2V5cyByZWFkOmNvbm5lY3Rpb25zIHVwZGF0ZTpjb25uZWN0aW9ucyBkZWxldGU6Y29ubmVjdGlvbnMgY3JlYXRlOmNvbm5lY3Rpb25zIHJlYWQ6cmVzb3VyY2Vfc2VydmVycyB1cGRhdGU6cmVzb3VyY2Vfc2VydmVycyBkZWxldGU6cmVzb3VyY2Vfc2VydmVycyBjcmVhdGU6cmVzb3VyY2Vfc2VydmVycyByZWFkOmRldmljZV9jcmVkZW50aWFscyB1cGRhdGU6ZGV2aWNlX2NyZWRlbnRpYWxzIGRlbGV0ZTpkZXZpY2VfY3JlZGVudGlhbHMgY3JlYXRlOmRldmljZV9jcmVkZW50aWFscyByZWFkOnJ1bGVzIHVwZGF0ZTpydWxlcyBkZWxldGU6cnVsZXMgY3JlYXRlOnJ1bGVzIHJlYWQ6cnVsZXNfY29uZmlncyB1cGRhdGU6cnVsZXNfY29uZmlncyBkZWxldGU6cnVsZXNfY29uZmlncyByZWFkOmVtYWlsX3Byb3ZpZGVyIHVwZGF0ZTplbWFpbF9wcm92aWRlciBkZWxldGU6ZW1haWxfcHJvdmlkZXIgY3JlYXRlOmVtYWlsX3Byb3ZpZGVyIGJsYWNrbGlzdDp0b2tlbnMgcmVhZDpzdGF0cyByZWFkOnRlbmFudF9zZXR0aW5ncyB1cGRhdGU6dGVuYW50X3NldHRpbmdzIHJlYWQ6bG9ncyByZWFkOnNoaWVsZHMgY3JlYXRlOnNoaWVsZHMgZGVsZXRlOnNoaWVsZHMgdXBkYXRlOnRyaWdnZXJzIHJlYWQ6dHJpZ2dlcnMgcmVhZDpncmFudHMgZGVsZXRlOmdyYW50cyByZWFkOmd1YXJkaWFuX2ZhY3RvcnMgdXBkYXRlOmd1YXJkaWFuX2ZhY3RvcnMgcmVhZDpndWFyZGlhbl9lbnJvbGxtZW50cyBkZWxldGU6Z3VhcmRpYW5fZW5yb2xsbWVudHMgY3JlYXRlOmd1YXJkaWFuX2Vucm9sbG1lbnRfdGlja2V0cyByZWFkOnVzZXJfaWRwX3Rva2VucyBjcmVhdGU6cGFzc3dvcmRzX2NoZWNraW5nX2pvYiBkZWxldGU6cGFzc3dvcmRzX2NoZWNraW5nX2pvYiByZWFkOmN1c3RvbV9kb21haW5zIGRlbGV0ZTpjdXN0b21fZG9tYWlucyBjcmVhdGU6Y3VzdG9tX2RvbWFpbnMiLCJndHkiOiJjbGllbnQtY3JlZGVudGlhbHMifQ.BWM8qNG7hWx95e5TIsZDd7wyPLrSt06BYUsDGtTzYbEJMiWmJJlcUv-J1oZMJfrO4OLfFIqNAYeu5SpK--2nC-rRDFRE9Nw9pBWRfx08L3jeODTSQ3NlfmKP0jKSLCs3af6Q4c-dZFPxRXHyk1Kh9QUlk7-wUJDdnB4WCcw64dilfe_tt2HNFMYvFSNSbfzcAdMEfBRRHnjjYUBGrkY2zE8adoc-QRQKi0a7MkRoXJsDi-LRNwr0Nvy1AceLuAkxjPgN6R47vdBTziRBxTIBCgmUWbXcrXXGwGPtnXIq3KsaDlI7jq2ZoUvvSWu4XzD0HQSNwYo2oR-Mh2hJ-CiBMw", -// | args=List.Build( -// | Record.Build(_1="per_page",_2="100"), -// | Record.Build(_1="fields", _2="email,app_metadata,email_verified,user_id,last_login,last_ip,logins_count,created_at"), -// | Record.Build(_1="page",_2=String.From(page))) -// | ), -// | auth0_users_type -// | ), -// | getUserPage(page+1) -// | ), -// | filterByEmail = -// | if(Nullable.IsNull(email)) -// | then -// | payload -// | else -// | Collection.Filter(payload, p -> p.email==email), -// | filterStartDate = -// | Collection.Filter(filterByEmail, t -> start_date<=Date.FromTimestamp(Timestamp.Parse(t.created_at, "yyyy-M-d'T'H:m:s.SSS'Z'"))), -// | filterEndDate = -// | Collection.Filter(filterStartDate, t -> end_date>=Date.FromTimestamp(Timestamp.Parse(t.created_at, "yyyy-M-d'T'H:m:s.SSS'Z'"))), -// | filterLastLogin = -// | Collection.Filter(filterEndDate, t -> last_login_since<=Date.FromTimestamp(Timestamp.Parse(t.last_login, "yyyy-M-d'T'H:m:s.SSS'Z'"))), -// | filterOrg = -// | if(Nullable.IsNull(organization)) -// | then -// | filterLastLogin -// | else -// | Collection.Filter(filterLastLogin, t -> Collection.Contains(t.app_metadata.rawOrg, organization)), -// | output = filterOrg -// | in -// | output -// | -// | in -// | Collection.Transform(getUserPage(0), c -> Record.AddField(c, reg=Date.FromTimestamp(Timestamp.Parse(c.created_at, "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")))) -// | -// |getAuth0Users()""".stripMargin) // some random query -// -// val elapsed = System.currentTimeMillis() -// -// logger.info("\n++++++++++ Execution time: " + (elapsed - started)) -// println("\n++++++++++ Execution time: " + (elapsed - started)) -// } + test("Query over a tpch10 csv file") { _ => + assume(false, "This test is disabled by default") -// test("Json Writer range test") { _ => -// assume(shouldBeExecuted, "This test is disabled by default") + val prog = """let + | lineitemsType = type collection( + | record(l_orderkey: int, l_partkey: int, l_suppkey: int, l_linenumber: int, l_quantity: double) + | ), + | lineitems = Csv.Read("file:///home/ld/workspace/TPCH/10GB/customer.tbl", lineitemsType, delimiter = "|"), + | filtered = Collection.Filter(lineitems, (o) -> o.l_quantity > 40), + | transformed = Collection.Transform(filtered, (o) -> o.l_quantity / 2) + |in + | Collection.Sum(transformed)""".stripMargin + + val startedIn = System.currentTimeMillis() + fastExecute(prog) + val elapsedIn = System.currentTimeMillis() + logger.info("++++++++++ First run: " + (elapsedIn - startedIn)) + + val numberOfRuns = 10 + + val values = Array.fill(numberOfRuns)(0L) + + val lastIdx = numberOfRuns - 1 + + for (i <- 0 to lastIdx) { + val startedIn = System.currentTimeMillis() + fastExecute(prog) + val elapsedIn = System.currentTimeMillis() + values(i) = elapsedIn - startedIn + logger.info("++++++++++ Next run: " + values(i)) + } + + val mean = (values.sum) / numberOfRuns + + var standardDeviation = 0.0 + for (num <- values) { + standardDeviation += Math.pow(num - mean, 2) + } + + logger.info("++++++++++ Average execution time: " + mean) + logger.info("++++++++++ Standard deviation is: " + Math.sqrt(standardDeviation / numberOfRuns)) + } + + test("Range Count test") { _ => + assume(false, "This test is disabled by default") + + for (i <- 0 to 20) { + fastExecute( + """let + | range = 1000L + |in + | Collection.Count(Collection.Transform(Collection.Filter(Long.Range(0, range), (x) -> x % 2 == 0), (y) -> y + 1))""".stripMargin + ) + } + + val values = Array.fill(7)(0L) + + for (i <- 0 to 6) { + logger.info("++++++++++ 10^" + (i + 3)) + val startedIn = System.currentTimeMillis() + fastExecute( + s"""let + | range = ${Math.pow(10, i + 3).toLong}L + |in + | Collection.Count(Collection.Transform(Collection.Filter(Long.Range(0, range), (x) -> x % 2 == 0), (y) -> y + 1))""".stripMargin + ) + val elapsedIn = System.currentTimeMillis() + values(i) = elapsedIn - startedIn + } + logger.info("++++++++++ Values: " + values.mkString(", ")) + + // Execution with STD + +// val prog = """let +// | range = 100000000L +// |in +// | Collection.Count(Collection.Transform(Collection.Filter(Long.Range(0, range), (x) -> x % 2 == 0), (y) -> y + 1))""".stripMargin + +// val startedIn = System.currentTimeMillis() +// fastExecute(prog) +// val elapsedIn = System.currentTimeMillis() +// logger.info("++++++++++ First run: " + (elapsedIn - startedIn)) // +// val numberOfRuns = 20 // fastExecute("""let a = "hello" in a """) // some random query // fastExecute("""let a = 2 + 2 in a """) // some random query // fastExecute("""let a = 2/2 in a """) // some random query // -// //Warmup -// fastExecute( -// """Collection.Transform(Int.Range(0,100,step=1), x -> List.Build({a: x, b: Collection.Transform(Int.Range(0,100,step=1), x -> List.Build({a: x, b: "hello"} , {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}))} , {a: x, b: Collection.Transform(Int.Range(0,100,step=1), x -> List.Build({a: x, b: "hello"} , {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}))}, {a: x, b: Collection.Transform(Int.Range(0,100,step=1), x -> List.Build({a: x, b: "hello"} , {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}))}, {a: x, b: Collection.Transform(Int.Range(0,100,step=1), x -> List.Build({a: x, b: "hello"} , {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}))}, {a: x, b: Collection.Transform(Int.Range(0,100,step=1), x -> List.Build({a: x, b: "hello"} , {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}))}))""" -// ) -// -// val started = System.currentTimeMillis() -// for (i <- 0 to numberOfRuns) { -// fastExecute( -// """Collection.Transform(Int.Range(0,100,step=1), x -> List.Build({a: x, b: Collection.Transform(Int.Range(0,100,step=1), x -> List.Build({a: x, b: "hello"} , {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}))} , {a: x, b: Collection.Transform(Int.Range(0,100,step=1), x -> List.Build({a: x, b: "hello"} , {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}))}, {a: x, b: Collection.Transform(Int.Range(0,100,step=1), x -> List.Build({a: x, b: "hello"} , {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}))}, {a: x, b: Collection.Transform(Int.Range(0,100,step=1), x -> List.Build({a: x, b: "hello"} , {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}))}, {a: x, b: Collection.Transform(Int.Range(0,100,step=1), x -> List.Build({a: x, b: "hello"} , {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}, {a: x, b: "hello"}))}))""" -// ) -// } -// val elapsed = System.currentTimeMillis() -// -// logger.info("++++++++++ Average execution time time: " + ((elapsed - started) / numberOfRuns)) -// } -// -// test("Range Count test") { _ => -// assume(shouldBeExecuted, "This test is disabled by default") -// -// fastExecute("""let a = "hello" in a """) // some random query -// fastExecute("""let a = 2 + 2 in a """) // some random query -// fastExecute("""let a = 2/2 in a """) // some random query +// val values = Array.fill(numberOfRuns + 1)(0L) // -// //Warmup -// fastExecute(s"Collection.Count(Int.Range(0,${Int.MaxValue},step=1))") // val started = System.currentTimeMillis() // for (i <- 0 to numberOfRuns) { -// fastExecute(s"Collection.Count(Int.Range(0,${Int.MaxValue},step=1))") +// val startedIn = System.currentTimeMillis() +// fastExecute(prog) +// val elapsedIn = System.currentTimeMillis() +// values(i) = elapsedIn - startedIn // } // val elapsed = System.currentTimeMillis() // -// logger.info("++++++++++ Average execution time time: " + ((elapsed - started) / numberOfRuns)) -// } -// -// test("Filter Test") { _ => -// assume(shouldBeExecuted, "This test is disabled by default") -// -// fastExecute("""let a = "hello" in a """) // some random query -// fastExecute("""let a = 2 + 2 in a """) // some random query -// fastExecute("""let a = 2/2 in a """) // some random query +// val mean = (elapsed - started) / numberOfRuns // -// //Warmup -// fastExecute(s"Collection.Filter(Int.Range(0,${Int.MaxValue},step=1), x -> x > ${Int.MaxValue - 2})") -// val started = System.currentTimeMillis() -// for (i <- 0 to numberOfRuns) { -// fastExecute(s"Collection.Filter(Int.Range(0,${Int.MaxValue},step=1), x -> x > ${Int.MaxValue - 2})") +// var standardDeviation = 0.0 +// for (num <- values) { +// standardDeviation += Math.pow(num - mean, 2) // } -// val elapsed = System.currentTimeMillis() // -// logger.info("++++++++++ Average execution time time: " + ((elapsed - started) / numberOfRuns)) -// } - +// logger.info("++++++++++ Average execution time: " + mean) +// logger.info("++++++++++ Standard deviation is: " + Math.sqrt(standardDeviation / numberOfRuns)) + } } diff --git a/snapi-client/src/test/scala/raw/compiler/rql2/tests/builtin/collection/CollectionRangeTest.scala b/snapi-client/src/test/scala/raw/compiler/rql2/tests/builtin/collection/CollectionRangeTest.scala index fc201ea80..53c2512db 100644 --- a/snapi-client/src/test/scala/raw/compiler/rql2/tests/builtin/collection/CollectionRangeTest.scala +++ b/snapi-client/src/test/scala/raw/compiler/rql2/tests/builtin/collection/CollectionRangeTest.scala @@ -21,6 +21,10 @@ trait CollectionRangeTest extends CompilerTestContext { test("""Long.Range(0, 10)""")(_ should evaluateTo("[0L,1L,2L,3L,4L,5L,6L,7L,8L,9L]")) test("""Long.Range(0, 1)""")(_ should evaluateTo("[0L]")) + test("""Collection.Filter(Long.Range(0, 1000000), x -> x == 999999)""")( + _ should evaluateTo("Collection.Build(999999L)") + ) + // end = start test("""Long.Range(0, 0)""")(_ should evaluateTo("[]")) test("""Long.Range(12, 12)""")(_ should evaluateTo("[]")) diff --git a/snapi-client/src/test/scala/raw/compiler/rql2/truffle/Rql2TruffleCompilerServiceTestContext.scala b/snapi-client/src/test/scala/raw/compiler/rql2/truffle/Rql2TruffleCompilerServiceTestContext.scala index f74e569f5..a79921ebb 100644 --- a/snapi-client/src/test/scala/raw/compiler/rql2/truffle/Rql2TruffleCompilerServiceTestContext.scala +++ b/snapi-client/src/test/scala/raw/compiler/rql2/truffle/Rql2TruffleCompilerServiceTestContext.scala @@ -30,6 +30,44 @@ trait Rql2TruffleCompilerServiceTestContext extends Rql2CompilerServiceTestConte // Create an isolated Truffle Engine val options = new java.util.HashMap[String, String]() options.put("rql.settings", settings.renderAsString) +// //diagnostics +// options.put("engine.CompilationStatistics", "true") +// // options.put("engine.CompilationStatisticDetails", "true") +// // options.put("compiler.InstrumentBoundaries", "true") +// options.put("engine.CompilationFailureAction", "Diagnose") +// options.put("engine.TracePerformanceWarnings", "all") +// options.put("engine.TraceCompilation", "true") +// options.put("engine.TraceSplitting", "true") +// options.put("engine.TraceDeoptimizeFrame", "true") +// options.put("engine.TraceTransferToInterpreter", "true") +// options.put("engine.TraceCompilationPolymorphism", "true") +// options.put("engine.TraceSplittingSummary", "true") +// // options.put("engine.TraceCompilationDetails", "true") +//// options.put("engine.CompileImmediately", "true") +// options.put("engine.BackgroundCompilation", "false") + // options.put("engine.SpecializationStatistics", "false") +// options.put("engine.OSR", "false") + +// // optimizations +// options.put("compiler.InlineAcrossTruffleBoundary", "true") +// options.put("engine.CompilerThreads", "24") +// options.put("engine.FirstTierCompilationThreshold", "100") +// options.put("engine.FirstTierMinInvokeThreshold", "5") +// options.put("engine.MinInvokeThreshold", "10") +// options.put("engine.Mode", "throughput") +// options.put("engine.MultiTier", "false") +// options.put("engine.OSR", "false") +// options.put("engine.PartialBlockCompilation", "false") +// options.put("engine.PartialBlockCompilationSize", "5000") +// options.put("engine.PartialBlockMaximumSize", "15000") +// options.put("engine.SingleTierCompilationThreshold", "500") +// options.put("engine.Splitting", "false") +// options.put("compiler.FirstTierUseEconomy", "false") +// options.put("compiler.InliningExpansionBudget", "20000") + // options.put("compiler.InliningInliningBudget", "20000") + // options.put("compiler.InliningRecursionDepth", "10") +// options.put("engine.IsolateMemoryProtection", "false") + engine = Engine .newBuilder() .allowExperimentalOptions(true) diff --git a/snapi-truffle/src/main/java/module-info.java b/snapi-truffle/src/main/java/module-info.java index 73a1890f3..0481d37a6 100644 --- a/snapi-truffle/src/main/java/module-info.java +++ b/snapi-truffle/src/main/java/module-info.java @@ -303,8 +303,6 @@ exports raw.runtime.truffle; exports raw.runtime.truffle.boundary; - exports raw.runtime.truffle.runtime.aggregation; - exports raw.runtime.truffle.runtime.aggregation.aggregator; exports raw.runtime.truffle.runtime.record; exports raw.runtime.truffle.runtime.operators; exports raw.runtime.truffle.runtime.function; @@ -314,6 +312,7 @@ exports raw.runtime.truffle.runtime.exceptions.csv; exports raw.runtime.truffle.runtime.exceptions.binary; exports raw.runtime.truffle.runtime.exceptions.rdbms; + exports raw.runtime.truffle.runtime.data_structures.treemap; exports raw.runtime.truffle.runtime.primitives; exports raw.runtime.truffle.runtime.list; exports raw.runtime.truffle.runtime.or; @@ -342,6 +341,7 @@ exports raw.runtime.truffle.runtime.iterable.sources; exports raw.runtime.truffle.runtime.kryo; exports raw.runtime.truffle.utils; + exports raw.runtime.truffle.tryable_nullable; exports raw.runtime.truffle.ast; exports raw.runtime.truffle.ast.io.kryo; exports raw.runtime.truffle.ast.io.xml.parser; @@ -357,6 +357,7 @@ exports raw.runtime.truffle.ast.io.binary; exports raw.runtime.truffle.ast.local; exports raw.runtime.truffle.ast.expressions.unary; + exports raw.runtime.truffle.ast.expressions.iterable; exports raw.runtime.truffle.ast.expressions.iterable.collection; exports raw.runtime.truffle.ast.expressions.iterable.list; exports raw.runtime.truffle.ast.expressions.record; @@ -387,7 +388,11 @@ exports raw.runtime.truffle.ast.expressions.builtin.string_package; exports raw.runtime.truffle.ast.expressions.builtin.location_package; exports raw.runtime.truffle.ast.expressions.builtin.binary_package; + exports raw.runtime.truffle.ast.expressions.aggregation; exports raw.runtime.truffle.ast.controlflow; + exports raw.runtime.truffle.ast.osr; + exports raw.runtime.truffle.ast.osr.bodies; + exports raw.runtime.truffle.ast.osr.conditions; exports raw.runtime.truffle.runtime.exceptions.validation; exports raw.compiler.snapi.truffle.compiler; exports raw.compiler.rql2output.truffle.builtin; diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/TruffleEmitter.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/TruffleEmitter.java index 2f3f43cc9..bb9ce7a36 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/TruffleEmitter.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/TruffleEmitter.java @@ -30,7 +30,9 @@ public abstract class TruffleEmitter { public abstract ClosureNode recurseLambda(TruffleBuildBody truffleBuildBody); - protected abstract RawLanguage getLanguage(); + public abstract FrameDescriptor.Builder getFrameDescriptorBuilder(); + + public abstract RawLanguage getLanguage(); protected abstract StatementNode emitMethod(Rql2Method m); } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/TruffleEntryExtension.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/TruffleEntryExtension.java index e46e1337d..a11ddb46b 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/TruffleEntryExtension.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/TruffleEntryExtension.java @@ -25,16 +25,15 @@ default ExpressionNode toTruffle(Type type, List args, RawLanguage r } default ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { - return toTruffle( - type, - args.stream() - .map( - a -> - new TruffleArg( - emitter.recurseExp(a.e()), - a.t(), - a.idn().isDefined() ? a.idn().get() : null)) - .collect(Collectors.toList()), - emitter.getLanguage()); + return toTruffle(type, rql2argsToTruffleArgs(args, emitter), emitter.getLanguage()); + } + + default List rql2argsToTruffleArgs(List args, TruffleEmitter emitter) { + return args.stream() + .map( + a -> + new TruffleArg( + emitter.recurseExp(a.e()), a.t(), a.idn().isDefined() ? a.idn().get() : null)) + .collect(Collectors.toList()); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleCountCollectionEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleCountCollectionEntry.java index f2f4e6608..394a1640b 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleCountCollectionEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleCountCollectionEntry.java @@ -12,19 +12,30 @@ package raw.compiler.snapi.truffle.builtin.collection_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.CountCollectionEntry; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionCountNodeGen; +import raw.runtime.truffle.ast.expressions.aggregation.AggregateSingleNode; +import raw.runtime.truffle.ast.expressions.aggregation.Aggregations; public class TruffleCountCollectionEntry extends CountCollectionEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { - return CollectionCountNodeGen.create(args.get(0).exprNode()); + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int resultSlot = + builder.addSlot(FrameSlotKind.Object, "result", "a slot to store the result of osr"); + return new AggregateSingleNode( + truffleArgs.get(0).exprNode(), Aggregations.COUNT, generatorSlot, resultSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleDistinctCollectionEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleDistinctCollectionEntry.java index af72b4760..72294bb75 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleDistinctCollectionEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleDistinctCollectionEntry.java @@ -12,22 +12,38 @@ package raw.compiler.snapi.truffle.builtin.collection_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.DistinctCollectionEntry; import raw.compiler.rql2.source.Rql2IterableType; import raw.compiler.rql2.source.Rql2TypeWithProperties; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionDistinctNodeGen; public class TruffleDistinctCollectionEntry extends DistinctCollectionEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + + int offHeapDistinctSlot = + builder.addSlot( + FrameSlotKind.Object, "offHeapDistinct", "a slot to store the offHeapDistinct of osr"); + return CollectionDistinctNodeGen.create( - args.get(0).exprNode(), (Rql2TypeWithProperties) ((Rql2IterableType) type).innerType()); + truffleArgs.get(0).exprNode(), + (Rql2TypeWithProperties) ((Rql2IterableType) type).innerType(), + generatorSlot, + offHeapDistinctSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleExistsCollectionEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleExistsCollectionEntry.java index 1961dc154..5cf9c6658 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleExistsCollectionEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleExistsCollectionEntry.java @@ -12,22 +12,38 @@ package raw.compiler.snapi.truffle.builtin.collection_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.ExistsCollectionEntry; -import raw.compiler.rql2.source.FunType; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionExistsNodeGen; +import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionExistsNode; public class TruffleExistsCollectionEntry extends ExistsCollectionEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { - FunType funType = (FunType) args.get(1).type(); - - return CollectionExistsNodeGen.create(args.get(0).exprNode(), args.get(1).exprNode()); + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int functionSlot = + builder.addSlot(FrameSlotKind.Object, "function", "a slot to store the function of osr"); + int predicateResultSlot = + builder.addSlot( + FrameSlotKind.Boolean, + "predicateResult", + "a slot to store the result of applying the function"); + return new CollectionExistsNode( + truffleArgs.get(0).exprNode(), + truffleArgs.get(1).exprNode(), + generatorSlot, + functionSlot, + predicateResultSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleFilterCollectionEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleFilterCollectionEntry.java index b7df47632..f11d26c0c 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleFilterCollectionEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleFilterCollectionEntry.java @@ -12,19 +12,37 @@ package raw.compiler.snapi.truffle.builtin.collection_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.FilterCollectionEntry; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionFilterNodeGen; +import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionFilterNode; public class TruffleFilterCollectionEntry extends FilterCollectionEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { - return CollectionFilterNodeGen.create(args.get(0).exprNode(), args.get(1).exprNode()); + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + int collectionSlot = + builder.addSlot( + FrameSlotKind.Object, "collection", "a slot to store the collection of osr"); + int predicateSlot = + builder.addSlot(FrameSlotKind.Object, "predicate", "a slot to store the predicate of osr"); + int resultSlot = + builder.addSlot(FrameSlotKind.Object, "result", "a slot to store the result of osr"); + + return new CollectionFilterNode( + truffleArgs.get(0).exprNode(), + truffleArgs.get(1).exprNode(), + collectionSlot, + predicateSlot, + resultSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleGroupCollectionEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleGroupCollectionEntry.java index fe3140f51..b03cdc633 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleGroupCollectionEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleGroupCollectionEntry.java @@ -12,15 +12,18 @@ package raw.compiler.snapi.truffle.builtin.collection_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.Arrays; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.GroupCollectionEntry; import raw.compiler.rql2.source.*; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionGroupByNodeGen; import scala.collection.JavaConverters; import scala.collection.immutable.HashSet; @@ -28,7 +31,15 @@ public class TruffleGroupCollectionEntry extends GroupCollectionEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int functionSlot = + builder.addSlot(FrameSlotKind.Object, "function", "a slot to store the function of osr"); + int mapSlot = builder.addSlot(FrameSlotKind.Object, "map", "a slot to store the map of osr"); Rql2IterableType iterable = (Rql2IterableType) type; Rql2RecordType record = (Rql2RecordType) iterable.innerType(); @@ -56,6 +67,12 @@ public ExpressionNode toTruffle(Type type, List args, RawLanguage ra Rql2TypeWithProperties valueType = (Rql2TypeWithProperties) iterableValueType.innerType(); return CollectionGroupByNodeGen.create( - args.get(0).exprNode(), args.get(1).exprNode(), keyType, valueType); + truffleArgs.get(0).exprNode(), + truffleArgs.get(1).exprNode(), + keyType, + valueType, + generatorSlot, + functionSlot, + mapSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleInternalEquiJoinCollectionEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleInternalEquiJoinCollectionEntry.java index 3fda0c815..d971de3f2 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleInternalEquiJoinCollectionEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleInternalEquiJoinCollectionEntry.java @@ -12,27 +12,45 @@ package raw.compiler.snapi.truffle.builtin.collection_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.InternalEquiJoinCollectionEntry; import raw.compiler.rql2.source.FunType; import raw.compiler.rql2.source.Rql2IterableType; import raw.compiler.rql2.source.Rql2TypeWithProperties; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionEquiJoinNode; public class TruffleInternalEquiJoinCollectionEntry extends InternalEquiJoinCollectionEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { - TruffleArg left = args.get(0); - TruffleArg right = args.get(1); - TruffleArg leftK = args.get(2); - TruffleArg rightK = args.get(3); - TruffleArg remap = args.get(4); + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + int computeNextSlot = + builder.addSlot( + FrameSlotKind.Object, "computeNext", "a slot to store the computeNext of osr"); + int shouldContinueSlot = + builder.addSlot( + FrameSlotKind.Boolean, "shouldContinue", "a slot to store the shouldContinue of osr"); + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int keyFunctionSlot = + builder.addSlot( + FrameSlotKind.Object, "keyFunction", "a slot to store the keyFunction of osr"); + int mapSlot = builder.addSlot(FrameSlotKind.Object, "map", "a slot to store the map of osr"); + + TruffleArg left = truffleArgs.get(0); + TruffleArg right = truffleArgs.get(1); + TruffleArg leftK = truffleArgs.get(2); + TruffleArg rightK = truffleArgs.get(3); + TruffleArg remap = truffleArgs.get(4); FunType funType = (FunType) leftK.type(); Rql2IterableType leftValue = (Rql2IterableType) left.type(); @@ -46,6 +64,11 @@ public ExpressionNode toTruffle(Type type, List args, RawLanguage ra (Rql2TypeWithProperties) funType.r(), (Rql2TypeWithProperties) leftValue.innerType(), (Rql2TypeWithProperties) rightValue.innerType(), - remap.exprNode()); + remap.exprNode(), + computeNextSlot, + shouldContinueSlot, + generatorSlot, + keyFunctionSlot, + mapSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleInternalJoinCollectionEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleInternalJoinCollectionEntry.java index 84101ac38..feb672ff1 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleInternalJoinCollectionEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleInternalJoinCollectionEntry.java @@ -12,26 +12,46 @@ package raw.compiler.snapi.truffle.builtin.collection_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.InternalJoinCollectionEntry; import raw.compiler.rql2.source.FunType; import raw.compiler.rql2.source.Rql2IterableType; import raw.compiler.rql2.source.Rql2TypeWithProperties; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionJoinNodeGen; public class TruffleInternalJoinCollectionEntry extends InternalJoinCollectionEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { - TruffleArg left = args.get(0); - TruffleArg right = args.get(1); - TruffleArg reshape = args.get(2); - TruffleArg predicate = args.get(3); + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + + int computeNextSlot = + builder.addSlot( + FrameSlotKind.Object, "computeNext", "a slot to store the computeNext of osr"); + int shouldContinueSlot = + builder.addSlot( + FrameSlotKind.Boolean, "shouldContinue", "a slot to store the shouldContinue of osr"); + int resultSlot = + builder.addSlot(FrameSlotKind.Object, "result", "a slot to store the result of osr"); + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int outputBufferSlot = + builder.addSlot( + FrameSlotKind.Object, "outputBuffer", "a slot to store the outputBuffer of osr"); + + TruffleArg left = truffleArgs.get(0); + TruffleArg right = truffleArgs.get(1); + TruffleArg reshape = truffleArgs.get(2); + TruffleArg predicate = truffleArgs.get(3); Rql2IterableType rql2IterableType = (Rql2IterableType) right.type(); Rql2TypeWithProperties rightType = (Rql2TypeWithProperties) rql2IterableType.innerType(); boolean reshapeBeforePredicate = ((FunType) predicate.type()).ms().size() == 1; @@ -41,6 +61,11 @@ public ExpressionNode toTruffle(Type type, List args, RawLanguage ra reshape.exprNode(), predicate.exprNode(), rightType, - reshapeBeforePredicate); + reshapeBeforePredicate, + computeNextSlot, + shouldContinueSlot, + resultSlot, + generatorSlot, + outputBufferSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleLastCollectionEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleLastCollectionEntry.java index 844a2103e..ec7a6130f 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleLastCollectionEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleLastCollectionEntry.java @@ -12,19 +12,30 @@ package raw.compiler.snapi.truffle.builtin.collection_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.LastCollectionEntry; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionLastNodeGen; +import raw.runtime.truffle.ast.expressions.aggregation.AggregateSingleNode; +import raw.runtime.truffle.ast.expressions.aggregation.Aggregations; public class TruffleLastCollectionEntry extends LastCollectionEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { - return CollectionLastNodeGen.create(args.get(0).exprNode()); + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int resultSlot = + builder.addSlot(FrameSlotKind.Object, "result", "a slot to store the result of osr"); + return new AggregateSingleNode( + truffleArgs.get(0).exprNode(), Aggregations.LAST, generatorSlot, resultSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleMaxCollectionEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleMaxCollectionEntry.java index 572ae8abc..73e4a9831 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleMaxCollectionEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleMaxCollectionEntry.java @@ -12,18 +12,29 @@ package raw.compiler.snapi.truffle.builtin.collection_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.MaxCollectionEntry; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionMaxNodeGen; +import raw.runtime.truffle.ast.expressions.aggregation.AggregateSingleNode; +import raw.runtime.truffle.ast.expressions.aggregation.Aggregations; public class TruffleMaxCollectionEntry extends MaxCollectionEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { - return CollectionMaxNodeGen.create(args.get(0).exprNode()); + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int resultSlot = + builder.addSlot(FrameSlotKind.Object, "result", "a slot to store the result of osr"); + return new AggregateSingleNode( + truffleArgs.get(0).exprNode(), Aggregations.MAX, generatorSlot, resultSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleMinCollectionEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleMinCollectionEntry.java index 54ddcd64e..89376aab7 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleMinCollectionEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleMinCollectionEntry.java @@ -12,18 +12,29 @@ package raw.compiler.snapi.truffle.builtin.collection_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.MinCollectionEntry; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionMinNodeGen; +import raw.runtime.truffle.ast.expressions.aggregation.AggregateSingleNode; +import raw.runtime.truffle.ast.expressions.aggregation.Aggregations; public class TruffleMinCollectionEntry extends MinCollectionEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { - return CollectionMinNodeGen.create(args.get(0).exprNode()); + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int resultSlot = + builder.addSlot(FrameSlotKind.Object, "result", "a slot to store the result of osr"); + return new AggregateSingleNode( + truffleArgs.get(0).exprNode(), Aggregations.MIN, generatorSlot, resultSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleMkStringCollectionEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleMkStringCollectionEntry.java index c6572542a..b3a851189 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleMkStringCollectionEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleMkStringCollectionEntry.java @@ -12,41 +12,54 @@ package raw.compiler.snapi.truffle.builtin.collection_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.MkStringCollectionEntry; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionMkStringNodeGen; +import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionMkStringNode; import raw.runtime.truffle.ast.expressions.literals.StringNode; public class TruffleMkStringCollectionEntry extends MkStringCollectionEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int sepSlot = + builder.addSlot(FrameSlotKind.Object, "separator", "a slot to store the separator of osr"); + int resultSlot = + builder.addSlot(FrameSlotKind.Boolean, "result", "a slot to store the result of osr"); + ExpressionNode start = - args.stream() + truffleArgs.stream() .filter(a -> a.identifier() != null && a.identifier().contains("start")) .map(TruffleArg::exprNode) .findFirst() .orElse(new StringNode("")); ExpressionNode sep = - args.stream() + truffleArgs.stream() .filter(a -> a.identifier() != null && a.identifier().contains("sep")) .map(TruffleArg::exprNode) .findFirst() .orElse(new StringNode("")); ExpressionNode end = - args.stream() + truffleArgs.stream() .filter(a -> a.identifier() != null && a.identifier().contains("end")) .map(TruffleArg::exprNode) .findFirst() .orElse(new StringNode("")); - return CollectionMkStringNodeGen.create(args.get(0).exprNode(), start, sep, end); + return new CollectionMkStringNode( + truffleArgs.get(0).exprNode(), start, sep, end, generatorSlot, sepSlot, resultSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleOrderByCollectionEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleOrderByCollectionEntry.java index e09fb5199..a2014d271 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleOrderByCollectionEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleOrderByCollectionEntry.java @@ -12,55 +12,79 @@ package raw.compiler.snapi.truffle.builtin.collection_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.OrderByCollectionEntry; import raw.compiler.rql2.source.FunType; import raw.compiler.rql2.source.Rql2IterableType; import raw.compiler.rql2.source.Rql2TypeWithProperties; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionOrderByNode; public class TruffleOrderByCollectionEntry extends OrderByCollectionEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int collectionSlot = + builder.addSlot( + FrameSlotKind.Object, "collection", "a slot to store the collection of osr"); + int offHeapGroupByKeysSlot = + builder.addSlot( + FrameSlotKind.Object, + "offHeapGroupByKeys", + "a slot to store the offHeapGroupByKeys of osr"); + AtomicInteger index = new AtomicInteger(); index.set(0); ExpressionNode[] keyFunctions = - args.stream() + truffleArgs.stream() .skip(1) .map(a -> index.getAndIncrement()) .filter(a -> a % 2 == 0) - .map(a -> args.get(a + 1).exprNode()) + .map(a -> truffleArgs.get(a + 1).exprNode()) .toArray(ExpressionNode[]::new); index.set(0); Rql2TypeWithProperties[] keyTypes = - args.stream() + truffleArgs.stream() .skip(1) .map(a -> index.getAndIncrement()) .filter(a -> a % 2 == 0) - .map(a -> (Rql2TypeWithProperties) ((FunType) args.get(a + 1).type()).r()) + .map(a -> (Rql2TypeWithProperties) ((FunType) truffleArgs.get(a + 1).type()).r()) .toArray(Rql2TypeWithProperties[]::new); index.set(0); ExpressionNode[] orderings = - args.stream() + truffleArgs.stream() .skip(1) .map(a -> index.getAndIncrement()) .filter(a -> a % 2 == 1) - .map(a -> args.get(a + 1).exprNode()) + .map(a -> truffleArgs.get(a + 1).exprNode()) .toArray(ExpressionNode[]::new); Rql2TypeWithProperties valueType = - (Rql2TypeWithProperties) ((Rql2IterableType) args.get(0).type()).innerType(); + (Rql2TypeWithProperties) ((Rql2IterableType) truffleArgs.get(0).type()).innerType(); return new CollectionOrderByNode( - args.get(0).exprNode(), keyFunctions, orderings, keyTypes, valueType); + truffleArgs.get(0).exprNode(), + keyFunctions, + orderings, + keyTypes, + valueType, + generatorSlot, + collectionSlot, + offHeapGroupByKeysSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleSumCollectionEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleSumCollectionEntry.java index 7c09c2f38..84c3e3374 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleSumCollectionEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleSumCollectionEntry.java @@ -12,18 +12,29 @@ package raw.compiler.snapi.truffle.builtin.collection_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.SumCollectionEntry; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionSumNodeGen; +import raw.runtime.truffle.ast.expressions.aggregation.AggregateSingleNode; +import raw.runtime.truffle.ast.expressions.aggregation.Aggregations; public class TruffleSumCollectionEntry extends SumCollectionEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { - return CollectionSumNodeGen.create(args.get(0).exprNode()); + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int resultSlot = + builder.addSlot(FrameSlotKind.Object, "result", "a slot to store the result of osr"); + return new AggregateSingleNode( + truffleArgs.get(0).exprNode(), Aggregations.SUM, generatorSlot, resultSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleTupleAvgCollectionEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleTupleAvgCollectionEntry.java index 57504d460..5b59fcaa5 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleTupleAvgCollectionEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/collection_extension/TruffleTupleAvgCollectionEntry.java @@ -12,19 +12,28 @@ package raw.compiler.snapi.truffle.builtin.collection_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.TupleAvgCollectionEntry; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionTupleAvgNodeGen; +import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionTupleAvgNode; public class TruffleTupleAvgCollectionEntry extends TupleAvgCollectionEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { - return CollectionTupleAvgNodeGen.create(args.get(0).exprNode()); + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int resultSlot = + builder.addSlot(FrameSlotKind.Object, "result", "a slot to store the result of osr"); + return new CollectionTupleAvgNode(truffleArgs.get(0).exprNode(), generatorSlot, resultSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/json_extension/JsonParser.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/json_extension/JsonParser.java index 2ffb0dc22..20fc4dd83 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/json_extension/JsonParser.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/json_extension/JsonParser.java @@ -13,6 +13,7 @@ package raw.compiler.snapi.truffle.builtin.json_extension; import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import raw.compiler.rql2.source.*; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.RawLanguage; @@ -27,7 +28,6 @@ import raw.runtime.truffle.ast.io.json.reader.parser.FloatParseJsonNodeGen; import raw.runtime.truffle.ast.io.json.reader.parser.IntParseJsonNodeGen; import raw.runtime.truffle.ast.io.json.reader.parser.IntervalParseJsonNodeGen; -import raw.runtime.truffle.ast.io.json.reader.parser.ListParseJsonNodeGen; import raw.runtime.truffle.ast.io.json.reader.parser.LongParseJsonNodeGen; import raw.runtime.truffle.ast.io.json.reader.parser.ShortParseJsonNodeGen; import raw.runtime.truffle.ast.io.json.reader.parser.StringParseJsonNodeGen; @@ -37,6 +37,7 @@ import scala.collection.JavaConverters; import java.util.LinkedHashMap; +import java.util.List; import static raw.compiler.snapi.truffle.builtin.CompilerScalaConsts.*; @@ -57,7 +58,21 @@ public ProgramExpressionNode recurse(Rql2TypeWithProperties tipe, RawLanguage la } private ProgramExpressionNode recurse(Rql2TypeWithProperties tipe, boolean appendNullCheck, RawLanguage lang) { - return program(switch (tipe){ + FrameDescriptor.Builder builder = FrameDescriptor.newBuilder(); + int parserSlot = + builder.addSlot( + FrameSlotKind.Object, "parser", "a slot to store the parser of osr"); + int llistSlot = + builder.addSlot( + FrameSlotKind.Object, "list", "a slot to store the ArrayList of osr"); + int currentIdxSlot = + builder.addSlot(FrameSlotKind.Int, "currentIdxSlot", "a slot to store the current index of osr"); + int listSizeSlot = + builder.addSlot( + FrameSlotKind.Int, "listSize", "a slot to store the size of the list for osr"); + int resultSlot = + builder.addSlot(FrameSlotKind.Object, "list", "a slot to store the result internal array for osr"); + ExpressionNode e = switch (tipe){ case Rql2TypeWithProperties nt when nt.props().contains(tryable) -> { Rql2TypeWithProperties nextType = (Rql2TypeWithProperties) nt.cloneAndRemoveProp(tryable); ProgramExpressionNode child = recurse(nextType, !(nt instanceof Rql2UndefinedType), lang); @@ -70,15 +85,25 @@ private ProgramExpressionNode recurse(Rql2TypeWithProperties tipe, boolean appen } case Rql2TypeWithProperties v when v.props().isEmpty() -> { ExpressionNode result = switch (v){ - case Rql2ListType r ->{ + case Rql2ListType r -> { ProgramExpressionNode child = recurse((Rql2TypeWithProperties)r.innerType(), lang); - yield ListParseJsonNodeGen.create( - (Rql2TypeWithProperties)r.innerType(), child.getCallTarget() - ); + yield new ListParseJsonNode( + (Rql2TypeWithProperties)r.innerType(), + child.getCallTarget(), + parserSlot, + llistSlot, + currentIdxSlot, + listSizeSlot, + resultSlot); } case Rql2IterableType r ->{ ProgramExpressionNode child = recurse((Rql2TypeWithProperties)r.innerType(), lang); - yield new IterableParseJsonNode(program(ListParseJsonNodeGen.create((Rql2TypeWithProperties)r.innerType(), child.getCallTarget()),lang)); + yield new IterableParseJsonNode( + program(new ListParseJsonNode( + (Rql2TypeWithProperties)r.innerType(), + child.getCallTarget(), + parserSlot, llistSlot, currentIdxSlot, listSizeSlot, resultSlot), + builder.build(), lang)); } case Rql2RecordType r ->{ LinkedHashMap hashMap = new LinkedHashMap<>(); @@ -88,10 +113,13 @@ private ProgramExpressionNode recurse(Rql2TypeWithProperties tipe, boolean appen .map(att -> recurse((Rql2TypeWithProperties) att.tipe(),lang)) .toArray(ProgramExpressionNode[]::new); JavaConverters.asJavaCollection(r.atts()).stream().map(a -> (Rql2AttrType) a).forEach(a -> hashMap.put(a.idn(),hashMap.size())); + List keys = JavaConverters.asJavaCollection(r.atts()).stream().map(a -> (Rql2AttrType) a).map(Rql2AttrType::idn).toList(); + boolean hasDuplicateKeys = keys.size() != keys.stream().distinct().count(); yield new RecordParseJsonNode( children, hashMap, - JavaConverters.asJavaCollection(r.atts()).stream().map(a -> (Rql2AttrType) a).map(a -> (Rql2TypeWithProperties) a.tipe()).toArray(Rql2TypeWithProperties[]::new) + JavaConverters.asJavaCollection(r.atts()).stream().map(a -> (Rql2AttrType) a).map(a -> (Rql2TypeWithProperties) a.tipe()).toArray(Rql2TypeWithProperties[]::new), + hasDuplicateKeys ); } case Rql2ByteType ignored -> ByteParseJsonNodeGen.create(); @@ -118,15 +146,17 @@ yield new RecordParseJsonNode( case Rql2UndefinedType ignored -> new UndefinedParseJsonNode(); default -> throw new RawTruffleInternalErrorException(); }; - if (appendNullCheck) yield new CheckNonNullJsonNode(program(result,lang)); + if (appendNullCheck) { + yield new CheckNonNullJsonNode(program(result, builder.build(), lang)); + } else yield result; } default -> throw new RawTruffleInternalErrorException(); - }, lang); + }; + return program(e, builder.build(), lang); } - private ProgramExpressionNode program(ExpressionNode e, RawLanguage lang){ - FrameDescriptor frameDescriptor = new FrameDescriptor(); + private ProgramExpressionNode program(ExpressionNode e, FrameDescriptor frameDescriptor, RawLanguage lang){ return new ProgramExpressionNode(lang, frameDescriptor, e); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleExistsListEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleExistsListEntry.java index ab38ea412..ad8edf460 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleExistsListEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleExistsListEntry.java @@ -12,18 +12,37 @@ package raw.compiler.snapi.truffle.builtin.list_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.ExistsListEntry; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.list.ListExistsNodeGen; +import raw.runtime.truffle.ast.expressions.iterable.list.ListExistsNode; public class TruffleExistsListEntry extends ExistsListEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { - return ListExistsNodeGen.create(args.get(0).exprNode(), args.get(1).exprNode()); + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int functionSlot = + builder.addSlot(FrameSlotKind.Object, "function", "a slot to store the function of osr"); + int predicateResultSlot = + builder.addSlot( + FrameSlotKind.Boolean, + "predicateResult", + "a slot to store the result of applying the function"); + return new ListExistsNode( + truffleArgs.get(0).exprNode(), + truffleArgs.get(1).exprNode(), + generatorSlot, + functionSlot, + predicateResultSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleFilterListEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleFilterListEntry.java index 3fab5d791..93be6ea02 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleFilterListEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleFilterListEntry.java @@ -12,18 +12,50 @@ package raw.compiler.snapi.truffle.builtin.list_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.FilterListEntry; +import raw.compiler.rql2.source.Rql2ListType; +import raw.compiler.rql2.source.Rql2Type; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.list.ListFilterNodeGen; +import raw.runtime.truffle.ast.expressions.iterable.list.ListFilterNode; public class TruffleFilterListEntry extends FilterListEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { - return ListFilterNodeGen.create(args.get(0).exprNode(), args.get(1).exprNode()); + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + Rql2ListType listType = (Rql2ListType) type; + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int functionSlot = + builder.addSlot(FrameSlotKind.Object, "function", "a slot to store the function of osr"); + int listSlot = + builder.addSlot(FrameSlotKind.Object, "filterList", "a slot to store the ArrayList of osr"); + int currentIdxSlot = + builder.addSlot( + FrameSlotKind.Int, "currentIdxSlot", "a slot to store the current index of osr"); + int listSizeSlot = + builder.addSlot( + FrameSlotKind.Int, "listSize", "a slot to store the size of the list for osr"); + int resultSlot = + builder.addSlot( + FrameSlotKind.Object, "result", "a slot to store the result internal array for osr"); + return new ListFilterNode( + truffleArgs.get(0).exprNode(), + truffleArgs.get(1).exprNode(), + (Rql2Type) listType.innerType(), + generatorSlot, + functionSlot, + listSlot, + currentIdxSlot, + listSizeSlot, + resultSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleFromListEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleFromListEntry.java index 2171cc6b9..7a66853b2 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleFromListEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleFromListEntry.java @@ -12,21 +12,45 @@ package raw.compiler.snapi.truffle.builtin.list_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.FromListEntry; import raw.compiler.rql2.source.Rql2ListType; import raw.compiler.rql2.source.Rql2Type; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.list.ListFromNodeGen; +import raw.runtime.truffle.ast.expressions.iterable.list.ListFromNode; public class TruffleFromListEntry extends FromListEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { Rql2ListType rql2ListType = (Rql2ListType) type; - return ListFromNodeGen.create(args.get(0).exprNode(), (Rql2Type) rql2ListType.innerType()); + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int listSlot = + builder.addSlot(FrameSlotKind.Object, "filterList", "a slot to store the ArrayList of osr"); + int currentIdxSlot = + builder.addSlot( + FrameSlotKind.Int, "currentIdxSlot", "a slot to store the current index of osr"); + int listSizeSlot = + builder.addSlot( + FrameSlotKind.Int, "listSize", "a slot to store the size of the list of osr"); + int resultSlot = + builder.addSlot(FrameSlotKind.Object, "list", "a slot to store the result array of osr"); + return new ListFromNode( + truffleArgs.get(0).exprNode(), + (Rql2Type) rql2ListType.innerType(), + generatorSlot, + listSlot, + currentIdxSlot, + listSizeSlot, + resultSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleGroupListEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleGroupListEntry.java index 77835eb03..62080aab0 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleGroupListEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleGroupListEntry.java @@ -12,22 +12,28 @@ package raw.compiler.snapi.truffle.builtin.list_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.Arrays; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.GroupListEntry; import raw.compiler.rql2.source.*; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.list.ListGroupByNodeGen; +import raw.runtime.truffle.ast.expressions.iterable.list.ListGroupByNode; import scala.collection.JavaConverters; import scala.collection.immutable.HashSet; public class TruffleGroupListEntry extends GroupListEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + Rql2ListType listType = (Rql2ListType) type; Rql2RecordType record = (Rql2RecordType) listType.innerType(); Rql2AttrType[] atts = @@ -48,10 +54,26 @@ public ExpressionNode toTruffle(Type type, List args, RawLanguage ra .findFirst() .orElse(Rql2AttrType.apply("key", new Rql2UndefinedType(new HashSet<>()))) .tipe(); - return ListGroupByNodeGen.create( - args.get(0).exprNode(), - args.get(1).exprNode(), + + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int keyFuncSlot = + builder.addSlot( + FrameSlotKind.Object, "keyFunction", "a slot to store the key function of osr"); + int mapSlot = + builder.addSlot(FrameSlotKind.Object, "mapSlot", "a slot to store the map of osr"); + int listSlot = + builder.addSlot(FrameSlotKind.Object, "listSize", "a slot to store the list of osr"); + + return new ListGroupByNode( + truffleArgs.get(0).exprNode(), + truffleArgs.get(1).exprNode(), + (Rql2TypeWithProperties) groupType.innerType(), keyType, - (Rql2TypeWithProperties) groupType.innerType()); + generatorSlot, + keyFuncSlot, + mapSlot, + listSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleMaxListEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleMaxListEntry.java index a0207c2bb..59492358c 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleMaxListEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleMaxListEntry.java @@ -12,18 +12,33 @@ package raw.compiler.snapi.truffle.builtin.list_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.MaxListEntry; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.list.ListMaxNodeGen; +import raw.runtime.truffle.ast.expressions.aggregation.AggregateSingleNode; +import raw.runtime.truffle.ast.expressions.aggregation.Aggregations; +import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionFromNodeGen; public class TruffleMaxListEntry extends MaxListEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { - return ListMaxNodeGen.create(args.get(0).exprNode()); + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int resultSlot = + builder.addSlot(FrameSlotKind.Object, "result", "a slot to store the result of osr"); + return new AggregateSingleNode( + CollectionFromNodeGen.create(truffleArgs.get(0).exprNode()), + Aggregations.MAX, + generatorSlot, + resultSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleMinListEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleMinListEntry.java index c293dd22d..856b5bea7 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleMinListEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleMinListEntry.java @@ -12,18 +12,33 @@ package raw.compiler.snapi.truffle.builtin.list_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.MinListEntry; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.list.ListMinNodeGen; +import raw.runtime.truffle.ast.expressions.aggregation.AggregateSingleNode; +import raw.runtime.truffle.ast.expressions.aggregation.Aggregations; +import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionFromNodeGen; public class TruffleMinListEntry extends MinListEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { - return ListMinNodeGen.create(args.get(0).exprNode()); + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int resultSlot = + builder.addSlot(FrameSlotKind.Object, "result", "a slot to store the result of osr"); + return new AggregateSingleNode( + CollectionFromNodeGen.create(truffleArgs.get(0).exprNode()), + Aggregations.MIN, + generatorSlot, + resultSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleSumListEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleSumListEntry.java index 37ff7e9e7..a6363b0ca 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleSumListEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleSumListEntry.java @@ -12,18 +12,33 @@ package raw.compiler.snapi.truffle.builtin.list_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.SumListEntry; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.list.ListSumNodeGen; +import raw.runtime.truffle.ast.expressions.aggregation.AggregateSingleNode; +import raw.runtime.truffle.ast.expressions.aggregation.Aggregations; +import raw.runtime.truffle.ast.expressions.iterable.collection.CollectionFromNodeGen; public class TruffleSumListEntry extends SumListEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { - return ListSumNodeGen.create(args.get(0).exprNode()); + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int resultSlot = + builder.addSlot(FrameSlotKind.Object, "result", "a slot to store the result of osr"); + return new AggregateSingleNode( + CollectionFromNodeGen.create(truffleArgs.get(0).exprNode()), + Aggregations.SUM, + generatorSlot, + resultSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleTransformListEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleTransformListEntry.java index c5f41bd8c..d25eac83a 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleTransformListEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleTransformListEntry.java @@ -12,22 +12,47 @@ package raw.compiler.snapi.truffle.builtin.list_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.TransformListEntry; import raw.compiler.rql2.source.FunType; import raw.compiler.rql2.source.Rql2Type; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.list.ListTransformNodeGen; +import raw.runtime.truffle.ast.expressions.iterable.list.ListTransformNode; public class TruffleTransformListEntry extends TransformListEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { - FunType funType = (FunType) args.get(1).type(); - return ListTransformNodeGen.create( - args.get(0).exprNode(), args.get(1).exprNode(), (Rql2Type) funType.r()); + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FunType funType = (FunType) truffleArgs.get(1).type(); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + int listSlot = builder.addSlot(FrameSlotKind.Object, "list", "a slot to store the list of osr"); + int functionSlot = + builder.addSlot(FrameSlotKind.Object, "function", "a slot to store the function of osr"); + int currentIdxSlot = + builder.addSlot( + FrameSlotKind.Int, "currentIdxSlot", "a slot to store the current index of osr"); + int listSizeSlot = + builder.addSlot( + FrameSlotKind.Int, "listSize", "a slot to store the size of the list of osr"); + int resultSlot = + builder.addSlot( + FrameSlotKind.Object, "list", "a slot to store the result list internal array of osr"); + + return new ListTransformNode( + truffleArgs.get(0).exprNode(), + truffleArgs.get(1).exprNode(), + (Rql2Type) funType.r(), + listSlot, + functionSlot, + currentIdxSlot, + listSizeSlot, + resultSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleUnsafeFromListEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleUnsafeFromListEntry.java index 434fa5fc6..912b329a3 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleUnsafeFromListEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/list_extension/TruffleUnsafeFromListEntry.java @@ -12,23 +12,46 @@ package raw.compiler.snapi.truffle.builtin.list_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.UnsafeFromListEntry; import raw.compiler.rql2.source.Rql2ListType; import raw.compiler.rql2.source.Rql2Type; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.list.ListFromUnsafeNodeGen; +import raw.runtime.truffle.ast.expressions.iterable.list.ListFromUnsafe; public class TruffleUnsafeFromListEntry extends UnsafeFromListEntry implements TruffleEntryExtension { @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); Rql2ListType rql2ListType = (Rql2ListType) type; - return ListFromUnsafeNodeGen.create( - args.get(0).exprNode(), (Rql2Type) rql2ListType.innerType()); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + int generatorSlot = + builder.addSlot(FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int listSlot = + builder.addSlot(FrameSlotKind.Object, "filterList", "a slot to store the ArrayList of osr"); + int currentIdxSlot = + builder.addSlot( + FrameSlotKind.Int, "currentIdxSlot", "a slot to store the current index of osr"); + int listSizeSlot = + builder.addSlot( + FrameSlotKind.Int, "listSize", "a slot to store the size of the list of osr"); + int resultSlot = + builder.addSlot(FrameSlotKind.Object, "list", "a slot to store the result array of osr"); + return new ListFromUnsafe( + truffleArgs.get(0).exprNode(), + (Rql2Type) rql2ListType.innerType(), + generatorSlot, + listSlot, + currentIdxSlot, + listSizeSlot, + resultSlot); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/record_extension/TruffleRecordBuildEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/record_extension/TruffleRecordBuildEntry.java index f8d0a782b..d28c56689 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/record_extension/TruffleRecordBuildEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/record_extension/TruffleRecordBuildEntry.java @@ -15,25 +15,30 @@ import java.util.List; import raw.compiler.base.source.Type; import raw.compiler.rql2.builtin.RecordBuildEntry; +import raw.compiler.rql2.source.Rql2AttrType; import raw.compiler.rql2.source.Rql2RecordType; import raw.compiler.snapi.truffle.TruffleArg; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.literals.StringNode; import raw.runtime.truffle.ast.expressions.record.RecordBuildNode; +import scala.collection.JavaConverters; public class TruffleRecordBuildEntry extends RecordBuildEntry implements TruffleEntryExtension { @Override public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { Rql2RecordType recordType = (Rql2RecordType) type; - ExpressionNode[] keyTypePairs = new ExpressionNode[recordType.atts().size() * 2]; - for (int i = 0; i < recordType.atts().size(); i++) { - keyTypePairs[i * 2] = new StringNode(recordType.atts().apply(i).idn()); - keyTypePairs[i * 2 + 1] = args.get(i).exprNode(); - } + String[] fieldNames = + JavaConverters.asJavaCollection(recordType.atts()).stream() + .map(a -> (Rql2AttrType) a) + .map(Rql2AttrType::idn) + .toList() + .toArray(new String[0]); - return new RecordBuildNode(keyTypePairs); + ExpressionNode[] values = + args.stream().map(a -> ((TruffleArg) a).exprNode()).toArray(ExpressionNode[]::new); + + return new RecordBuildNode(values, fieldNames); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/test_extension/TruffleStrictArgsTestEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/test_extension/TruffleStrictArgsTestEntry.java index 73cf384c8..8a90440c6 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/test_extension/TruffleStrictArgsTestEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/test_extension/TruffleStrictArgsTestEntry.java @@ -39,12 +39,8 @@ public ExpressionNode toTruffle(Type type, List args, RawLanguage ra arg(args, "r") .orElse( new RecordBuildNode( - new ExpressionNode[] { - new StringNode("a"), - new LongNode("0"), - new StringNode("b"), - new FloatNode("0") - })); + new ExpressionNode[] {new LongNode("0"), new FloatNode("0")}, + new String[] {"a", "b"})); return new PlusNode( FloatFromNodeGen.create( new PlusNode( diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/test_extension/TruffleValueArg.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/test_extension/TruffleValueArg.java index 3e25ea5b4..525f626e7 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/test_extension/TruffleValueArg.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/test_extension/TruffleValueArg.java @@ -18,13 +18,11 @@ import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.literals.StringNode; import raw.runtime.truffle.ast.expressions.record.RecordBuildNode; public interface TruffleValueArg extends TruffleEntryExtension { @Override default ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { - return new RecordBuildNode( - new ExpressionNode[] {new StringNode("arg"), args.get(0).exprNode()}); + return new RecordBuildNode(new ExpressionNode[] {args.get(0).exprNode()}, new String[] {"arg"}); } } diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/xml_extension/TruffleParseXmlEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/xml_extension/TruffleParseXmlEntry.java index a1d881776..1c73a82d7 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/xml_extension/TruffleParseXmlEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/xml_extension/TruffleParseXmlEntry.java @@ -12,25 +12,27 @@ package raw.compiler.snapi.truffle.builtin.xml_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; +import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.ParseXmlEntry; import raw.compiler.rql2.source.Rql2IterableType; import raw.compiler.rql2.source.Rql2ListType; import raw.compiler.rql2.source.Rql2Type; import raw.compiler.rql2.source.Rql2TypeWithProperties; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.list.ListFromNodeGen; -import raw.runtime.truffle.ast.expressions.iterable.list.ListFromUnsafeNodeGen; +import raw.runtime.truffle.ast.expressions.iterable.list.ListFromNode; +import raw.runtime.truffle.ast.expressions.iterable.list.ListFromUnsafe; import raw.runtime.truffle.ast.expressions.literals.StringNode; import raw.runtime.truffle.ast.io.json.reader.TryableTopLevelWrapper; import raw.runtime.truffle.ast.io.xml.parser.XmlParseCollectionNode; import raw.runtime.truffle.ast.io.xml.parser.XmlParseValueNode; -import java.util.List; - public class TruffleParseXmlEntry extends ParseXmlEntry implements TruffleEntryExtension { private static ExpressionNode getArg( @@ -48,10 +50,14 @@ private static ExpressionNode getArg( private static final ExpressionNode defaultDateFormat = new StringNode("yyyy-M-d"); private static final ExpressionNode defaultTimeFormat = new StringNode("HH:mm[:ss[.SSS]]"); - @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { - List unnamedArgs = args.stream().filter(arg -> arg.identifier() == null).toList(); - List namedArgs = args.stream().filter(arg -> arg.identifier() != null).toList(); + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + + List unnamedArgs = + truffleArgs.stream().filter(arg -> arg.identifier() == null).toList(); + List namedArgs = + truffleArgs.stream().filter(arg -> arg.identifier() != null).toList(); ExpressionNode encoding = getArg(namedArgs, "encoding", defaultEncoding); ExpressionNode timeFormatExp = getArg(namedArgs, "timeFormat", defaultTimeFormat); ExpressionNode dateFormatExp = getArg(namedArgs, "dateFormat", defaultDateFormat); @@ -67,7 +73,7 @@ public ExpressionNode toTruffle(Type type, List args, RawLanguage ra timeFormatExp, timestampFormatExp, XmlRecurse.recurseXmlParser( - (Rql2TypeWithProperties) iterableType.innerType(), rawLanguage)); + (Rql2TypeWithProperties) iterableType.innerType(), emitter.getLanguage())); if (XmlRecurse.isTryable(iterableType)) { // Probably will need to be either reused in json and xml or create a copy yield new TryableTopLevelWrapper(parseNode); @@ -83,12 +89,43 @@ public ExpressionNode toTruffle(Type type, List args, RawLanguage ra timeFormatExp, timestampFormatExp, XmlRecurse.recurseXmlParser( - (Rql2TypeWithProperties) listType.innerType(), rawLanguage)); + (Rql2TypeWithProperties) listType.innerType(), emitter.getLanguage())); + + int generatorSlot = + builder.addSlot( + FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int listSlot = + builder.addSlot( + FrameSlotKind.Object, "filterList", "a slot to store the ArrayList of osr"); + int currentIdxSlot = + builder.addSlot( + FrameSlotKind.Int, "currentIdxSlot", "a slot to store the current index of osr"); + int listSizeSlot = + builder.addSlot( + FrameSlotKind.Int, "listSize", "a slot to store the size of the list of osr"); + int resultSlot = + builder.addSlot( + FrameSlotKind.Object, "list", "a slot to store the result array of osr"); + if (XmlRecurse.isTryable(listType)) { // Probably will need to be either reused in json and xml or create a copy - yield ListFromNodeGen.create(parseNode, (Rql2Type) listType.innerType()); + yield new ListFromNode( + parseNode, + (Rql2Type) listType.innerType(), + generatorSlot, + listSlot, + currentIdxSlot, + listSizeSlot, + resultSlot); } else { - yield ListFromUnsafeNodeGen.create(parseNode, (Rql2Type) listType.innerType()); + yield new ListFromUnsafe( + parseNode, + (Rql2Type) listType.innerType(), + generatorSlot, + listSlot, + currentIdxSlot, + listSizeSlot, + resultSlot); } } case Rql2TypeWithProperties t -> { @@ -98,7 +135,7 @@ public ExpressionNode toTruffle(Type type, List args, RawLanguage ra dateFormatExp, timeFormatExp, timestampFormatExp, - XmlRecurse.recurseXmlParser(t, rawLanguage).getCallTarget()); + XmlRecurse.recurseXmlParser(t, emitter.getLanguage()).getCallTarget()); if (XmlRecurse.isTryable(t)) { yield new TryableTopLevelWrapper(parseNode); } else { diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/xml_extension/TruffleReadXmlEntry.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/xml_extension/TruffleReadXmlEntry.java index 4d5db6490..9352106f0 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/xml_extension/TruffleReadXmlEntry.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/builtin/xml_extension/TruffleReadXmlEntry.java @@ -12,25 +12,27 @@ package raw.compiler.snapi.truffle.builtin.xml_extension; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotKind; +import java.util.List; import raw.compiler.base.source.Type; +import raw.compiler.rql2.api.Rql2Arg; import raw.compiler.rql2.builtin.ReadXmlEntry; import raw.compiler.rql2.source.Rql2IterableType; import raw.compiler.rql2.source.Rql2ListType; import raw.compiler.rql2.source.Rql2Type; import raw.compiler.rql2.source.Rql2TypeWithProperties; import raw.compiler.snapi.truffle.TruffleArg; +import raw.compiler.snapi.truffle.TruffleEmitter; import raw.compiler.snapi.truffle.TruffleEntryExtension; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.ast.expressions.iterable.list.ListFromNodeGen; -import raw.runtime.truffle.ast.expressions.iterable.list.ListFromUnsafeNodeGen; +import raw.runtime.truffle.ast.expressions.iterable.list.ListFromNode; +import raw.runtime.truffle.ast.expressions.iterable.list.ListFromUnsafe; import raw.runtime.truffle.ast.expressions.literals.StringNode; import raw.runtime.truffle.ast.io.json.reader.TryableTopLevelWrapper; import raw.runtime.truffle.ast.io.xml.parser.XmlReadCollectionNode; import raw.runtime.truffle.ast.io.xml.parser.XmlReadValueNode; -import java.util.List; - public class TruffleReadXmlEntry extends ReadXmlEntry implements TruffleEntryExtension { private static ExpressionNode getArg( @@ -49,9 +51,14 @@ private static ExpressionNode getArg( private static final ExpressionNode defaultTimeFormat = new StringNode("HH:mm[:ss[.SSS]]"); @Override - public ExpressionNode toTruffle(Type type, List args, RawLanguage rawLanguage) { - List unnamedArgs = args.stream().filter(arg -> arg.identifier() == null).toList(); - List namedArgs = args.stream().filter(arg -> arg.identifier() != null).toList(); + public ExpressionNode toTruffle(Type type, List args, TruffleEmitter emitter) { + List truffleArgs = rql2argsToTruffleArgs(args, emitter); + FrameDescriptor.Builder builder = emitter.getFrameDescriptorBuilder(); + + List unnamedArgs = + truffleArgs.stream().filter(arg -> arg.identifier() == null).toList(); + List namedArgs = + truffleArgs.stream().filter(arg -> arg.identifier() != null).toList(); ExpressionNode encoding = getArg(namedArgs, "encoding", defaultEncoding); ExpressionNode timeFormatExp = getArg(namedArgs, "timeFormat", defaultTimeFormat); ExpressionNode dateFormatExp = getArg(namedArgs, "dateFormat", defaultDateFormat); @@ -68,7 +75,7 @@ public ExpressionNode toTruffle(Type type, List args, RawLanguage ra timeFormatExp, timestampFormatExp, XmlRecurse.recurseXmlParser( - (Rql2TypeWithProperties) iterableType.innerType(), rawLanguage)); + (Rql2TypeWithProperties) iterableType.innerType(), emitter.getLanguage())); if (XmlRecurse.isTryable(iterableType)) { // Probably will need to be either reused in json and xml or create a copy yield new TryableTopLevelWrapper(parseNode); @@ -85,12 +92,43 @@ public ExpressionNode toTruffle(Type type, List args, RawLanguage ra timeFormatExp, timestampFormatExp, XmlRecurse.recurseXmlParser( - (Rql2TypeWithProperties) listType.innerType(), rawLanguage)); + (Rql2TypeWithProperties) listType.innerType(), emitter.getLanguage())); + + int generatorSlot = + builder.addSlot( + FrameSlotKind.Object, "generator", "a slot to store the generator of osr"); + int listSlot = + builder.addSlot( + FrameSlotKind.Object, "filterList", "a slot to store the ArrayList of osr"); + int currentIdxSlot = + builder.addSlot( + FrameSlotKind.Int, "currentIdxSlot", "a slot to store the current index of osr"); + int listSizeSlot = + builder.addSlot( + FrameSlotKind.Int, "listSize", "a slot to store the size of the list of osr"); + int resultSlot = + builder.addSlot( + FrameSlotKind.Object, "list", "a slot to store the result array of osr"); + if (XmlRecurse.isTryable(listType)) { // Probably will need to be either reused in json and xml or create a copy - yield ListFromNodeGen.create(parseNode, (Rql2Type) listType.innerType()); + yield new ListFromNode( + parseNode, + (Rql2Type) listType.innerType(), + generatorSlot, + listSlot, + currentIdxSlot, + listSizeSlot, + resultSlot); } else { - yield ListFromUnsafeNodeGen.create(parseNode, (Rql2Type) listType.innerType()); + yield new ListFromUnsafe( + parseNode, + (Rql2Type) listType.innerType(), + generatorSlot, + listSlot, + currentIdxSlot, + listSizeSlot, + resultSlot); } } case Rql2TypeWithProperties t -> { @@ -101,7 +139,7 @@ public ExpressionNode toTruffle(Type type, List args, RawLanguage ra dateFormatExp, timeFormatExp, timestampFormatExp, - XmlRecurse.recurseXmlParser(t, rawLanguage).getCallTarget()); + XmlRecurse.recurseXmlParser(t, emitter.getLanguage()).getCallTarget()); if (XmlRecurse.isTryable(t)) { yield new TryableTopLevelWrapper(parseNode); } else { diff --git a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/compiler/SnapiTruffleEmitter.java b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/compiler/SnapiTruffleEmitter.java index b0efc8396..10bc4c4e2 100644 --- a/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/compiler/SnapiTruffleEmitter.java +++ b/snapi-truffle/src/main/java/raw/compiler/snapi/truffle/compiler/SnapiTruffleEmitter.java @@ -81,7 +81,7 @@ private Type tipe(Exp e) { return analyzer.tipe(e); } - protected RawLanguage getLanguage() { + public RawLanguage getLanguage() { return this.rawLanguage; } @@ -112,7 +112,7 @@ protected FrameDescriptor dropScope() { return frameDescriptorBuilder.build(); } - private FrameDescriptor.Builder getFrameDescriptorBuilder() { + public FrameDescriptor.Builder getFrameDescriptorBuilder() { return frameDescriptorBuilderScope.get(0); } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ExpressionNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ExpressionNode.java index afb34c5e2..cfb1332ef 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ExpressionNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ExpressionNode.java @@ -20,7 +20,8 @@ import com.oracle.truffle.api.instrumentation.Tag; import com.oracle.truffle.api.nodes.UnexpectedResultException; import raw.runtime.truffle.runtime.primitives.*; -import raw.runtime.truffle.runtime.record.RecordObject; +import raw.runtime.truffle.runtime.record.DuplicateKeyRecord; +import raw.runtime.truffle.runtime.record.PureRecord; @TypeSystemReference(RawTypes.class) @GenerateWrapper @@ -97,8 +98,13 @@ public LocationObject executeLocation(VirtualFrame virtualFrame) return RawTypesGen.expectLocationObject(executeGeneric(virtualFrame)); } - public RecordObject executeRecord(VirtualFrame virtualFrame) throws UnexpectedResultException { - return RawTypesGen.expectRecordObject(executeGeneric(virtualFrame)); + public PureRecord executePureRecord(VirtualFrame virtualFrame) throws UnexpectedResultException { + return RawTypesGen.expectPureRecord(executeGeneric(virtualFrame)); + } + + public DuplicateKeyRecord executeDuplicateKey(VirtualFrame virtualFrame) + throws UnexpectedResultException { + return RawTypesGen.expectDuplicateKeyRecord(executeGeneric(virtualFrame)); } @Override diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/PropertyType.java b/snapi-truffle/src/main/java/raw/runtime/truffle/PropertyType.java new file mode 100644 index 000000000..98ab8fad6 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/PropertyType.java @@ -0,0 +1,48 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle; + +// Static properties for dynamic object storage types +public class PropertyType { + public static final byte BYTE_TYPE = 0; + public static final byte SHORT_TYPE = 1; + public static final byte INT_TYPE = 2; + public static final byte LONG_TYPE = 3; + public static final byte FLOAT_TYPE = 4; + public static final byte DOUBLE_TYPE = 5; + public static final byte OBJECT_TYPE = 6; + + public static boolean isByte(int type) { + return type == BYTE_TYPE; + } + + public static boolean isShort(int type) { + return type == SHORT_TYPE; + } + + public static boolean isInt(int type) { + return type == INT_TYPE; + } + + public static boolean isFloat(int type) { + return type == FLOAT_TYPE; + } + + public static boolean isLong(int type) { + return type == LONG_TYPE; + } + + public static boolean isDouble(int type) { + return type == DOUBLE_TYPE; + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/RawContext.java b/snapi-truffle/src/main/java/raw/runtime/truffle/RawContext.java index a27d2ee02..519ad8dc6 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/RawContext.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/RawContext.java @@ -41,14 +41,15 @@ public final class RawContext { private final RawLanguage language; private final Env env; - private RawSettings rawSettings; - private OutputStream output; - private AuthenticatedUser user; - private String traceId; - private String[] scopes; - private ProgramEnvironment programEnvironment; + private final RawSettings rawSettings; + private final OutputStream output; + private final AuthenticatedUser user; + private final String traceId; + private final String[] scopes; + private final ProgramEnvironment programEnvironment; private final RawFunctionRegistry functionRegistry; + @CompilerDirectives.TruffleBoundary public RawContext(RawLanguage language, Env env) { this.language = language; this.env = env; @@ -141,6 +142,7 @@ public RawSettings getSettings() { return rawSettings; } + @CompilerDirectives.TruffleBoundary public Secret getSecret(String key) { if (user == null) { throw new RawTruffleRuntimeException("User not set"); diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/RawLanguage.java b/snapi-truffle/src/main/java/raw/runtime/truffle/RawLanguage.java index c433d7a0d..973d09066 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/RawLanguage.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/RawLanguage.java @@ -13,6 +13,7 @@ package raw.runtime.truffle; import com.oracle.truffle.api.CallTarget; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.instrumentation.ProvidedTags; import com.oracle.truffle.api.instrumentation.StandardTags; @@ -41,7 +42,8 @@ import raw.inferrer.api.InferrerService; import raw.runtime.RuntimeContext; import raw.runtime.truffle.runtime.exceptions.RawTruffleValidationException; -import raw.runtime.truffle.runtime.record.RecordObject; +import raw.runtime.truffle.runtime.record.DuplicateKeyRecord; +import raw.runtime.truffle.runtime.record.PureRecord; import raw.sources.api.SourceContext; import raw.utils.AuthenticatedUser; import raw.utils.RawSettings; @@ -73,7 +75,19 @@ public final class RawLanguage extends TruffleLanguage { private static final RawSettings defaultRawSettings = new RawSettings(ConfigFactory.load(), ConfigFactory.empty()); - private final Shape initialRecordShape = Shape.newBuilder().build(); + private final Shape pureRecordShape = Shape.newBuilder().build(); + private final Shape duplicateKeyRecordShape = Shape.newBuilder().build(); + + // The bellow methods are used to create new instances of the record classes. + // This instances must have common ancestor, so we create them with the same shape. + // This is a common pattern in Truffle, due to the way the object model works. + public PureRecord createPureRecord() { + return new PureRecord(pureRecordShape); + } + + public DuplicateKeyRecord createDuplicateKeyRecord() { + return new DuplicateKeyRecord(duplicateKeyRecordShape); + } @Override protected final RawContext createContext(Env env) { @@ -98,11 +112,6 @@ public static RawLanguage get(Node node) { private final InteropLibrary bindings = InteropLibrary.getFactory().createDispatched(1); - // FIXME (msb): Why is this here? - public RecordObject createRecord() { - return new RecordObject(initialRecordShape); - } - @Override protected OptionDescriptors getOptionDescriptors() { return RawOptions.OPTION_DESCRIPTORS; @@ -187,6 +196,7 @@ protected CallTarget parse(ParsingRequest request) throws Exception { (Class>) (Class) ImplicitCasts.class)); + @CompilerDirectives.TruffleBoundary SourceProgram transpile(SourceProgram root, ProgramContext programContext) { if (phases.isEmpty()) { // No phases in compiler @@ -200,6 +210,7 @@ SourceProgram transpile(SourceProgram root, ProgramContext programContext) { } } + @CompilerDirectives.TruffleBoundary private Phase buildPipeline( Phase init, ProgramContext programContext) { Phase cur = init; diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/RawLanguageCache.java b/snapi-truffle/src/main/java/raw/runtime/truffle/RawLanguageCache.java index 46a1ad478..ec39d6282 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/RawLanguageCache.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/RawLanguageCache.java @@ -12,6 +12,7 @@ package raw.runtime.truffle; +import com.oracle.truffle.api.CompilerDirectives; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -63,6 +64,7 @@ public InferrerService getInferrer() { } } + @CompilerDirectives.TruffleBoundary private Value get(AuthenticatedUser user, RawSettings rawSettings) { // Create services on-demand. CredentialsService credentialsService = @@ -98,12 +100,14 @@ public InferrerService getInferrer(AuthenticatedUser user, RawSettings rawSettin return get(user, rawSettings).getInferrer(); } + @CompilerDirectives.TruffleBoundary public void incrementContext(RawContext context) { synchronized (activeContextsLock) { activeContexts.add(context); } } + @CompilerDirectives.TruffleBoundary public void releaseContext(RawContext context) { synchronized (activeContextsLock) { activeContexts.remove(context); diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/RawTypes.java b/snapi-truffle/src/main/java/raw/runtime/truffle/RawTypes.java index a1091fcf4..53ffb5429 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/RawTypes.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/RawTypes.java @@ -14,7 +14,8 @@ import com.oracle.truffle.api.dsl.TypeSystem; import raw.runtime.truffle.runtime.primitives.*; -import raw.runtime.truffle.runtime.record.RecordObject; +import raw.runtime.truffle.runtime.record.DuplicateKeyRecord; +import raw.runtime.truffle.runtime.record.PureRecord; @TypeSystem({ boolean.class, @@ -32,6 +33,7 @@ IntervalObject.class, TimestampObject.class, LocationObject.class, - RecordObject.class + PureRecord.class, + DuplicateKeyRecord.class }) public abstract class RawTypes {} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/ProgramExpressionNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/ProgramExpressionNode.java index fe19739c5..3a3566a62 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/ProgramExpressionNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/ProgramExpressionNode.java @@ -42,4 +42,9 @@ public SourceSection getSourceSection() { public Object execute(VirtualFrame frame) { return bodyNode.executeGeneric(frame); } + + @Override + public String toString() { + return bodyNode.toString(); + } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/TypeGuards.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/TypeGuards.java index 1a0be270b..04b4f9669 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/TypeGuards.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/TypeGuards.java @@ -12,28 +12,35 @@ package raw.runtime.truffle.ast; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Idempotent; import raw.compiler.rql2.source.*; public class TypeGuards { + public static final Rql2IsTryableTypeProperty tryable = Rql2IsTryableTypeProperty.apply(); + public static final Rql2IsNullableTypeProperty nullable = Rql2IsNullableTypeProperty.apply(); + @Idempotent + @CompilerDirectives.TruffleBoundary public static boolean isTryable(Rql2Type rql2Type) { if (rql2Type instanceof Rql2TypeWithProperties rql2TypeWithProperties) { - return rql2TypeWithProperties.props().contains(Rql2IsTryableTypeProperty.apply()); + return rql2TypeWithProperties.props().contains(tryable); } return false; } @Idempotent + @CompilerDirectives.TruffleBoundary public static boolean isNullable(Rql2Type rql2Type) { if (rql2Type instanceof Rql2TypeWithProperties rql2TypeWithProperties) { - return rql2TypeWithProperties.props().contains(new Rql2IsNullableTypeProperty()); + return rql2TypeWithProperties.props().contains(nullable); } return false; } @Idempotent + @CompilerDirectives.TruffleBoundary public static boolean isBooleanKind(Rql2Type rql2Type) { if (rql2Type instanceof Rql2TypeWithProperties rql2TypeWithProperties) { return rql2TypeWithProperties instanceof Rql2BoolType @@ -43,6 +50,7 @@ public static boolean isBooleanKind(Rql2Type rql2Type) { } @Idempotent + @CompilerDirectives.TruffleBoundary public static boolean isByteKind(Rql2Type rql2Type) { if (rql2Type instanceof Rql2TypeWithProperties rql2TypeWithProperties) { return rql2TypeWithProperties instanceof Rql2ByteType @@ -52,6 +60,7 @@ public static boolean isByteKind(Rql2Type rql2Type) { } @Idempotent + @CompilerDirectives.TruffleBoundary public static boolean isShortKind(Rql2Type rql2Type) { if (rql2Type instanceof Rql2TypeWithProperties rql2TypeWithProperties) { return rql2TypeWithProperties instanceof Rql2ShortType @@ -61,6 +70,7 @@ public static boolean isShortKind(Rql2Type rql2Type) { } @Idempotent + @CompilerDirectives.TruffleBoundary public static boolean isIntKind(Rql2Type rql2Type) { if (rql2Type instanceof Rql2TypeWithProperties rql2TypeWithProperties) { return rql2TypeWithProperties instanceof Rql2IntType @@ -70,6 +80,7 @@ public static boolean isIntKind(Rql2Type rql2Type) { } @Idempotent + @CompilerDirectives.TruffleBoundary public static boolean isLongKind(Rql2Type rql2Type) { if (rql2Type instanceof Rql2TypeWithProperties rql2TypeWithProperties) { return rql2TypeWithProperties instanceof Rql2LongType @@ -79,6 +90,7 @@ public static boolean isLongKind(Rql2Type rql2Type) { } @Idempotent + @CompilerDirectives.TruffleBoundary public static boolean isFloatKind(Rql2Type rql2Type) { if (rql2Type instanceof Rql2TypeWithProperties rql2TypeWithProperties) { return rql2TypeWithProperties instanceof Rql2FloatType @@ -88,6 +100,7 @@ public static boolean isFloatKind(Rql2Type rql2Type) { } @Idempotent + @CompilerDirectives.TruffleBoundary public static boolean isDoubleKind(Rql2Type rql2Type) { if (rql2Type instanceof Rql2TypeWithProperties rql2TypeWithProperties) { return rql2TypeWithProperties instanceof Rql2DoubleType @@ -97,6 +110,7 @@ public static boolean isDoubleKind(Rql2Type rql2Type) { } @Idempotent + @CompilerDirectives.TruffleBoundary public static boolean isDecimalKind(Rql2Type rql2Type) { if (rql2Type instanceof Rql2TypeWithProperties rql2TypeWithProperties) { return rql2TypeWithProperties instanceof Rql2DecimalType @@ -106,6 +120,7 @@ public static boolean isDecimalKind(Rql2Type rql2Type) { } @Idempotent + @CompilerDirectives.TruffleBoundary public static boolean isStringKind(Rql2Type rql2Type) { if (rql2Type instanceof Rql2TypeWithProperties rql2TypeWithProperties) { return rql2TypeWithProperties instanceof Rql2StringType @@ -115,6 +130,7 @@ public static boolean isStringKind(Rql2Type rql2Type) { } @Idempotent + @CompilerDirectives.TruffleBoundary public static boolean isIntervalKind(Rql2Type rql2Type) { if (rql2Type instanceof Rql2TypeWithProperties rql2TypeWithProperties) { return rql2TypeWithProperties instanceof Rql2IntervalType @@ -124,6 +140,7 @@ public static boolean isIntervalKind(Rql2Type rql2Type) { } @Idempotent + @CompilerDirectives.TruffleBoundary public static boolean isDateKind(Rql2Type rql2Type) { if (rql2Type instanceof Rql2TypeWithProperties rql2TypeWithProperties) { return rql2TypeWithProperties instanceof Rql2DateType @@ -133,6 +150,7 @@ public static boolean isDateKind(Rql2Type rql2Type) { } @Idempotent + @CompilerDirectives.TruffleBoundary public static boolean isTimeKind(Rql2Type rql2Type) { if (rql2Type instanceof Rql2TypeWithProperties rql2TypeWithProperties) { return rql2TypeWithProperties instanceof Rql2TimeType @@ -142,6 +160,7 @@ public static boolean isTimeKind(Rql2Type rql2Type) { } @Idempotent + @CompilerDirectives.TruffleBoundary public static boolean isTimestampKind(Rql2Type rql2Type) { if (rql2Type instanceof Rql2TypeWithProperties rql2TypeWithProperties) { return rql2TypeWithProperties instanceof Rql2TimestampType @@ -151,6 +170,7 @@ public static boolean isTimestampKind(Rql2Type rql2Type) { } @Idempotent + @CompilerDirectives.TruffleBoundary public static boolean isRecordKind(Rql2Type rql2Type) { if (rql2Type instanceof Rql2TypeWithProperties rql2TypeWithProperties) { return rql2TypeWithProperties instanceof Rql2RecordType @@ -160,6 +180,7 @@ public static boolean isRecordKind(Rql2Type rql2Type) { } @Idempotent + @CompilerDirectives.TruffleBoundary public static boolean isListKind(Rql2Type rql2Type) { if (rql2Type instanceof Rql2TypeWithProperties rql2TypeWithProperties) { return rql2TypeWithProperties instanceof Rql2ListType @@ -169,6 +190,7 @@ public static boolean isListKind(Rql2Type rql2Type) { } @Idempotent + @CompilerDirectives.TruffleBoundary public static boolean isIterableKind(Rql2Type rql2Type) { if (rql2Type instanceof Rql2TypeWithProperties rql2TypeWithProperties) { return rql2TypeWithProperties instanceof Rql2IterableType @@ -178,6 +200,7 @@ public static boolean isIterableKind(Rql2Type rql2Type) { } @Idempotent + @CompilerDirectives.TruffleBoundary public static boolean isBinaryKind(Rql2Type rql2Type) { if (rql2Type instanceof Rql2TypeWithProperties rql2TypeWithProperties) { return rql2TypeWithProperties instanceof Rql2BinaryType diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/controlflow/ExpBlockNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/controlflow/ExpBlockNode.java index a0d919c40..dca327953 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/controlflow/ExpBlockNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/controlflow/ExpBlockNode.java @@ -44,4 +44,9 @@ public Object executeGeneric(VirtualFrame virtualFrame) { public void executeVoid(VirtualFrame frame, StatementNode node, int index, int argument) { node.executeVoid(frame); } + + @Override + public String toString() { + return expNode.toString(); + } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/aggregation/AggregateMultipleNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/aggregation/AggregateMultipleNode.java new file mode 100644 index 000000000..bf5bfa53d --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/aggregation/AggregateMultipleNode.java @@ -0,0 +1,93 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.expressions.aggregation; + +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.ast.osr.OSRGeneratorNode; +import raw.runtime.truffle.ast.osr.bodies.OSRMultiAggregationBodyNode; +import raw.runtime.truffle.ast.osr.conditions.OSRHasNextConditionNode; +import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; +import raw.runtime.truffle.runtime.iterable.IterableNodes; +import raw.runtime.truffle.runtime.iterable.IterableNodesFactory; +import raw.runtime.truffle.runtime.primitives.ErrorObject; + +public class AggregateMultipleNode extends ExpressionNode { + + @Child ExpressionNode iterableNode; + + @Child private LoopNode loop; + + @Child + GeneratorNodes.GeneratorInitNode initNode = GeneratorNodesFactory.GeneratorInitNodeGen.create(); + + @Child + GeneratorNodes.GeneratorCloseNode closeNode = + GeneratorNodesFactory.GeneratorCloseNodeGen.create(); + + @Child + private GeneratorNodes.GeneratorHasNextNode hasNextNode = + GeneratorNodesFactory.GeneratorHasNextNodeGen.create(); + + @Child + IterableNodes.GetGeneratorNode getGeneratorNode = + IterableNodesFactory.GetGeneratorNodeGen.create(); + + @Child AggregatorNodes.Zero zeroNode = AggregatorNodesFactory.ZeroNodeGen.create(); + + private final byte[] aggregationTypes; + + private final int generatorSlot; + private final int resultSlot; + + public AggregateMultipleNode( + ExpressionNode iterableNode, byte[] aggregationTypes, int generatorSlot, int resultSlot) { + this.iterableNode = iterableNode; + loop = + Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRHasNextConditionNode(generatorSlot), + new OSRMultiAggregationBodyNode(aggregationTypes, generatorSlot, resultSlot))); + this.aggregationTypes = aggregationTypes; + this.generatorSlot = generatorSlot; + this.resultSlot = resultSlot; + } + + @Override + public Object executeGeneric(VirtualFrame virtualFrame) { + Object generator = getGeneratorNode.execute(this, iterableNode.executeGeneric(virtualFrame)); + try { + initNode.execute(this, generator); + Object[] results = new Object[aggregationTypes.length]; + for (int i = 0; i < aggregationTypes.length; i++) { + results[i] = zeroNode.execute(this, aggregationTypes[i]); + } + if (!hasNextNode.execute(this, generator)) { + return results; + } + virtualFrame.setObject(generatorSlot, generator); + virtualFrame.setObject(resultSlot, results); + loop.execute(virtualFrame); + return virtualFrame.getObject(resultSlot); + } catch (RawTruffleRuntimeException e) { + return new ErrorObject(e.getMessage()); + } finally { + closeNode.execute(this, generator); + } + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/aggregation/AggregateSingleNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/aggregation/AggregateSingleNode.java new file mode 100644 index 000000000..523385764 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/aggregation/AggregateSingleNode.java @@ -0,0 +1,91 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.expressions.aggregation; + +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.ast.osr.OSRGeneratorNode; +import raw.runtime.truffle.ast.osr.bodies.OSRSingleAggregationBodyNode; +import raw.runtime.truffle.ast.osr.conditions.OSRHasNextConditionNode; +import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; +import raw.runtime.truffle.runtime.iterable.IterableNodes; +import raw.runtime.truffle.runtime.iterable.IterableNodesFactory; +import raw.runtime.truffle.runtime.primitives.ErrorObject; + +public class AggregateSingleNode extends ExpressionNode { + + @Child ExpressionNode iterableNode; + + @Child private LoopNode loop; + + @Child + GeneratorNodes.GeneratorInitNode initNode = GeneratorNodesFactory.GeneratorInitNodeGen.create(); + + @Child + GeneratorNodes.GeneratorCloseNode closeNode = + GeneratorNodesFactory.GeneratorCloseNodeGen.create(); + + @Child + private GeneratorNodes.GeneratorHasNextNode hasNextNode = + GeneratorNodesFactory.GeneratorHasNextNodeGen.create(); + + @Child + IterableNodes.GetGeneratorNode getGeneratorNode = + IterableNodesFactory.GetGeneratorNodeGen.create(); + + @Child AggregatorNodes.Zero zeroNode = AggregatorNodesFactory.ZeroNodeGen.create(); + + private final byte aggregationType; + + private final int generatorSlot; + private final int resultSlot; + + public AggregateSingleNode( + ExpressionNode iterableNode, byte aggregationType, int generatorSlot, int resultSlot) { + this.iterableNode = iterableNode; + loop = + Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRHasNextConditionNode(generatorSlot), + new OSRSingleAggregationBodyNode(aggregationType, generatorSlot, resultSlot))); + this.aggregationType = aggregationType; + this.generatorSlot = generatorSlot; + this.resultSlot = resultSlot; + } + + @Override + public Object executeGeneric(VirtualFrame virtualFrame) { + Object generator = getGeneratorNode.execute(this, iterableNode.executeGeneric(virtualFrame)); + try { + initNode.execute(this, generator); + if (!hasNextNode.execute(this, generator)) { + return zeroNode.execute(this, aggregationType); + } + Object result = zeroNode.execute(this, aggregationType); + + virtualFrame.setObject(generatorSlot, generator); + virtualFrame.setObject(resultSlot, result); + loop.execute(virtualFrame); + return virtualFrame.getObject(resultSlot); + } catch (RawTruffleRuntimeException e) { + return new ErrorObject(e.getMessage()); + } finally { + closeNode.execute(this, generator); + } + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/aggregation/aggregator/Aggregators.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/aggregation/Aggregations.java similarity index 81% rename from snapi-truffle/src/main/java/raw/runtime/truffle/runtime/aggregation/aggregator/Aggregators.java rename to snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/aggregation/Aggregations.java index 5cc577731..816988a45 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/aggregation/aggregator/Aggregators.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/aggregation/Aggregations.java @@ -10,11 +10,12 @@ * licenses/APL.txt. */ -package raw.runtime.truffle.runtime.aggregation.aggregator; +package raw.runtime.truffle.ast.expressions.aggregation; -public class Aggregators { +public class Aggregations { public static final byte COUNT = 0; public static final byte MAX = 1; public static final byte MIN = 2; public static final byte SUM = 3; + public static final byte LAST = 4; } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/aggregation/aggregator/AggregatorNodes.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/aggregation/AggregatorNodes.java similarity index 80% rename from snapi-truffle/src/main/java/raw/runtime/truffle/runtime/aggregation/aggregator/AggregatorNodes.java rename to snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/aggregation/AggregatorNodes.java index 43c0b3dd9..ca1fafa63 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/aggregation/aggregator/AggregatorNodes.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/aggregation/AggregatorNodes.java @@ -10,20 +10,20 @@ * licenses/APL.txt. */ -package raw.runtime.truffle.runtime.aggregation.aggregator; +package raw.runtime.truffle.ast.expressions.aggregation; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.runtime.operators.OperatorNodes; import raw.runtime.truffle.runtime.primitives.NullObject; -import raw.runtime.truffle.tryable_nullable.Nullable; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; public class AggregatorNodes { @NodeInfo(shortName = "Aggregator.Zero") @GenerateUncached @GenerateInline - @ImportStatic(Aggregators.class) + @ImportStatic(Aggregations.class) public abstract static class Zero extends Node { public abstract Object execute(Node node, byte aggregatorType); @@ -47,12 +47,17 @@ static Object minZero(Node node, byte aggregatorType) { static Object sumZero(Node node, byte aggregatorType) { return NullObject.INSTANCE; } + + @Specialization(guards = "aggregatorType == LAST") + static Object sumLast(Node node, byte aggregatorType) { + return NullObject.INSTANCE; + } } @NodeInfo(shortName = "Aggregator.Merge") @GenerateUncached @GenerateInline - @ImportStatic(Aggregators.class) + @ImportStatic(Aggregations.class) public abstract static class Merge extends Node { public abstract Object execute(Node node, byte aggregatorType, Object current, Object next); @@ -69,9 +74,10 @@ static Object mergeMax( Object current, Object next, @Bind("$node") Node thisNode, + @Cached @Cached.Shared("isNull") TryableNullableNodes.IsNullNode isNullNode, @Cached @Cached.Shared("compare") OperatorNodes.CompareNode compare) { - if (Nullable.isNotNull(current)) { - if (Nullable.isNotNull(next)) { + if (!isNullNode.execute(thisNode, current)) { + if (!isNullNode.execute(thisNode, next)) { // if both are defined, pick the largest if (compare.execute(thisNode, current, next) > 0) { return current; @@ -95,9 +101,10 @@ static Object mergeMin( Object current, Object next, @Bind("$node") Node thisNode, + @Cached @Cached.Shared("isNull") TryableNullableNodes.IsNullNode isNullNode, @Cached @Cached.Shared("compare") OperatorNodes.CompareNode compare) { - if (Nullable.isNotNull(current)) { - if (Nullable.isNotNull(next)) { + if (!isNullNode.execute(thisNode, current)) { + if (!isNullNode.execute(thisNode, next)) { // if both are defined, pick the smallest if (compare.execute(thisNode, current, next) < 0) { return current; @@ -124,5 +131,10 @@ static Object mergeSum( @Cached OperatorNodes.AddNode add) { return add.execute(thisNode, current, next); } + + @Specialization(guards = "aggregatorType == LAST") + static Object mergeLast(Node node, byte aggregatorType, Object current, Object next) { + return next; + } } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/binary/AndNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/binary/AndNode.java index cc2d03a66..5e3492023 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/binary/AndNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/binary/AndNode.java @@ -15,13 +15,18 @@ import com.oracle.truffle.api.frame.VirtualFrame; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.runtime.primitives.NullObject; -import raw.runtime.truffle.tryable_nullable.Nullable; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodesFactory; public final class AndNode extends ExpressionNode { @Child private ExpressionNode leftNode; @Child private ExpressionNode rightNode; + @Child + private TryableNullableNodes.IsNullNode isNullNode = + TryableNullableNodesFactory.IsNullNodeGen.create(); + public AndNode(ExpressionNode leftNode, ExpressionNode rightNode) { this.leftNode = leftNode; this.rightNode = rightNode; @@ -50,7 +55,7 @@ public Object executeGeneric(VirtualFrame virtualFrame) { private Boolean getOperand(ExpressionNode node, VirtualFrame frame) { Object value = node.executeGeneric(frame); - if (Nullable.isNotNull(value)) { + if (!isNullNode.execute(this, value)) { return (Boolean) value; } else { return null; diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/binary/OrNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/binary/OrNode.java index 74fe96b7f..38d700a32 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/binary/OrNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/binary/OrNode.java @@ -15,13 +15,18 @@ import com.oracle.truffle.api.frame.VirtualFrame; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.runtime.primitives.NullObject; -import raw.runtime.truffle.tryable_nullable.Nullable; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodesFactory; public final class OrNode extends ExpressionNode { @Child private ExpressionNode leftNode; @Child private ExpressionNode rightNode; + @Child + private TryableNullableNodes.IsNullNode isNullNode = + TryableNullableNodesFactory.IsNullNodeGen.create(); + public OrNode(ExpressionNode leftNode, ExpressionNode rightNode) { this.leftNode = leftNode; this.rightNode = rightNode; @@ -50,7 +55,7 @@ public Object executeGeneric(VirtualFrame virtualFrame) { private Boolean getOperand(ExpressionNode node, VirtualFrame frame) { Object value = node.executeGeneric(frame); - if (Nullable.isNotNull(value)) { + if (!isNullNode.execute(this, value)) { return (Boolean) value; } else { return null; diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/aws_package/AwsV4SignedRequestNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/aws_package/AwsV4SignedRequestNode.java index 54f12cf00..3379ae665 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/aws_package/AwsV4SignedRequestNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/aws_package/AwsV4SignedRequestNode.java @@ -16,11 +16,6 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.UnknownIdentifierException; -import com.oracle.truffle.api.interop.UnsupportedMessageException; -import com.oracle.truffle.api.interop.UnsupportedTypeException; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.NodeInfo; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; @@ -40,6 +35,7 @@ import raw.runtime.truffle.runtime.list.ListNodes; import raw.runtime.truffle.runtime.list.ObjectList; import raw.runtime.truffle.runtime.primitives.LocationObject; +import raw.runtime.truffle.runtime.record.RecordNodes; import scala.Tuple2; import scala.collection.immutable.HashMap; import scala.collection.immutable.Map; @@ -129,206 +125,209 @@ protected LocationObject doRequest( @Cached(inline = true) ListNodes.SortNode sortNode, @Cached(inline = true) ListNodes.SizeNode sizeNode, @Cached(inline = true) ListNodes.GetNode getNode, - @CachedLibrary(limit = "2") InteropLibrary records) { - try { - Instant t = Instant.now(); - String amzdate = formatterWithTimeZone().format(t); - String datestamp = getDateFormatter().format(t); - - // Task 1: create canonical request with all request settings: method, canonicalUri, - // canonicalQueryString etc. - VectorBuilder> urlParamsVec = new VectorBuilder<>(); - StringBuilder canonicalQueryBuilder = new StringBuilder(); - - Object urlParamsSorted = sortNode.execute(this, urlParams); - - for (int i = 0; i < sizeNode.execute(this, urlParamsSorted); i++) { - canonicalQueryBuilder - .append( - URLEncoder.encode( - (String) records.readMember(getNode.execute(this, urlParamsSorted, i), "_1"), - StandardCharsets.UTF_8)) - .append("=") - .append( - URLEncoder.encode( - (String) records.readMember(getNode.execute(this, urlParamsSorted, i), "_2"), - StandardCharsets.UTF_8)) - .append("&"); - urlParamsVec.$plus$eq( - new Tuple2<>( - (String) records.readMember(getNode.execute(this, urlParamsSorted, i), "_1"), - (String) records.readMember(getNode.execute(this, urlParamsSorted, i), "_2"))); - } - // remove last '&' - if (!canonicalQueryBuilder.isEmpty()) { - canonicalQueryBuilder.deleteCharAt(canonicalQueryBuilder.length() - 1); - } - - // Create the canonical headers and signed headers. - // Header names must be trimmed and lowercase, and sorted in code point order from - // low to high. Note that there is a trailing \n. - // Note: The request can include any headers; canonical_headers and signed_headers lists - // those that you want to be included in the hash of the request. "Host" and - // "x-amz-date" are - // always required. - StringBuilder canonicalHeadersBuilder = new StringBuilder(); - StringBuilder signedHeadersBuilder = new StringBuilder(); - VectorBuilder> headersParamsVec = new VectorBuilder<>(); - - int headersSize = (int) sizeNode.execute(this, headers); - // Adding space for host and "x-amz-date", "host" and "x-amz-security-token" if it is - // defined - int allHeadersSize = headersSize + 2; - if (!sessionToken.isEmpty()) allHeadersSize++; - - Object[] allHeaders = new Object[allHeadersSize]; - - for (int i = 0; i < headersSize; i++) { - allHeaders[i] = getNode.execute(this, headers, i); - } - - allHeaders[headersSize] = RawLanguage.get(this).createRecord(); - records.writeMember(allHeaders[headersSize], "_1", "host"); - records.writeMember(allHeaders[headersSize], "_2", host); - - allHeaders[headersSize + 1] = RawLanguage.get(this).createRecord(); - records.writeMember(allHeaders[headersSize + 1], "_1", "x-amz-date"); - records.writeMember(allHeaders[headersSize + 1], "_2", amzdate); - - if (!sessionToken.isEmpty()) { - allHeaders[headersSize + 2] = RawLanguage.get(this).createRecord(); - records.writeMember(allHeaders[headersSize + 2], "_1", "x-amz-security-token"); - records.writeMember(allHeaders[headersSize + 2], "_2", sessionToken); - } - - Object sortedHeaders = sortNode.execute(this, new ObjectList(allHeaders)); - - for (int i = 0; i < sizeNode.execute(this, sortedHeaders); i++) { - canonicalHeadersBuilder - .append( - ((String) records.readMember(getNode.execute(this, sortedHeaders, i), "_1")) - .toLowerCase()) - .append(":") - .append((String) records.readMember(getNode.execute(this, sortedHeaders, i), "_2")) - .append("\n"); - signedHeadersBuilder - .append( - ((String) records.readMember(getNode.execute(this, sortedHeaders, i), "_1")) - .toLowerCase()) - .append(";"); - } - - for (int i = 0; i < sizeNode.execute(this, headers); i++) { - headersParamsVec.$plus$eq( - new Tuple2<>( - ((String) records.readMember(getNode.execute(this, headers, i), "_1")) - .toLowerCase(), - (String) records.readMember(getNode.execute(this, headers, i), "_2"))); - } - - if (!signedHeadersBuilder.isEmpty()) { - signedHeadersBuilder.deleteCharAt(signedHeadersBuilder.length() - 1); - } - - // List of signed headers: lists the headers in the canonical_headers list, delimited - // with - // ";". - String signedHeaders = signedHeadersBuilder.toString(); - - String payloadHash = - toHexString(getSha256Digest().digest(bodyString.getBytes(StandardCharsets.UTF_8))); - - String canonicalRequest = - method - + "\n" - + path - + "\n" - + canonicalQueryBuilder - + "\n" - + canonicalHeadersBuilder - + "\n" - + signedHeadersBuilder - + "\n" - + payloadHash; - - // Task 2: create string to sign - // Match the algorithm to the hashing algorithm you use, either SHA-1 or SHA-256 - // (recommended). - - String algorithm = "AWS4-HMAC-SHA256"; - String credentialScope = datestamp + "/" + region + "/" + service + "/" + "aws4_request"; - - String stringToSign = - algorithm - + "\n" - + amzdate - + "\n" - + credentialScope - + "\n" - + toHexString( - getSha256Digest().digest(canonicalRequest.getBytes(StandardCharsets.UTF_8))); - - // Task 3: calculate the signature using amazon java example function. - byte[] signingKey = getSignatureKey(secretKey, datestamp, region, service); - String signature = toHexString(hmacSHA256(stringToSign, signingKey)); - - // Task 4: Finally create request using signing information. - String authorizationHeader = - algorithm - + " " - + "Credential=" - + key - + "/" - + credentialScope - + ", " - + "SignedHeaders=" - + signedHeaders - + ", " - + "Signature=" - + signature; - - VectorBuilder> newHeaders = new VectorBuilder<>(); - newHeaders.$plus$eq(new Tuple2<>("x-amz-date", amzdate)); - newHeaders.$plus$eq(new Tuple2<>("Authorization", authorizationHeader)); - if (!sessionToken.isEmpty()) { - newHeaders.$plus$eq(new Tuple2<>("x-amz-security-token", sessionToken)); - } - - VectorBuilder> requestHeaders = - newHeaders.$plus$plus$eq(headersParamsVec.result()); - - // host is added automatically - Map map = new HashMap<>(); - map = - map.$plus( - Tuple2.apply( - new LocationSettingKey("http-method"), new LocationStringSetting(method))); - map = - map.$plus( - Tuple2.apply( - new LocationSettingKey("http-args"), - new LocationKVSetting(urlParamsVec.result()))); + @Cached(inline = true) RecordNodes.AddPropNode addPropNode, + @Cached(inline = true) RecordNodes.GetValueNode getValueNode) { + + Instant t = Instant.now(); + String amzdate = formatterWithTimeZone().format(t); + String datestamp = getDateFormatter().format(t); + + // Task 1: create canonical request with all request settings: method, canonicalUri, + // canonicalQueryString etc. + VectorBuilder> urlParamsVec = new VectorBuilder<>(); + StringBuilder canonicalQueryBuilder = new StringBuilder(); + + Object urlParamsSorted = sortNode.execute(this, urlParams); + + for (int i = 0; i < sizeNode.execute(this, urlParamsSorted); i++) { + canonicalQueryBuilder + .append( + URLEncoder.encode( + (String) + getValueNode.execute(this, getNode.execute(this, urlParamsSorted, i), "_1"), + StandardCharsets.UTF_8)) + .append("=") + .append( + URLEncoder.encode( + (String) + getValueNode.execute(this, getNode.execute(this, urlParamsSorted, i), "_2"), + StandardCharsets.UTF_8)) + .append("&"); + urlParamsVec.$plus$eq( + new Tuple2<>( + (String) getValueNode.execute(this, getNode.execute(this, urlParamsSorted, i), "_1"), + (String) + getValueNode.execute(this, getNode.execute(this, urlParamsSorted, i), "_2"))); + } + // remove last '&' + if (!canonicalQueryBuilder.isEmpty()) { + canonicalQueryBuilder.deleteCharAt(canonicalQueryBuilder.length() - 1); + } + + // Create the canonical headers and signed headers. + // Header names must be trimmed and lowercase, and sorted in code point order from + // low to high. Note that there is a trailing \n. + // Note: The request can include any headers; canonical_headers and signed_headers lists + // those that you want to be included in the hash of the request. "Host" and + // "x-amz-date" are + // always required. + StringBuilder canonicalHeadersBuilder = new StringBuilder(); + StringBuilder signedHeadersBuilder = new StringBuilder(); + VectorBuilder> headersParamsVec = new VectorBuilder<>(); + + int headersSize = (int) sizeNode.execute(this, headers); + // Adding space for host and "x-amz-date", "host" and "x-amz-security-token" if it is + // defined + int allHeadersSize = headersSize + 2; + if (!sessionToken.isEmpty()) allHeadersSize++; + + Object[] allHeaders = new Object[allHeadersSize]; + + for (int i = 0; i < headersSize; i++) { + allHeaders[i] = getNode.execute(this, headers, i); + } + + allHeaders[headersSize] = RawLanguage.get(this).createPureRecord(); + addPropNode.execute(this, allHeaders[headersSize], "_1", "host", false); + addPropNode.execute(this, allHeaders[headersSize], "_2", host, false); + + allHeaders[headersSize + 1] = RawLanguage.get(this).createPureRecord(); + addPropNode.execute(this, allHeaders[headersSize + 1], "_1", "x-amz-date", false); + addPropNode.execute(this, allHeaders[headersSize + 1], "_2", amzdate, false); + + if (!sessionToken.isEmpty()) { + allHeaders[headersSize + 2] = RawLanguage.get(this).createPureRecord(); + addPropNode.execute(this, allHeaders[headersSize + 2], "_1", "x-amz-security-token", false); + addPropNode.execute(this, allHeaders[headersSize + 2], "_2", sessionToken, false); + } + + Object sortedHeaders = sortNode.execute(this, new ObjectList(allHeaders)); + + for (int i = 0; i < sizeNode.execute(this, sortedHeaders); i++) { + canonicalHeadersBuilder + .append( + getValueNode + .execute(this, getNode.execute(this, sortedHeaders, i), "_1") + .toString() + .toLowerCase()) + .append(":") + .append(getValueNode.execute(this, getNode.execute(this, sortedHeaders, i), "_2")) + .append("\n"); + signedHeadersBuilder + .append( + getValueNode + .execute(this, getNode.execute(this, sortedHeaders, i), "_1") + .toString() + .toLowerCase()) + .append(";"); + } + + for (int i = 0; i < sizeNode.execute(this, headers); i++) { + headersParamsVec.$plus$eq( + new Tuple2<>( + getValueNode + .execute(this, getNode.execute(this, headers, i), "_1") + .toString() + .toLowerCase(), + (String) getValueNode.execute(this, getNode.execute(this, headers, i), "_2"))); + } + + if (!signedHeadersBuilder.isEmpty()) { + signedHeadersBuilder.deleteCharAt(signedHeadersBuilder.length() - 1); + } + + // List of signed headers: lists the headers in the canonical_headers list, delimited + // with + // ";". + String signedHeaders = signedHeadersBuilder.toString(); + + String payloadHash = + toHexString(getSha256Digest().digest(bodyString.getBytes(StandardCharsets.UTF_8))); + + String canonicalRequest = + method + + "\n" + + path + + "\n" + + canonicalQueryBuilder + + "\n" + + canonicalHeadersBuilder + + "\n" + + signedHeadersBuilder + + "\n" + + payloadHash; + + // Task 2: create string to sign + // Match the algorithm to the hashing algorithm you use, either SHA-1 or SHA-256 + // (recommended). + + String algorithm = "AWS4-HMAC-SHA256"; + String credentialScope = datestamp + "/" + region + "/" + service + "/" + "aws4_request"; + + String stringToSign = + algorithm + + "\n" + + amzdate + + "\n" + + credentialScope + + "\n" + + toHexString( + getSha256Digest().digest(canonicalRequest.getBytes(StandardCharsets.UTF_8))); + + // Task 3: calculate the signature using amazon java example function. + byte[] signingKey = getSignatureKey(secretKey, datestamp, region, service); + String signature = toHexString(hmacSHA256(stringToSign, signingKey)); + + // Task 4: Finally create request using signing information. + String authorizationHeader = + algorithm + + " " + + "Credential=" + + key + + "/" + + credentialScope + + ", " + + "SignedHeaders=" + + signedHeaders + + ", " + + "Signature=" + + signature; + + VectorBuilder> newHeaders = new VectorBuilder<>(); + newHeaders.$plus$eq(new Tuple2<>("x-amz-date", amzdate)); + newHeaders.$plus$eq(new Tuple2<>("Authorization", authorizationHeader)); + if (!sessionToken.isEmpty()) { + newHeaders.$plus$eq(new Tuple2<>("x-amz-security-token", sessionToken)); + } + + VectorBuilder> requestHeaders = + newHeaders.$plus$plus$eq(headersParamsVec.result()); + + // host is added automatically + Map map = new HashMap<>(); + map = + map.$plus( + Tuple2.apply(new LocationSettingKey("http-method"), new LocationStringSetting(method))); + map = + map.$plus( + Tuple2.apply( + new LocationSettingKey("http-args"), new LocationKVSetting(urlParamsVec.result()))); + map = + map.$plus( + Tuple2.apply( + new LocationSettingKey("http-headers"), + new LocationKVSetting(requestHeaders.result()))); + + if (!bodyString.isEmpty()) { map = map.$plus( Tuple2.apply( - new LocationSettingKey("http-headers"), - new LocationKVSetting(requestHeaders.result()))); - - if (!bodyString.isEmpty()) { - map = - map.$plus( - Tuple2.apply( - new LocationSettingKey("http-body-string"), - new LocationStringSetting(bodyString))); - } - - String url = "https://" + host + "/" + path.replaceAll("^/+", ""); - - return new LocationObject(url, map); - } catch (UnsupportedMessageException - | UnknownIdentifierException - | UnsupportedTypeException e) { - throw new RawTruffleInternalErrorException(e); + new LocationSettingKey("http-body-string"), + new LocationStringSetting(bodyString))); } + + String url = "https://" + host + "/" + path.replaceAll("^/+", ""); + + return new LocationObject(url, map); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/binary_package/BinaryReadNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/binary_package/BinaryReadNode.java index 6c79af4eb..aaaa5f769 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/binary_package/BinaryReadNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/binary_package/BinaryReadNode.java @@ -13,15 +13,15 @@ package raw.runtime.truffle.ast.expressions.builtin.binary_package; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import java.io.IOException; import java.io.InputStream; import org.apache.commons.io.IOUtils; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawContext; import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; +import raw.runtime.truffle.runtime.generator.collection.StaticInitializers; import raw.runtime.truffle.runtime.primitives.BinaryObject; import raw.runtime.truffle.runtime.primitives.ErrorObject; import raw.runtime.truffle.runtime.primitives.LocationObject; @@ -30,12 +30,15 @@ @NodeInfo(shortName = "Binary.Read") @NodeChild(value = "binary") +@ImportStatic(StaticInitializers.class) public abstract class BinaryReadNode extends ExpressionNode { @Specialization @TruffleBoundary - protected Object doExecute(LocationObject locationObject) { - SourceContext context = RawContext.get(this).getSourceContext(); + protected Object doExecute( + LocationObject locationObject, + @Bind("$node") Node thisNode, + @Cached(value = "getSourceContext(thisNode)", neverDefault = true) SourceContext context) { InputStream stream = null; try { stream = (new TruffleInputStream(locationObject, context)).getInputStream(); diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/environment_package/EnvironmentParameterNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/environment_package/EnvironmentParameterNode.java index a9e98c2ba..75900a970 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/environment_package/EnvironmentParameterNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/environment_package/EnvironmentParameterNode.java @@ -18,14 +18,17 @@ import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.UnknownIdentifierException; import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import raw.compiler.rql2.source.Rql2Type; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.RawContext; import raw.runtime.truffle.ast.TypeGuards; +import raw.runtime.truffle.runtime.generator.collection.StaticInitializers; import raw.runtime.truffle.runtime.primitives.*; -@ImportStatic(value = TypeGuards.class) +@ImportStatic(value = {TypeGuards.class, StaticInitializers.class}) @NodeInfo(shortName = "Environment.Parameter") @NodeChild(value = "key") @NodeField(name = "paramType", type = Rql2Type.class) @@ -34,81 +37,199 @@ public abstract class EnvironmentParameterNode extends ExpressionNode { @Idempotent protected abstract Rql2Type getParamType(); - @Child private InteropLibrary bindings = insert(InteropLibrary.getFactory().createDispatched(1)); - - private Object getParam(String key) { - TruffleObject polyglotBindings = RawContext.get(this).getPolyglotBindings(); + @Specialization(guards = {"isByteKind(getParamType())"}) + protected byte getByte( + String key, + @Bind("$node") Node thisNode, + @Cached(value = "getRawContext(thisNode)", neverDefault = true) RawContext context, + @CachedLibrary(limit = "3") @Cached.Shared("interop") InteropLibrary bindings) { + TruffleObject polyglotBindings = context.getPolyglotBindings(); assert bindings.hasMembers(polyglotBindings); try { - return bindings.readMember(polyglotBindings, key); + return (byte) bindings.readMember(polyglotBindings, key); } catch (UnsupportedMessageException | UnknownIdentifierException e) { throw new RuntimeException(e); } } - @Specialization(guards = {"isByteKind(getParamType())"}) - protected byte getByte(String key) { - return (byte) getParam(key); - } - @Specialization(guards = {"isShortKind(getParamType())"}) - protected short getShort(String key) { - return (short) getParam(key); + protected short getShort( + String key, + @Bind("$node") Node thisNode, + @Cached(value = "getRawContext(thisNode)", neverDefault = true) RawContext context, + @CachedLibrary(limit = "3") @Cached.Shared("interop") InteropLibrary bindings) { + TruffleObject polyglotBindings = context.getPolyglotBindings(); + assert bindings.hasMembers(polyglotBindings); + try { + return (short) bindings.readMember(polyglotBindings, key); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw new RuntimeException(e); + } } @Specialization(guards = {"isIntKind(getParamType())"}) - protected int getInt(String key) { - return (int) getParam(key); + protected int getInt( + String key, + @Bind("$node") Node thisNode, + @Cached(value = "getRawContext(thisNode)", neverDefault = true) RawContext context, + @CachedLibrary(limit = "3") @Cached.Shared("interop") InteropLibrary bindings) { + TruffleObject polyglotBindings = context.getPolyglotBindings(); + assert bindings.hasMembers(polyglotBindings); + try { + return (int) bindings.readMember(polyglotBindings, key); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw new RuntimeException(e); + } } @Specialization(guards = {"isLongKind(getParamType())"}) - protected long getLong(String key) { - return (long) getParam(key); + protected long getLong( + String key, + @Bind("$node") Node thisNode, + @Cached(value = "getRawContext(thisNode)", neverDefault = true) RawContext context, + @CachedLibrary(limit = "3") @Cached.Shared("interop") InteropLibrary bindings) { + TruffleObject polyglotBindings = context.getPolyglotBindings(); + assert bindings.hasMembers(polyglotBindings); + try { + return (long) bindings.readMember(polyglotBindings, key); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw new RuntimeException(e); + } } @Specialization(guards = {"isFloatKind(getParamType())"}) - protected float getFloat(String key) { - return (float) getParam(key); + protected float getFloat( + String key, + @Bind("$node") Node thisNode, + @Cached(value = "getRawContext(thisNode)", neverDefault = true) RawContext context, + @CachedLibrary(limit = "3") @Cached.Shared("interop") InteropLibrary bindings) { + TruffleObject polyglotBindings = context.getPolyglotBindings(); + assert bindings.hasMembers(polyglotBindings); + try { + return (float) bindings.readMember(polyglotBindings, key); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw new RuntimeException(e); + } } @Specialization(guards = {"isDoubleKind(getParamType())"}) - protected Double getDouble(String key) { - return (double) getParam(key); + protected Double getDouble( + String key, + @Bind("$node") Node thisNode, + @Cached(value = "getRawContext(thisNode)", neverDefault = true) RawContext context, + @CachedLibrary(limit = "3") @Cached.Shared("interop") InteropLibrary bindings) { + TruffleObject polyglotBindings = context.getPolyglotBindings(); + assert bindings.hasMembers(polyglotBindings); + try { + return (double) bindings.readMember(polyglotBindings, key); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw new RuntimeException(e); + } } @Specialization(guards = {"isDecimalKind(getParamType())"}) - protected DecimalObject getDecimal(String key) { - return (DecimalObject) getParam(key); + protected DecimalObject getDecimal( + String key, + @Bind("$node") Node thisNode, + @Cached(value = "getRawContext(thisNode)", neverDefault = true) RawContext context, + @CachedLibrary(limit = "3") @Cached.Shared("interop") InteropLibrary bindings) { + TruffleObject polyglotBindings = context.getPolyglotBindings(); + assert bindings.hasMembers(polyglotBindings); + try { + return (DecimalObject) bindings.readMember(polyglotBindings, key); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw new RuntimeException(e); + } } @Specialization(guards = {"isBooleanKind(getParamType())"}) - protected boolean getBool(String key) { - return (boolean) getParam(key); + protected boolean getBool( + String key, + @Bind("$node") Node thisNode, + @Cached(value = "getRawContext(thisNode)", neverDefault = true) RawContext context, + @CachedLibrary(limit = "3") @Cached.Shared("interop") InteropLibrary bindings) { + TruffleObject polyglotBindings = context.getPolyglotBindings(); + assert bindings.hasMembers(polyglotBindings); + try { + return (boolean) bindings.readMember(polyglotBindings, key); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw new RuntimeException(e); + } } @Specialization(guards = {"isStringKind(getParamType())"}) - protected String getString(String key) { - return (String) getParam(key); + protected String getString( + String key, + @Bind("$node") Node thisNode, + @Cached(value = "getRawContext(thisNode)", neverDefault = true) RawContext context, + @CachedLibrary(limit = "3") @Cached.Shared("interop") InteropLibrary bindings) { + TruffleObject polyglotBindings = context.getPolyglotBindings(); + assert bindings.hasMembers(polyglotBindings); + try { + return (String) bindings.readMember(polyglotBindings, key); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw new RuntimeException(e); + } } @Specialization(guards = {"isDateKind(getParamType())"}) - protected DateObject getDate(String key) { - return (DateObject) getParam(key); + protected DateObject getDate( + String key, + @Bind("$node") Node thisNode, + @Cached(value = "getRawContext(thisNode)", neverDefault = true) RawContext context, + @CachedLibrary(limit = "3") @Cached.Shared("interop") InteropLibrary bindings) { + TruffleObject polyglotBindings = context.getPolyglotBindings(); + assert bindings.hasMembers(polyglotBindings); + try { + return (DateObject) bindings.readMember(polyglotBindings, key); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw new RuntimeException(e); + } } @Specialization(guards = {"isTimeKind(getParamType())"}) - protected TimeObject getTime(String key) { - return (TimeObject) getParam(key); + protected TimeObject getTime( + String key, + @Bind("$node") Node thisNode, + @Cached(value = "getRawContext(thisNode)", neverDefault = true) RawContext context, + @CachedLibrary(limit = "3") @Cached.Shared("interop") InteropLibrary bindings) { + TruffleObject polyglotBindings = context.getPolyglotBindings(); + assert bindings.hasMembers(polyglotBindings); + try { + return (TimeObject) bindings.readMember(polyglotBindings, key); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw new RuntimeException(e); + } } @Specialization(guards = {"isTimestampKind(getParamType())"}) - protected TimestampObject getTimestamp(String key) { - return (TimestampObject) getParam(key); + protected TimestampObject getTimestamp( + String key, + @Bind("$node") Node thisNode, + @Cached(value = "getRawContext(thisNode)", neverDefault = true) RawContext context, + @CachedLibrary(limit = "3") @Cached.Shared("interop") InteropLibrary bindings) { + TruffleObject polyglotBindings = context.getPolyglotBindings(); + assert bindings.hasMembers(polyglotBindings); + try { + return (TimestampObject) bindings.readMember(polyglotBindings, key); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw new RuntimeException(e); + } } @Specialization(guards = {"isIntervalKind(getParamType())"}) @TruffleBoundary - protected IntervalObject getInterval(String key) { - return (IntervalObject) getParam(key); + protected IntervalObject getInterval( + String key, + @Bind("$node") Node thisNode, + @Cached(value = "getRawContext(thisNode)", neverDefault = true) RawContext context, + @CachedLibrary(limit = "3") @Cached.Shared("interop") InteropLibrary bindings) { + TruffleObject polyglotBindings = context.getPolyglotBindings(); + assert bindings.hasMembers(polyglotBindings); + try { + return (IntervalObject) bindings.readMember(polyglotBindings, key); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw new RuntimeException(e); + } } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/environment_package/EnvironmentScopesNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/environment_package/EnvironmentScopesNode.java index c95ba8993..1d33619d6 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/environment_package/EnvironmentScopesNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/environment_package/EnvironmentScopesNode.java @@ -13,19 +13,25 @@ package raw.runtime.truffle.ast.expressions.builtin.environment_package; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Bind; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawContext; +import raw.runtime.truffle.runtime.generator.collection.StaticInitializers; import raw.runtime.truffle.runtime.list.ObjectList; @NodeInfo(shortName = "Environment.Scopes") +@ImportStatic(StaticInitializers.class) public abstract class EnvironmentScopesNode extends ExpressionNode { @Specialization @TruffleBoundary - protected Object doScopes() { - String[] bl = RawContext.get(this).getScopes(); - return new ObjectList(bl); + protected static Object doScopes( + @Bind("$node") Node thisNode, + @Cached(value = "getScopes(thisNode)", neverDefault = true, dimensions = 1) String[] scopes) { + return new ObjectList(scopes); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/environment_package/EnvironmentSecretNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/environment_package/EnvironmentSecretNode.java index b43f8e066..f573ad194 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/environment_package/EnvironmentSecretNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/environment_package/EnvironmentSecretNode.java @@ -12,23 +12,28 @@ package raw.runtime.truffle.ast.expressions.builtin.environment_package; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import java.util.NoSuchElementException; import raw.creds.api.Secret; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.RawContext; +import raw.runtime.truffle.runtime.generator.collection.StaticInitializers; import raw.runtime.truffle.runtime.primitives.ErrorObject; @NodeInfo(shortName = "Environment.Secret") @NodeChild(value = "key") +@ImportStatic(StaticInitializers.class) public abstract class EnvironmentSecretNode extends ExpressionNode { @Specialization - protected Object doSecret(String key) { + protected static Object doSecret( + String key, + @Bind("$node") Node thisNode, + @Cached(value = "getRawContext(thisNode)", neverDefault = true) RawContext context) { try { - Secret v = RawContext.get(this).getSecret(key); + Secret v = context.getSecret(key); return v.value(); } catch (NoSuchElementException e) { return new ErrorObject("could not find secret " + key); diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/http_package/HttpReadNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/http_package/HttpReadNode.java index cca4c1912..36c270e02 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/http_package/HttpReadNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/http_package/HttpReadNode.java @@ -13,29 +13,22 @@ package raw.runtime.truffle.ast.expressions.builtin.http_package; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.UnknownIdentifierException; -import com.oracle.truffle.api.interop.UnsupportedMessageException; -import com.oracle.truffle.api.interop.UnsupportedTypeException; -import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawContext; import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; +import raw.runtime.truffle.runtime.generator.collection.StaticInitializers; import raw.runtime.truffle.runtime.list.ListNodes; import raw.runtime.truffle.runtime.list.ObjectList; import raw.runtime.truffle.runtime.primitives.BinaryObject; import raw.runtime.truffle.runtime.primitives.ErrorObject; import raw.runtime.truffle.runtime.primitives.LocationObject; -import raw.runtime.truffle.runtime.record.RecordObject; -import raw.runtime.truffle.tryable_nullable.Nullable; +import raw.runtime.truffle.runtime.record.RecordNodes; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; import raw.sources.api.LocationException; import raw.sources.api.SourceContext; import raw.sources.bytestream.http.HttpByteStreamLocation; @@ -47,28 +40,31 @@ @NodeInfo(shortName = "Http.Read") @NodeChild(value = "locationObject") @NodeChild(value = "statusList") +@ImportStatic(StaticInitializers.class) public abstract class HttpReadNode extends ExpressionNode { @Specialization @TruffleBoundary - protected Object doRead( + protected static Object doRead( LocationObject locationObject, Object statusListOption, + @Bind("$node") Node thisNode, + @Cached(inline = true) TryableNullableNodes.IsNullNode isNullNode, @Cached(inline = true) ListNodes.SizeNode sizeNode, @Cached(inline = true) ListNodes.GetNode getNode, - @CachedLibrary(limit = "3") InteropLibrary records) { + @Cached(inline = true) RecordNodes.AddPropNode addPropNode, + @Cached(value = "getSourceContext(thisNode)", neverDefault = true) SourceContext context) { try { - SourceContext context = RawContext.get(this).getSourceContext(); HttpByteStreamLocationBuilder builder = new HttpByteStreamLocationBuilder(); HttpByteStreamLocation location = builder.build(locationObject.getLocationDescription(), context); HttpResult result = location.getHttpResult(); - RecordObject record = RawLanguage.get(this).createRecord(); + Object record = RawLanguage.get(thisNode).createPureRecord(); - if (Nullable.isNotNull(statusListOption)) { - int[] statuses = new int[(int) sizeNode.execute(this, statusListOption)]; + if (!isNullNode.execute(thisNode, statusListOption)) { + int[] statuses = new int[(int) sizeNode.execute(thisNode, statusListOption)]; for (int i = 0; i < statuses.length; i++) { - statuses[i] = (int) getNode.execute(this, statusListOption, i); + statuses[i] = (int) getNode.execute(thisNode, statusListOption, i); } if (Arrays.stream(statuses).noneMatch(status -> status == result.status())) { String method = @@ -87,31 +83,27 @@ protected Object doRead( } } - records.writeMember(record, "status", result.status()); + addPropNode.execute(thisNode, record, "status", result.status(), false); try (InputStream is = result.is()) { - records.writeMember(record, "data", new BinaryObject(is.readAllBytes())); + addPropNode.execute(thisNode, record, "data", new BinaryObject(is.readAllBytes()), false); } IndexedSeq> headerTuples = result.headers().toIndexedSeq(); Object[] headers = new Object[result.headers().size()]; for (int i = 0; i < result.headers().size(); i++) { - headers[i] = RawLanguage.get(this).createRecord(); - records.writeMember(headers[i], "_1", headerTuples.apply(i)._1()); - records.writeMember(headers[i], "_2", headerTuples.apply(i)._2()); + headers[i] = RawLanguage.get(thisNode).createPureRecord(); + addPropNode.execute(thisNode, headers[i], "_1", headerTuples.apply(i)._1(), false); + addPropNode.execute(thisNode, headers[i], "_2", headerTuples.apply(i)._2(), false); } ObjectList headersResult = new ObjectList(headers); - records.writeMember(record, "headers", headersResult); + addPropNode.execute(thisNode, record, "headers", headersResult, false); return record; } catch (LocationException | IOException e) { return new ErrorObject(e.getMessage()); - } catch (UnsupportedMessageException - | UnknownIdentifierException - | UnsupportedTypeException e) { - throw new RawTruffleInternalErrorException(e, this); } } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/location_package/LocationDescribeNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/location_package/LocationDescribeNode.java index 06785ff1c..3372ac360 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/location_package/LocationDescribeNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/location_package/LocationDescribeNode.java @@ -13,13 +13,9 @@ package raw.runtime.truffle.ast.expressions.builtin.location_package; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.UnknownIdentifierException; -import com.oracle.truffle.api.interop.UnsupportedMessageException; -import com.oracle.truffle.api.interop.UnsupportedTypeException; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.NodeInfo; import java.util.ArrayList; import java.util.HashMap; @@ -32,12 +28,11 @@ import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.RawContext; import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; import raw.runtime.truffle.runtime.list.ObjectList; import raw.runtime.truffle.runtime.primitives.ErrorObject; import raw.runtime.truffle.runtime.primitives.LocationObject; import raw.runtime.truffle.runtime.primitives.NullObject; -import raw.runtime.truffle.runtime.record.RecordObject; +import raw.runtime.truffle.runtime.record.RecordNodes; import raw.utils.RawException; import scala.Some; @@ -52,7 +47,7 @@ public abstract class LocationDescribeNode extends ExpressionNode { protected Object doDescribe( LocationObject locationObject, int sampleSize, - @CachedLibrary(limit = "5") InteropLibrary records) { + @Cached(inline = true) RecordNodes.AddPropNode addPropNode) { InferrerService inferrer = RawContext.get(this).getInferrer(); try { // In scala implementation interpreter there is a sample size argument @@ -170,34 +165,34 @@ protected Object doDescribe( String formattedType = SourcePrettyPrinter$.MODULE$.format(rql2Type); - RecordObject record = RawLanguage.get(this).createRecord(); + Object record = RawLanguage.get(this).createPureRecord(); - records.writeMember(record, "format", format); - records.writeMember(record, "comment", comment); - records.writeMember(record, "type", formattedType); + addPropNode.execute(this, record, "format", format, false); + addPropNode.execute(this, record, "comment", comment, false); + addPropNode.execute(this, record, "type", formattedType, false); - Object[] propRecords = new RecordObject[properties.size()]; + Object[] propRecords = new Object[properties.size()]; // properties List keyList = new ArrayList<>(properties.keySet()); for (int i = 0; i < keyList.size(); i++) { - RecordObject rec = RawLanguage.get(this).createRecord(); - records.writeMember(rec, "name", keyList.get(i)); + Object rec = RawLanguage.get(this).createPureRecord(); + addPropNode.execute(this, rec, "name", keyList.get(i), false); if (properties.containsKey(keyList.get(i))) { - records.writeMember(rec, "value", properties.get(keyList.get(i))); + addPropNode.execute(this, rec, "value", properties.get(keyList.get(i)), false); } else { - records.writeMember(rec, "value", NullObject.INSTANCE); + addPropNode.execute(this, rec, "value", NullObject.INSTANCE, false); } propRecords[i] = rec; } ObjectList propList = new ObjectList(propRecords); - records.writeMember(record, "properties", propList); - records.writeMember(record, "is_collection", isCollection); + addPropNode.execute(this, record, "properties", propList, false); + addPropNode.execute(this, record, "is_collection", isCollection, false); // columns if (flatten instanceof Rql2RecordType) { Rql2RecordType rql2RecordType = (Rql2RecordType) flatten; - Object[] columnRecords = new RecordObject[rql2RecordType.atts().length()]; + Object[] columnRecords = new Object[rql2RecordType.atts().length()]; for (int i = 0; i < rql2RecordType.atts().length(); i++) { String typeStr; boolean isNullable; @@ -205,14 +200,16 @@ protected Object doDescribe( (Rql2TypeWithProperties) rql2RecordType.atts().apply(i).tipe(); typeStr = SourcePrettyPrinter$.MODULE$.format(fieldType); isNullable = fieldType.props().contains(Rql2IsNullableTypeProperty.apply()); - RecordObject column = RawLanguage.get(this).createRecord(); - records.writeMember(column, "col_name", rql2RecordType.atts().apply(i).idn()); - records.writeMember(column, "col_type", typeStr); - records.writeMember(column, "nullable", isNullable); + Object column = RawLanguage.get(this).createPureRecord(); + + addPropNode.execute( + this, column, "col_name", rql2RecordType.atts().apply(i).idn(), false); + addPropNode.execute(this, column, "col_type", typeStr, false); + addPropNode.execute(this, column, "nullable", isNullable, false); columnRecords[i] = column; } ObjectList columnList = new ObjectList(columnRecords); - records.writeMember(record, "columns", columnList); + addPropNode.execute(this, record, "columns", columnList, false); } else { String typeStr; boolean isNullable = false; @@ -225,22 +222,17 @@ protected Object doDescribe( } else { typeStr = SourcePrettyPrinter$.MODULE$.format(flatten); } - RecordObject column = RawLanguage.get(this).createRecord(); - records.writeMember(column, "col_name", NullObject.INSTANCE); - records.writeMember(column, "col_type", typeStr); - records.writeMember(column, "nullable", isNullable); + Object column = RawLanguage.get(this).createPureRecord(); + addPropNode.execute(this, column, "col_name", NullObject.INSTANCE, false); + addPropNode.execute(this, column, "col_type", typeStr, false); + addPropNode.execute(this, column, "nullable", isNullable, false); ObjectList columnList = new ObjectList(new Object[] {column}); - records.writeMember(record, "columns", columnList); + addPropNode.execute(this, record, "columns", columnList, false); } - records.writeMember(record, "sampled", sampled); - + addPropNode.execute(this, record, "sampled", sampled, false); return record; } catch (RawException ex) { return new ErrorObject(ex.getMessage()); - } catch (UnsupportedMessageException - | UnknownIdentifierException - | UnsupportedTypeException ex) { - throw new RawTruffleInternalErrorException(ex); } finally { inferrer.stop(); } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/location_package/LocationLlNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/location_package/LocationLlNode.java index 1a1092eb8..d22e72d23 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/location_package/LocationLlNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/location_package/LocationLlNode.java @@ -13,27 +13,22 @@ package raw.runtime.truffle.ast.expressions.builtin.location_package; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.UnknownIdentifierException; -import com.oracle.truffle.api.interop.UnsupportedMessageException; -import com.oracle.truffle.api.interop.UnsupportedTypeException; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.NodeInfo; import java.time.LocalDateTime; import java.time.ZoneOffset; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.RawContext; import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; import raw.runtime.truffle.runtime.list.ObjectList; import raw.runtime.truffle.runtime.list.StringList; import raw.runtime.truffle.runtime.primitives.ErrorObject; import raw.runtime.truffle.runtime.primitives.LocationObject; import raw.runtime.truffle.runtime.primitives.NullObject; import raw.runtime.truffle.runtime.primitives.TimestampObject; -import raw.runtime.truffle.runtime.record.RecordObject; +import raw.runtime.truffle.runtime.record.RecordNodes; import raw.sources.api.SourceContext; import raw.sources.filesystem.api.*; import raw.utils.RawException; @@ -46,7 +41,7 @@ public abstract class LocationLlNode extends ExpressionNode { @Specialization @TruffleBoundary protected Object doLl( - LocationObject locationObject, @CachedLibrary(limit = "5") InteropLibrary records) { + LocationObject locationObject, @Cached(inline = true) RecordNodes.AddPropNode addPropNode) { try { SourceContext context = RawContext.get(this).getSourceContext(); FileSystemLocation fs = @@ -54,66 +49,69 @@ protected Object doLl( IndexedSeq> values = fs.lsWithMetadata().toIndexedSeq(); int size = values.size(); - RecordObject[] result = new RecordObject[size]; + Object[] result = new Object[size]; for (int i = 0; i < size; i++) { - RecordObject topRecord = RawLanguage.get(this).createRecord(); - RecordObject metadata = RawLanguage.get(this).createRecord(); - records.writeMember(topRecord, "url", values.apply(i)._1.rawUri()); + Object topRecord = RawLanguage.get(this).createPureRecord(); + Object metadata = RawLanguage.get(this).createPureRecord(); + addPropNode.execute(this, topRecord, "url", values.apply(i)._1.rawUri(), false); if (values.apply(i)._2 instanceof DirectoryMetadata) { DirectoryMetadata directoryMetadata = (DirectoryMetadata) values.apply(i)._2; if (directoryMetadata.modifiedInstant().isDefined()) { - records.writeMember( + + addPropNode.execute( + this, metadata, "modified", new TimestampObject( LocalDateTime.ofInstant( - directoryMetadata.modifiedInstant().get(), ZoneOffset.UTC))); + directoryMetadata.modifiedInstant().get(), ZoneOffset.UTC)), + false); } else { - records.writeMember(metadata, "modified", NullObject.INSTANCE); + addPropNode.execute(this, metadata, "modified", NullObject.INSTANCE, false); } - records.writeMember(metadata, "size", NullObject.INSTANCE); - records.writeMember(metadata, "blocks", new ObjectList(new Object[0])); + addPropNode.execute(this, metadata, "size", NullObject.INSTANCE, false); + addPropNode.execute(this, metadata, "blocks", new ObjectList(new Object[0]), false); } else { FileMetadata fileMetadata = (FileMetadata) values.apply(i)._2; if (fileMetadata.modifiedInstant().isDefined()) { - records.writeMember( + addPropNode.execute( + this, metadata, "modified", new TimestampObject( - LocalDateTime.ofInstant(fileMetadata.modifiedInstant().get(), ZoneOffset.UTC))); + LocalDateTime.ofInstant(fileMetadata.modifiedInstant().get(), ZoneOffset.UTC)), + false); } else { - records.writeMember(metadata, "modified", NullObject.INSTANCE); + addPropNode.execute(this, metadata, "modified", NullObject.INSTANCE, false); } if (fileMetadata.size().isDefined()) { - records.writeMember(metadata, "size", fileMetadata.size().get()); + addPropNode.execute(this, metadata, "size", fileMetadata.size().get(), false); } else { - records.writeMember(metadata, "size", NullObject.INSTANCE); + addPropNode.execute(this, metadata, "size", NullObject.INSTANCE, false); } int blocksSize = fileMetadata.blocks().length; - RecordObject[] blocks = new RecordObject[blocksSize]; + Object[] blocks = new Object[blocksSize]; for (int j = 0; j < blocksSize; j++) { - RecordObject block = RawLanguage.get(this).createRecord(); - records.writeMember(block, "hosts", new StringList(fileMetadata.blocks()[j].hosts())); - records.writeMember(block, "offset", fileMetadata.blocks()[j].offset()); - records.writeMember(block, "length", fileMetadata.blocks()[j].length()); + Object block = RawLanguage.get(this).createPureRecord(); + + addPropNode.execute( + this, block, "hosts", new StringList(fileMetadata.blocks()[j].hosts()), false); + addPropNode.execute(this, block, "offset", fileMetadata.blocks()[j].offset(), false); + addPropNode.execute(this, block, "length", fileMetadata.blocks()[j].length(), false); blocks[j] = block; } ObjectList blockList = new ObjectList(blocks); - records.writeMember(metadata, "blocks", blockList); + addPropNode.execute(this, metadata, "blocks", blockList, false); } - records.writeMember(topRecord, "metadata", metadata); + addPropNode.execute(this, topRecord, "metadata", metadata, false); result[i] = topRecord; } return new ObjectList(result); } catch (RawException e) { return new ErrorObject(e.getMessage()); - } catch (UnsupportedMessageException - | UnknownIdentifierException - | UnsupportedTypeException e) { - throw new RawTruffleInternalErrorException(e); } } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/string_package/StringReadLinesNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/string_package/StringReadLinesNode.java index 8241971c0..19129155a 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/string_package/StringReadLinesNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/string_package/StringReadLinesNode.java @@ -12,11 +12,11 @@ package raw.runtime.truffle.ast.expressions.builtin.string_package; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawContext; +import raw.runtime.truffle.runtime.generator.collection.StaticInitializers; import raw.runtime.truffle.runtime.iterable.sources.ReadLinesCollection; import raw.runtime.truffle.runtime.primitives.LocationObject; import raw.runtime.truffle.utils.TruffleCharInputStream; @@ -26,10 +26,15 @@ @NodeInfo(shortName = "String.ReadLines") @NodeChild("location") @NodeChild("encoding") +@ImportStatic(StaticInitializers.class) public abstract class StringReadLinesNode extends ExpressionNode { + @Specialization - protected Object doExecute(LocationObject locationObject, String encoding) { - SourceContext context = RawContext.get(this).getSourceContext(); + static Object doExecute( + LocationObject locationObject, + String encoding, + @Bind("$node") Node thisNode, + @Cached(value = "getSourceContext(thisNode)", neverDefault = true) SourceContext context) { TruffleInputStream stream = new TruffleInputStream(locationObject, context); TruffleCharInputStream charStream = new TruffleCharInputStream(stream, encoding); return new ReadLinesCollection(charStream); diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/string_package/StringReadNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/string_package/StringReadNode.java index 5c2f0adf2..fae666c5b 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/string_package/StringReadNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/builtin/string_package/StringReadNode.java @@ -13,15 +13,15 @@ package raw.runtime.truffle.ast.expressions.builtin.string_package; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import java.io.IOException; import java.io.Reader; import org.apache.commons.io.IOUtils; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawContext; import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; +import raw.runtime.truffle.runtime.generator.collection.StaticInitializers; import raw.runtime.truffle.runtime.primitives.ErrorObject; import raw.runtime.truffle.runtime.primitives.LocationObject; import raw.runtime.truffle.utils.TruffleInputStream; @@ -30,11 +30,15 @@ @NodeInfo(shortName = "String.Read") @NodeChild("location") @NodeChild("encoding") +@ImportStatic(StaticInitializers.class) public abstract class StringReadNode extends ExpressionNode { @Specialization @TruffleBoundary - protected Object doExecute(LocationObject locationObject, String encoding) { - SourceContext context = RawContext.get(this).getSourceContext(); + protected static Object doExecute( + LocationObject locationObject, + String encoding, + @Bind("$node") Node thisNode, + @Cached(value = "getSourceContext(thisNode)", neverDefault = true) SourceContext context) { TruffleInputStream stream = new TruffleInputStream(locationObject, context); try { Reader reader = stream.getReader(encoding); diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/function/MethodNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/function/MethodNode.java index f76bc8db9..f34cdb941 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/function/MethodNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/function/MethodNode.java @@ -21,6 +21,7 @@ import raw.runtime.truffle.runtime.function.Closure; import raw.runtime.truffle.runtime.function.Function; import raw.runtime.truffle.runtime.function.Lambda; +import raw.runtime.truffle.runtime.function.RawFunctionRegistry; public final class MethodNode extends ExpressionNode { @@ -34,6 +35,7 @@ public final class MethodNode extends ExpressionNode { private final String name; private final boolean hasFreeVars; private final boolean hasOptionalArgs; + private final RawFunctionRegistry functionRegistry = RawContext.get(this).getFunctionRegistry(); public MethodNode( String name, Function f, ExpressionNode[] defaultArgumentExps, boolean hasFreeVars) { @@ -71,7 +73,7 @@ public Object executeGeneric(VirtualFrame virtualFrame) { } // Only put actual methods in registry if (name != null) { - RawContext.get(this).getFunctionRegistry().register(name, function); + functionRegistry.register(name, function); } } return function; diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/ArrayOperationNodes.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/ArrayOperationNodes.java new file mode 100644 index 000000000..5cd10b0f8 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/ArrayOperationNodes.java @@ -0,0 +1,201 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.expressions.iterable; + +import com.oracle.truffle.api.dsl.GenerateInline; +import com.oracle.truffle.api.dsl.GenerateUncached; +import com.oracle.truffle.api.dsl.ImportStatic; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.NodeInfo; +import java.util.ArrayList; +import raw.compiler.rql2.source.Rql2Type; +import raw.runtime.truffle.ast.TypeGuards; +import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; +import raw.runtime.truffle.runtime.list.*; + +public class ArrayOperationNodes { + + @NodeInfo(shortName = "ArrayOperation.Build") + @GenerateUncached + @GenerateInline + @ImportStatic(TypeGuards.class) + public abstract static class ArrayBuildNode extends Node { + + public abstract Object execute(Node node, Rql2Type resultType, int size); + + @Specialization(guards = "isByteKind(resultType)") + static byte[] buildByte(Node node, Rql2Type resultType, int size) { + return new byte[size]; + } + + @Specialization(guards = "isShortKind(resultType)") + static short[] buildShort(Node node, Rql2Type resultType, int size) { + return new short[size]; + } + + @Specialization(guards = "isIntKind(resultType)") + static int[] buildInt(Node node, Rql2Type resultType, int size) { + return new int[size]; + } + + @Specialization(guards = "isLongKind(resultType)") + static long[] buildLong(Node node, Rql2Type resultType, int size) { + return new long[size]; + } + + @Specialization(guards = "isFloatKind(resultType)") + static float[] buildFloat(Node node, Rql2Type resultType, int size) { + return new float[size]; + } + + @Specialization(guards = "isDoubleKind(resultType)") + static double[] buildDouble(Node node, Rql2Type resultType, int size) { + return new double[size]; + } + + @Specialization(guards = "isBooleanKind(resultType)") + static boolean[] buildBoolean(Node node, Rql2Type resultType, int size) { + return new boolean[size]; + } + + @Specialization(guards = "isStringKind(resultType)") + static String[] buildString(Node node, Rql2Type resultType, int size) { + return new String[size]; + } + + @Specialization + static Object[] buildObject(Node node, Rql2Type resultType, int size) { + return new Object[size]; + } + } + + @NodeInfo(shortName = "ArrayOperation.BuildList") + @GenerateUncached + @GenerateInline + @ImportStatic(TypeGuards.class) + public abstract static class ArrayBuildListNode extends Node { + + public abstract Object execute(Node node, Object array); + + @Specialization + static ByteList buildByte(Node node, byte[] array) { + return new ByteList(array); + } + + @Specialization + static ShortList buildShort(Node node, short[] array) { + return new ShortList(array); + } + + @Specialization + static IntList buildInt(Node node, int[] array) { + return new IntList(array); + } + + @Specialization + static LongList buildLong(Node node, long[] array) { + return new LongList(array); + } + + @Specialization + static FloatList buildFloat(Node node, float[] array) { + return new FloatList(array); + } + + @Specialization + static DoubleList buildDouble(Node node, double[] array) { + return new DoubleList(array); + } + + @Specialization + static BooleanList buildBoolean(Node node, boolean[] array) { + return new BooleanList(array); + } + + @Specialization + static StringList buildString(Node node, String[] array) { + return new StringList(array); + } + + @Specialization + static ObjectList buildObject(Node node, Object[] array) { + return new ObjectList(array); + } + + @Specialization + static RawArrayList buildObject(Node node, Object array) { + try { + @SuppressWarnings("unchecked") + ArrayList arrayList = (ArrayList) array; + return new RawArrayList(arrayList); + } catch (ClassCastException e) { + throw new RawTruffleInternalErrorException(e.getMessage(), e); + } + } + } + + @NodeInfo(shortName = "ArrayOperation.BuildList") + @GenerateUncached + @GenerateInline + @ImportStatic(TypeGuards.class) + public abstract static class ArraySetArrayItemNode extends Node { + + public abstract void execute(Node node, Object array, Object item, int idx); + + @Specialization + static void buildByte(Node node, byte[] array, byte item, int idx) { + array[idx] = item; + } + + @Specialization + static void buildShort(Node node, short[] array, short item, int idx) { + array[idx] = item; + } + + @Specialization + static void buildInt(Node node, int[] array, int item, int idx) { + array[idx] = item; + } + + @Specialization + static void buildLong(Node node, long[] array, long item, int idx) { + array[idx] = item; + } + + @Specialization + static void buildFloat(Node node, float[] array, float item, int idx) { + array[idx] = item; + } + + @Specialization + static void buildDouble(Node node, double[] array, double item, int idx) { + array[idx] = item; + } + + @Specialization + static void buildBoolean(Node node, boolean[] array, boolean item, int idx) { + array[idx] = item; + } + + @Specialization + static void buildString(Node node, String[] array, String item, int idx) { + array[idx] = item; + } + + @Specialization + static void buildObject(Node node, Object[] array, Object item, int idx) { + array[idx] = item; + } + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionCountNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionCountNode.java deleted file mode 100644 index 3ce0f16d5..000000000 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionCountNode.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2023 RAW Labs S.A. - * - * Use of this software is governed by the Business Source License - * included in the file licenses/BSL.txt. - * - * As of the Change Date specified in that file, in accordance with - * the Business Source License, use of this software will be governed - * by the Apache License, Version 2.0, included in the file - * licenses/APL.txt. - */ - -package raw.runtime.truffle.ast.expressions.iterable.collection; - -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.NodeInfo; -import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.runtime.aggregation.AggregationNodes; -import raw.runtime.truffle.runtime.aggregation.SingleAggregation; -import raw.runtime.truffle.runtime.aggregation.aggregator.Aggregators; -import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; -import raw.runtime.truffle.runtime.primitives.ErrorObject; - -// A.Z. Need to cache count somehow -@NodeInfo(shortName = "Collection.Count") -@NodeChild("parent") -public abstract class CollectionCountNode extends ExpressionNode { - - private final Object aggregation = new SingleAggregation(Aggregators.COUNT); - - @Specialization - protected Object doCount( - Object iterable, @Cached(inline = true) AggregationNodes.Aggregate aggregate) { - try { - return aggregate.execute(this, aggregation, iterable); - } catch (RawTruffleRuntimeException ex) { - return new ErrorObject(ex.getMessage()); - } - } -} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionDistinctNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionDistinctNode.java index 5bc67f535..28da731d1 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionDistinctNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionDistinctNode.java @@ -12,28 +12,36 @@ package raw.runtime.truffle.ast.expressions.iterable.collection; -import com.oracle.truffle.api.dsl.Idempotent; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.NodeField; -import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.NodeInfo; import raw.compiler.rql2.source.Rql2TypeWithProperties; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawContext; -import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.runtime.iterable.operations.DistinctCollection; @NodeInfo(shortName = "Collection.Distinct") @NodeChild("input") @NodeField(name = "valueType", type = Rql2TypeWithProperties.class) +@NodeField(name = "generatorSlot", type = int.class) +@NodeField(name = "offHeapDistinctSlot", type = int.class) public abstract class CollectionDistinctNode extends ExpressionNode { @Idempotent protected abstract Rql2TypeWithProperties getValueType(); + @Idempotent + protected abstract int getGeneratorSlot(); + + @Idempotent + protected abstract int getOffHeapDistinctSlot(); + @Specialization - protected Object doDistinct(Object iterable) { + protected Object doDistinct(VirtualFrame frame, Object iterable) { return new DistinctCollection( - iterable, getValueType(), RawLanguage.get(this), RawContext.get(this).getSourceContext()); + iterable, + getValueType(), + frame.materialize(), + getGeneratorSlot(), + getOffHeapDistinctSlot()); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionEquiJoinNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionEquiJoinNode.java index 98b0f02e3..84f28de8f 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionEquiJoinNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionEquiJoinNode.java @@ -16,8 +16,6 @@ import com.oracle.truffle.api.nodes.NodeInfo; import raw.compiler.rql2.source.Rql2TypeWithProperties; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawContext; -import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.runtime.iterable.operations.EquiJoinCollection; @NodeInfo(shortName = "Collection.EquiJoin") @@ -32,6 +30,12 @@ public class CollectionEquiJoinNode extends ExpressionNode { private final Rql2TypeWithProperties rightValueType; private final Rql2TypeWithProperties keyType; + private final int computeNextSlot; + private final int shouldContinueSlot; + private final int generatorSlot; + private final int keyFunctionSlot; + private final int mapSlot; + public CollectionEquiJoinNode( ExpressionNode left, ExpressionNode right, @@ -40,7 +44,12 @@ public CollectionEquiJoinNode( Rql2TypeWithProperties keyType, Rql2TypeWithProperties leftValueType, Rql2TypeWithProperties rightValueType, - ExpressionNode remapFun) { + ExpressionNode remapFun, + int computeNextSlot, + int shouldContinueSlot, + int generatorSlot, + int keyFunctionSlot, + int mapSlot) { this.remapFun = remapFun; this.keyType = keyType; // left @@ -51,6 +60,12 @@ public CollectionEquiJoinNode( this.right = right; this.rightKeyFun = rightKeyFun; this.rightValueType = rightValueType; + + this.computeNextSlot = computeNextSlot; + this.shouldContinueSlot = shouldContinueSlot; + this.generatorSlot = generatorSlot; + this.keyFunctionSlot = keyFunctionSlot; + this.mapSlot = mapSlot; } @Override @@ -60,6 +75,7 @@ public Object executeGeneric(VirtualFrame frame) { Object rightIterable = right.executeGeneric(frame); Object rightKeyF = rightKeyFun.executeGeneric(frame); Object remapF = remapFun.executeGeneric(frame); + return new EquiJoinCollection( leftIterable, leftKeyF, @@ -69,7 +85,11 @@ public Object executeGeneric(VirtualFrame frame) { rightValueType, keyType, remapF, - RawLanguage.get(this), - RawContext.get(this).getSourceContext()); + frame.materialize(), + computeNextSlot, + shouldContinueSlot, + generatorSlot, + keyFunctionSlot, + mapSlot); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionExistsNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionExistsNode.java index 11b564812..2c5be4483 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionExistsNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionExistsNode.java @@ -12,54 +12,84 @@ package raw.runtime.truffle.ast.expressions.iterable.collection; -import com.oracle.truffle.api.dsl.Bind; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.ast.osr.OSRGeneratorNode; +import raw.runtime.truffle.ast.osr.bodies.OSRExistsBodyNode; +import raw.runtime.truffle.ast.osr.conditions.OSRExistsConditionNode; import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; -import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; import raw.runtime.truffle.runtime.iterable.IterableNodes; +import raw.runtime.truffle.runtime.iterable.IterableNodesFactory; import raw.runtime.truffle.runtime.primitives.ErrorObject; -import raw.runtime.truffle.tryable_nullable.TryableNullable; @NodeInfo(shortName = "Collection.Exists") -@NodeChild("iterable") -@NodeChild("function") -public abstract class CollectionExistsNode extends ExpressionNode { +public class CollectionExistsNode extends ExpressionNode { + @Child private ExpressionNode iterableNode; + @Child private ExpressionNode functionNode; + @Child private LoopNode existsLoopNode; - @Specialization - protected static Object doIterable( - Object iterable, - Object function, - @Bind("this") Node thisNode, - @Cached(inline = true) IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) GeneratorNodes.GeneratorInitNode generatorInitNode, - @Cached(inline = true) GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) GeneratorNodes.GeneratorCloseNode generatorCloseNode, - @Cached(inline = true) FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { - Object generator = getGeneratorNode.execute(thisNode, iterable); + @Child + private GeneratorNodes.GeneratorInitNode generatorInitNode = + GeneratorNodesFactory.GeneratorInitNodeGen.create(); + + @Child + private IterableNodes.GetGeneratorNode getGeneratorNode = + IterableNodesFactory.GetGeneratorNodeGen.create(); + + @Child + private GeneratorNodes.GeneratorCloseNode generatorCloseNode = + GeneratorNodesFactory.GeneratorCloseNodeGen.create(); + + private final int generatorSlot; + private final int functionSlot; + private final int predicateResultSlot; + + public CollectionExistsNode( + ExpressionNode iterableNode, + ExpressionNode functionNode, + int generatorSlot, + int functionSlot, + int predicateResultSlot) { + this.iterableNode = iterableNode; + this.functionNode = functionNode; + this.generatorSlot = generatorSlot; + this.functionSlot = functionSlot; + this.predicateResultSlot = predicateResultSlot; + + this.existsLoopNode = + Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRExistsConditionNode(generatorSlot, predicateResultSlot), + new OSRExistsBodyNode(generatorSlot, functionSlot, predicateResultSlot))); + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object function = functionNode.executeGeneric(frame); + Object iterable = iterableNode.executeGeneric(frame); + Object generator = getGeneratorNode.execute(this, iterable); try { - generatorInitNode.execute(thisNode, generator); - while (generatorHasNextNode.execute(thisNode, generator)) { - boolean predicate = - TryableNullable.handlePredicate( - functionExecuteOneNode.execute( - thisNode, function, generatorNextNode.execute(thisNode, generator)), - false); - if (predicate) { - return true; - } - } - return false; + generatorInitNode.execute(this, generator); + frame.setObject(generatorSlot, generator); + frame.setObject(functionSlot, function); + frame.setBoolean(predicateResultSlot, false); + existsLoopNode.execute(frame); + return frame.getBoolean(predicateResultSlot); } catch (RawTruffleRuntimeException ex) { return new ErrorObject(ex.getMessage()); } finally { - generatorCloseNode.execute(thisNode, generator); + generatorCloseNode.execute(this, generator); } } + + @Override + public boolean executeBoolean(VirtualFrame virtualFrame) { + return (boolean) executeGeneric(virtualFrame); + } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionFilterNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionFilterNode.java index 2d9cb1f97..92cf904ca 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionFilterNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionFilterNode.java @@ -12,19 +12,41 @@ package raw.runtime.truffle.ast.expressions.iterable.collection; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.runtime.iterable.operations.FilterCollection; @NodeInfo(shortName = "Collection.Filter") -@NodeChild("iterable") -@NodeChild("predicate") -public abstract class CollectionFilterNode extends ExpressionNode { +public class CollectionFilterNode extends ExpressionNode { - @Specialization - protected Object doFilter(Object iterable, Object predicate) { - return new FilterCollection(iterable, predicate); + @Child private ExpressionNode iterableNode; + + @Child private ExpressionNode predicateNode; + + private final int collectionSlot; + private final int functionSlot; + private final int resultSlot; + + public CollectionFilterNode( + ExpressionNode iterableNode, + ExpressionNode predicateNode, + int collectionSlot, + int functionSlot, + int resultSlot) { + this.iterableNode = iterableNode; + this.predicateNode = predicateNode; + this.collectionSlot = collectionSlot; + this.functionSlot = functionSlot; + this.resultSlot = resultSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object iterable = iterableNode.executeGeneric(frame); + Object predicate = predicateNode.executeGeneric(frame); + + return new FilterCollection( + iterable, predicate, frame.materialize(), collectionSlot, functionSlot, resultSlot); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionGroupByNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionGroupByNode.java index 054b1c091..d9f2de73e 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionGroupByNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionGroupByNode.java @@ -12,15 +12,11 @@ package raw.runtime.truffle.ast.expressions.iterable.collection; -import com.oracle.truffle.api.dsl.Idempotent; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.NodeField; -import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.NodeInfo; import raw.compiler.rql2.source.Rql2TypeWithProperties; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawContext; -import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.runtime.iterable.operations.GroupByCollection; @NodeInfo(shortName = "Collection.GroupBy") @@ -28,6 +24,9 @@ @NodeChild("keyFun") @NodeField(name = "keyType", type = Rql2TypeWithProperties.class) @NodeField(name = "rowType", type = Rql2TypeWithProperties.class) +@NodeField(name = "generatorSlot", type = int.class) +@NodeField(name = "functionSlot", type = int.class) +@NodeField(name = "mapSlot", type = int.class) public abstract class CollectionGroupByNode extends ExpressionNode { @Idempotent @@ -36,14 +35,25 @@ public abstract class CollectionGroupByNode extends ExpressionNode { @Idempotent protected abstract Rql2TypeWithProperties getRowType(); + @Idempotent + protected abstract int getGeneratorSlot(); + + @Idempotent + protected abstract int getFunctionSlot(); + + @Idempotent + protected abstract int getMapSlot(); + @Specialization - protected Object doGroup(Object iterable, Object keyFun) { + protected Object doGroup(VirtualFrame frame, Object iterable, Object keyFun) { return new GroupByCollection( iterable, keyFun, getKeyType(), getRowType(), - RawLanguage.get(this), - RawContext.get(this).getSourceContext()); + frame.materialize(), + getGeneratorSlot(), + getFunctionSlot(), + getMapSlot()); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionJoinNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionJoinNode.java index c26f51438..3b36b7bcf 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionJoinNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionJoinNode.java @@ -12,15 +12,13 @@ package raw.runtime.truffle.ast.expressions.iterable.collection; -import com.oracle.truffle.api.dsl.Idempotent; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.NodeField; -import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import raw.compiler.rql2.source.Rql2TypeWithProperties; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawContext; -import raw.runtime.truffle.RawLanguage; +import raw.runtime.truffle.runtime.generator.collection.StaticInitializers; import raw.runtime.truffle.runtime.iterable.operations.JoinCollection; @NodeInfo(shortName = "Collection.Join") @@ -30,6 +28,12 @@ @NodeChild("predicate") @NodeField(name = "rightType", type = Rql2TypeWithProperties.class) @NodeField(name = "reshapeBeforePredicate", type = Boolean.class) +@NodeField(name = "computeNextSlot", type = int.class) +@NodeField(name = "shouldContinueSlot", type = int.class) +@NodeField(name = "resultSlot", type = int.class) +@NodeField(name = "generatorSlot", type = int.class) +@NodeField(name = "outputBufferSlot", type = int.class) +@ImportStatic(StaticInitializers.class) public abstract class CollectionJoinNode extends ExpressionNode { @Idempotent @@ -38,17 +42,45 @@ public abstract class CollectionJoinNode extends ExpressionNode { @Idempotent protected abstract Boolean getReshapeBeforePredicate(); + @Idempotent + protected abstract int getComputeNextSlot(); + + @Idempotent + protected abstract int getShouldContinueSlot(); + + @Idempotent + protected abstract int getResultSlot(); + + @Idempotent + protected abstract int getGeneratorSlot(); + + @Idempotent + protected abstract int getOutputBufferSlot(); + @Specialization - protected Object doJoin( - Object leftIterable, Object rightIterable, Object remap, Object predicate) { + protected static Object doJoin( + VirtualFrame frame, + Object leftIterable, + Object rightIterable, + Object remap, + Object predicate, + @Bind("$node") Node thisNode, + @Cached(value = "getKryoOutputBufferSize(thisNode)", neverDefault = true) + int kryoOutputBufferSize) { + CollectionJoinNode joinNode = (CollectionJoinNode) thisNode; return new JoinCollection( leftIterable, rightIterable, remap, predicate, - getRightType(), - getReshapeBeforePredicate(), - RawContext.get(this).getSourceContext(), - RawLanguage.get(this)); + joinNode.getRightType(), + joinNode.getReshapeBeforePredicate(), + kryoOutputBufferSize, + frame.materialize(), + joinNode.getComputeNextSlot(), + joinNode.getShouldContinueSlot(), + joinNode.getResultSlot(), + joinNode.getGeneratorSlot(), + joinNode.getOutputBufferSlot()); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionLastNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionLastNode.java deleted file mode 100644 index 8bbca726c..000000000 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionLastNode.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2023 RAW Labs S.A. - * - * Use of this software is governed by the Business Source License - * included in the file licenses/BSL.txt. - * - * As of the Change Date specified in that file, in accordance with - * the Business Source License, use of this software will be governed - * by the Apache License, Version 2.0, included in the file - * licenses/APL.txt. - */ - -package raw.runtime.truffle.ast.expressions.iterable.collection; - -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.NodeInfo; -import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; -import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; -import raw.runtime.truffle.runtime.iterable.IterableNodes; -import raw.runtime.truffle.runtime.primitives.ErrorObject; -import raw.runtime.truffle.runtime.primitives.NullObject; - -@NodeInfo(shortName = "Collection.Last") -@NodeChild("parent") -public abstract class CollectionLastNode extends ExpressionNode { - @Specialization - protected Object doObject( - Object iterable, - @Cached(inline = true) IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) GeneratorNodes.GeneratorInitNode initNode, - @Cached(inline = true) GeneratorNodes.GeneratorHasNextNode hasNextNode, - @Cached(inline = true) GeneratorNodes.GeneratorNextNode nextNode, - @Cached(inline = true) GeneratorNodes.GeneratorCloseNode closeNode) { - Object generator = getGeneratorNode.execute(this, iterable); - try { - initNode.execute(this, generator); - if (!hasNextNode.execute(this, generator)) { - return NullObject.INSTANCE; - } - Object next = nextNode.execute(this, generator); - while (hasNextNode.execute(this, generator)) { - next = nextNode.execute(this, generator); - } - return next; - } catch (RawTruffleRuntimeException e) { - return new ErrorObject(e.getMessage()); - } finally { - closeNode.execute(this, generator); - } - } -} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionMaxNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionMaxNode.java deleted file mode 100644 index cb0eb28be..000000000 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionMaxNode.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2023 RAW Labs S.A. - * - * Use of this software is governed by the Business Source License - * included in the file licenses/BSL.txt. - * - * As of the Change Date specified in that file, in accordance with - * the Business Source License, use of this software will be governed - * by the Apache License, Version 2.0, included in the file - * licenses/APL.txt. - */ - -package raw.runtime.truffle.ast.expressions.iterable.collection; - -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.NodeInfo; -import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.runtime.aggregation.AggregationNodes; -import raw.runtime.truffle.runtime.aggregation.SingleAggregation; -import raw.runtime.truffle.runtime.aggregation.aggregator.Aggregators; -import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; -import raw.runtime.truffle.runtime.primitives.ErrorObject; - -@NodeInfo(shortName = "Collection.Max") -@NodeChild("iterable") -public abstract class CollectionMaxNode extends ExpressionNode { - private final SingleAggregation aggregation = new SingleAggregation(Aggregators.MAX); - - @Specialization - protected Object doCollection( - Object iterable, @Cached(inline = true) AggregationNodes.Aggregate aggregate) { - try { - return aggregate.execute(this, aggregation, iterable); - } catch (RawTruffleRuntimeException ex) { - return new ErrorObject(ex.getMessage()); - } - } -} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionMinNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionMinNode.java deleted file mode 100644 index e99e850b9..000000000 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionMinNode.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2023 RAW Labs S.A. - * - * Use of this software is governed by the Business Source License - * included in the file licenses/BSL.txt. - * - * As of the Change Date specified in that file, in accordance with - * the Business Source License, use of this software will be governed - * by the Apache License, Version 2.0, included in the file - * licenses/APL.txt. - */ - -package raw.runtime.truffle.ast.expressions.iterable.collection; - -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.NodeInfo; -import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.runtime.aggregation.AggregationNodes; -import raw.runtime.truffle.runtime.aggregation.SingleAggregation; -import raw.runtime.truffle.runtime.aggregation.aggregator.Aggregators; -import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; -import raw.runtime.truffle.runtime.primitives.ErrorObject; - -@NodeInfo(shortName = "Collection.Min") -@NodeChild("iterable") -public abstract class CollectionMinNode extends ExpressionNode { - - private final SingleAggregation aggregation = new SingleAggregation(Aggregators.MIN); - - @Specialization - protected Object doCollection( - Object iterable, @Cached(inline = true) AggregationNodes.Aggregate aggregate) { - try { - return aggregate.execute(this, aggregation, iterable); - } catch (RawTruffleRuntimeException ex) { - return new ErrorObject(ex.getMessage()); - } - } -} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionMkStringNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionMkStringNode.java index cf68a967b..1a05b0477 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionMkStringNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionMkStringNode.java @@ -12,35 +12,87 @@ package raw.runtime.truffle.ast.expressions.iterable.collection; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.ast.osr.OSRGeneratorNode; +import raw.runtime.truffle.ast.osr.bodies.OSRCollectionMkStringBodyNode; +import raw.runtime.truffle.ast.osr.conditions.OSRHasNextConditionNode; import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; import raw.runtime.truffle.runtime.iterable.IterableNodes; +import raw.runtime.truffle.runtime.iterable.IterableNodesFactory; import raw.runtime.truffle.runtime.operators.OperatorNodes; +import raw.runtime.truffle.runtime.operators.OperatorNodesFactory; import raw.runtime.truffle.runtime.primitives.ErrorObject; @NodeInfo(shortName = "Collection.MkString") -@NodeChild("iterable") -@NodeChild("start") -@NodeChild("sep") -@NodeChild("end") -public abstract class CollectionMkStringNode extends ExpressionNode { - @Specialization - protected Object doCollection( - Object iterable, - String start, - String sep, - String end, - @Cached(inline = true) OperatorNodes.AddNode add, - @Cached(inline = true) IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) GeneratorNodes.GeneratorHasNextNode hasNextNode, - @Cached(inline = true) GeneratorNodes.GeneratorNextNode nextNode, - @Cached(inline = true) GeneratorNodes.GeneratorInitNode initNode, - @Cached(inline = true) GeneratorNodes.GeneratorCloseNode closeNode) { +public class CollectionMkStringNode extends ExpressionNode { + + @Child private ExpressionNode iterableNode; + @Child private ExpressionNode startNode; + @Child private ExpressionNode sepNode; + @Child private ExpressionNode endNode; + @Child private LoopNode mkStringLoopNode; + + @Child + private GeneratorNodes.GeneratorInitNode initNode = + GeneratorNodesFactory.GeneratorInitNodeGen.create(); + + @Child + private IterableNodes.GetGeneratorNode getGeneratorNode = + IterableNodesFactory.GetGeneratorNodeGen.create(); + + @Child + private GeneratorNodes.GeneratorCloseNode closeNode = + GeneratorNodesFactory.GeneratorCloseNodeGen.create(); + + @Child + private GeneratorNodes.GeneratorHasNextNode hasNextNode = + GeneratorNodesFactory.GeneratorHasNextNodeGen.create(); + + @Child + private GeneratorNodes.GeneratorNextNode nextNode = + GeneratorNodesFactory.GeneratorNextNodeGen.create(); + + @Child private OperatorNodes.AddNode add = OperatorNodesFactory.AddNodeGen.create(); + + private final int generatorSlot; + private final int sepSlot; + private final int resultSlot; + + public CollectionMkStringNode( + ExpressionNode iterableNode, + ExpressionNode startNode, + ExpressionNode sepNode, + ExpressionNode endNode, + int generatorSlot, + int sepSlot, + int resultSlot) { + this.iterableNode = iterableNode; + this.startNode = startNode; + this.sepNode = sepNode; + this.endNode = endNode; + this.generatorSlot = generatorSlot; + this.sepSlot = sepSlot; + this.resultSlot = resultSlot; + this.mkStringLoopNode = + Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRHasNextConditionNode(generatorSlot), + new OSRCollectionMkStringBodyNode(generatorSlot, sepSlot, resultSlot))); + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object iterable = iterableNode.executeGeneric(frame); + String start = (String) startNode.executeGeneric(frame); + String sep = (String) sepNode.executeGeneric(frame); + String end = (String) endNode.executeGeneric(frame); Object generator = getGeneratorNode.execute(this, iterable); try { initNode.execute(this, generator); @@ -51,10 +103,13 @@ protected Object doCollection( Object next = nextNode.execute(this, generator); currentString = (String) add.execute(this, currentString, next); } - while (hasNextNode.execute(this, generator)) { - Object next = nextNode.execute(this, generator); - currentString = (String) add.execute(this, currentString + sep, next); - } + + frame.setObject(generatorSlot, generator); + frame.setObject(sepSlot, sep); + frame.setObject(resultSlot, currentString); + mkStringLoopNode.execute(frame); + currentString = (String) frame.getObject(resultSlot); + return currentString + end; } catch (RawTruffleRuntimeException ex) { return new ErrorObject(ex.getMessage()); diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionOrderByNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionOrderByNode.java index 1bd0088ec..5dc76ab55 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionOrderByNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionOrderByNode.java @@ -18,8 +18,6 @@ import com.oracle.truffle.api.nodes.UnexpectedResultException; import raw.compiler.rql2.source.Rql2TypeWithProperties; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawContext; -import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; import raw.runtime.truffle.runtime.iterable.operations.OrderByCollection; @@ -30,18 +28,27 @@ public class CollectionOrderByNode extends ExpressionNode { @Children private final ExpressionNode[] orderings; private final Rql2TypeWithProperties[] keyTypes; private final Rql2TypeWithProperties valueType; + private final int generatorSlot; + private final int collectionSlot; + private final int offHeapGroupByKeysSlot; public CollectionOrderByNode( ExpressionNode input, ExpressionNode[] keyFuns, ExpressionNode[] orderings, Rql2TypeWithProperties[] keyTypes, - Rql2TypeWithProperties valueType) { + Rql2TypeWithProperties valueType, + int generatorSlot, + int collectionSlot, + int offHeapGroupByKeysSlot) { this.input = input; this.keyFuns = keyFuns; this.orderings = orderings; this.keyTypes = keyTypes; this.valueType = valueType; + this.generatorSlot = generatorSlot; + this.collectionSlot = collectionSlot; + this.offHeapGroupByKeysSlot = offHeapGroupByKeysSlot; } @Override @@ -63,13 +70,16 @@ public Object executeGeneric(VirtualFrame frame) { for (int i = 0; i < this.keyFuns.length; i++) { keyFunctions[i] = this.keyFuns[i].executeGeneric(frame); } + return new OrderByCollection( iterable, keyFunctions, orders, keyTypes, valueType, - RawLanguage.get(this), - RawContext.get(this).getSourceContext()); + frame.materialize(), + generatorSlot, + collectionSlot, + offHeapGroupByKeysSlot); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionSumNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionSumNode.java deleted file mode 100644 index 91bf0e7ee..000000000 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionSumNode.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2023 RAW Labs S.A. - * - * Use of this software is governed by the Business Source License - * included in the file licenses/BSL.txt. - * - * As of the Change Date specified in that file, in accordance with - * the Business Source License, use of this software will be governed - * by the Apache License, Version 2.0, included in the file - * licenses/APL.txt. - */ - -package raw.runtime.truffle.ast.expressions.iterable.collection; - -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.NodeInfo; -import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.runtime.aggregation.AggregationNodes; -import raw.runtime.truffle.runtime.aggregation.SingleAggregation; -import raw.runtime.truffle.runtime.aggregation.aggregator.Aggregators; -import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; -import raw.runtime.truffle.runtime.primitives.ErrorObject; - -@NodeInfo(shortName = "Collection.Sum") -@NodeChild("iterable") -public abstract class CollectionSumNode extends ExpressionNode { - - private final SingleAggregation aggregation = new SingleAggregation(Aggregators.SUM); - - @Specialization - protected Object doCollection( - Object iterable, @Cached(inline = true) AggregationNodes.Aggregate aggregate) { - try { - return aggregate.execute(this, aggregation, iterable); - } catch (RawTruffleRuntimeException ex) { - return new ErrorObject(ex.getMessage()); - } - } -} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionTupleAvgNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionTupleAvgNode.java index b9c7e1d02..a3e9fe1df 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionTupleAvgNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/collection/CollectionTupleAvgNode.java @@ -12,55 +12,45 @@ package raw.runtime.truffle.ast.expressions.iterable.collection; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.UnknownIdentifierException; -import com.oracle.truffle.api.interop.UnsupportedMessageException; -import com.oracle.truffle.api.interop.UnsupportedTypeException; -import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.NodeInfo; import java.math.BigDecimal; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.runtime.aggregation.AggregationNodes; -import raw.runtime.truffle.runtime.aggregation.MultiAggregation; -import raw.runtime.truffle.runtime.aggregation.aggregator.AggregatorNodes; -import raw.runtime.truffle.runtime.aggregation.aggregator.Aggregators; -import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; +import raw.runtime.truffle.ast.expressions.aggregation.*; import raw.runtime.truffle.runtime.primitives.DecimalObject; -import raw.runtime.truffle.runtime.record.RecordObject; +import raw.runtime.truffle.runtime.record.RecordNodes; +import raw.runtime.truffle.runtime.record.RecordNodesFactory; @NodeInfo(shortName = "Collection.TupleAvg") -@NodeChild("iterable") -public abstract class CollectionTupleAvgNode extends ExpressionNode { +public class CollectionTupleAvgNode extends ExpressionNode { + @Child private RecordNodes.AddPropNode addPropNode = RecordNodesFactory.AddPropNodeGen.create(); - private final Object aggregation = - new MultiAggregation(new byte[] {Aggregators.SUM, Aggregators.COUNT}); + @Child AggregateMultipleNode aggregate; + @Child AggregatorNodes.Zero zeroNode = AggregatorNodesFactory.ZeroNodeGen.create(); - @Specialization - protected Object doCollection( - Object iterable, - @Cached(inline = true) AggregationNodes.Aggregate aggregate, - @Cached(inline = true) AggregatorNodes.Zero zero, - @CachedLibrary(limit = "1") InteropLibrary records) { - try { + public CollectionTupleAvgNode(ExpressionNode iterableNode, int generatorSlot, int resultSlot) { + aggregate = + new AggregateMultipleNode( + iterableNode, + new byte[] {Aggregations.SUM, Aggregations.COUNT}, + generatorSlot, + resultSlot); + } + + @Override + public Object executeGeneric(VirtualFrame virtualFrame) { + + Object[] results = (Object[]) aggregate.executeGeneric(virtualFrame); + Object record = RawLanguage.get(this).createPureRecord(); + if ((long) results[1] == (long) zeroNode.execute(this, Aggregations.COUNT)) { + addPropNode.execute(this, record, "sum", zeroNode.execute(this, Aggregations.SUM), false); + } else { - Object[] results = (Object[]) aggregate.execute(this, aggregation, iterable); - RecordObject record = RawLanguage.get(this).createRecord(); - if ((long) results[1] == (long) zero.execute(this, Aggregators.COUNT)) { - records.writeMember(record, "sum", zero.execute(this, Aggregators.SUM)); - } else { - records.writeMember( - record, "sum", new DecimalObject(new BigDecimal(results[0].toString()))); - } - records.writeMember(record, "count", results[1]); - return record; - } catch (UnsupportedMessageException - | UnknownIdentifierException - | UnsupportedTypeException ex) { - throw new RawTruffleInternalErrorException(ex); + addPropNode.execute( + this, record, "sum", new DecimalObject(new BigDecimal(results[0].toString())), false); } + addPropNode.execute(this, record, "count", results[1], false); + return record; } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListExistsNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListExistsNode.java index 73dd89be9..e16a3c277 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListExistsNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListExistsNode.java @@ -12,53 +12,86 @@ package raw.runtime.truffle.ast.expressions.iterable.list; -import com.oracle.truffle.api.dsl.Bind; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; +import raw.runtime.truffle.ast.osr.OSRGeneratorNode; +import raw.runtime.truffle.ast.osr.bodies.OSRExistsBodyNode; +import raw.runtime.truffle.ast.osr.conditions.OSRExistsConditionNode; import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; import raw.runtime.truffle.runtime.iterable.IterableNodes; +import raw.runtime.truffle.runtime.iterable.IterableNodesFactory; import raw.runtime.truffle.runtime.list.ListNodes; -import raw.runtime.truffle.tryable_nullable.TryableNullable; +import raw.runtime.truffle.runtime.list.ListNodesFactory; @NodeInfo(shortName = "List.Exists") -@NodeChild("list") -@NodeChild("function") -public abstract class ListExistsNode extends ExpressionNode { +public class ListExistsNode extends ExpressionNode { - @Specialization - protected static boolean doList( - Object list, - Object function, - @Bind("this") Node thisNode, - @Cached(inline = true) IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) GeneratorNodes.GeneratorInitNode generatorInitNode, - @Cached(inline = true) GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) GeneratorNodes.GeneratorCloseNode generatorCloseNode, - @Cached(inline = true) ListNodes.ToIterableNode toIterableNode, - @Cached(inline = true) FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { - Object iterable = toIterableNode.execute(thisNode, list); - Object generator = getGeneratorNode.execute(thisNode, iterable); + @Child private ExpressionNode listNode; + @Child private ExpressionNode functionNode; + @Child private LoopNode existsLoopNode; + + @Child + private GeneratorNodes.GeneratorInitNode generatorInitNode = + GeneratorNodesFactory.GeneratorInitNodeGen.create(); + + @Child + private IterableNodes.GetGeneratorNode getGeneratorNode = + IterableNodesFactory.GetGeneratorNodeGen.create(); + + @Child + private ListNodes.ToIterableNode toIterableNode = ListNodesFactory.ToIterableNodeGen.create(); + + @Child + private GeneratorNodes.GeneratorCloseNode generatorCloseNode = + GeneratorNodesFactory.GeneratorCloseNodeGen.create(); + + private final int generatorSlot; + private final int functionSlot; + private final int predicateResultSlot; + + public ListExistsNode( + ExpressionNode listNode, + ExpressionNode functionNode, + int generatorSlot, + int functionSlot, + int predicateResultSlot) { + this.listNode = listNode; + this.functionNode = functionNode; + this.generatorSlot = generatorSlot; + this.functionSlot = functionSlot; + this.predicateResultSlot = predicateResultSlot; + this.existsLoopNode = + Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRExistsConditionNode(generatorSlot, predicateResultSlot), + new OSRExistsBodyNode(generatorSlot, functionSlot, predicateResultSlot))); + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object list = listNode.executeGeneric(frame); + Object function = functionNode.executeGeneric(frame); + Object iterable = toIterableNode.execute(this, list); + Object generator = getGeneratorNode.execute(this, iterable); try { - generatorInitNode.execute(thisNode, generator); - while (generatorHasNextNode.execute(thisNode, generator)) { - boolean predicate = - TryableNullable.handlePredicate( - functionExecuteOneNode.execute( - thisNode, function, generatorNextNode.execute(thisNode, generator)), - false); - if (predicate) { - return true; - } - } - return false; + generatorInitNode.execute(this, generator); + frame.setObject(generatorSlot, generator); + frame.setObject(functionSlot, function); + frame.setBoolean(predicateResultSlot, false); + existsLoopNode.execute(frame); + return frame.getBoolean(predicateResultSlot); } finally { - generatorCloseNode.execute(thisNode, generator); + generatorCloseNode.execute(this, generator); } } + + @Override + public boolean executeBoolean(VirtualFrame virtualFrame) { + return (boolean) executeGeneric(virtualFrame); + } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListFilterNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListFilterNode.java index 25e3a6a9b..5f4d632d9 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListFilterNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListFilterNode.java @@ -12,54 +12,122 @@ package raw.runtime.truffle.ast.expressions.iterable.list; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.NodeInfo; import java.util.ArrayList; +import raw.compiler.rql2.source.Rql2Type; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.ast.TypeGuards; -import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; +import raw.runtime.truffle.ast.expressions.iterable.ArrayOperationNodes; +import raw.runtime.truffle.ast.expressions.iterable.ArrayOperationNodesFactory; +import raw.runtime.truffle.ast.osr.OSRGeneratorNode; +import raw.runtime.truffle.ast.osr.bodies.OSRListFilterBodyNode; +import raw.runtime.truffle.ast.osr.bodies.OSRToArrayBodyNode; +import raw.runtime.truffle.ast.osr.conditions.OSRHasNextConditionNode; +import raw.runtime.truffle.ast.osr.conditions.OSRIsLessThanSizeConditionNode; import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; import raw.runtime.truffle.runtime.iterable.IterableNodes; +import raw.runtime.truffle.runtime.iterable.IterableNodesFactory; import raw.runtime.truffle.runtime.list.*; -import raw.runtime.truffle.tryable_nullable.TryableNullable; -@ImportStatic(value = TypeGuards.class) @NodeInfo(shortName = "List.Filter") -@NodeChild("list") -@NodeChild("function") -public abstract class ListFilterNode extends ExpressionNode { +public class ListFilterNode extends ExpressionNode { - @Specialization - protected static RawArrayList doFilter( - Object list, - Object function, - @Bind("this") Node thisNode, - @Cached(inline = true) IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) ListNodes.ToIterableNode toIterableNode, - @Cached(inline = true) GeneratorNodes.GeneratorCloseNode generatorCloseNode, - @Cached(inline = true) GeneratorNodes.GeneratorInitNode generatorInitNode, - @Cached(inline = true) FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { - ArrayList llist = new ArrayList<>(); - Object iterable = toIterableNode.execute(thisNode, list); - Object generator = getGeneratorNode.execute(thisNode, iterable); + @Child private ExpressionNode listNode; + @Child private ExpressionNode functionNode; + @Child private LoopNode filterLoopNode; + @Child private LoopNode toArrayLoopNode; + + @Child + private GeneratorNodes.GeneratorInitNode generatorInitNode = + GeneratorNodesFactory.GeneratorInitNodeGen.create(); + + @Child + private IterableNodes.GetGeneratorNode getGeneratorNode = + IterableNodesFactory.GetGeneratorNodeGen.create(); + + @Child + private ListNodes.ToIterableNode toIterableNode = ListNodesFactory.ToIterableNodeGen.create(); + + @Child + private GeneratorNodes.GeneratorCloseNode generatorCloseNode = + GeneratorNodesFactory.GeneratorCloseNodeGen.create(); + + @Child + ArrayOperationNodes.ArrayBuildNode arrayBuildNode = + ArrayOperationNodesFactory.ArrayBuildNodeGen.create(); + + @Child + ArrayOperationNodes.ArrayBuildListNode arrayBuildListNode = + ArrayOperationNodesFactory.ArrayBuildListNodeGen.create(); + + private final Rql2Type resultType; + + private final int generatorSlot; + private final int functionSlot; + private final int llistSlot; + private final int currentIdxSlot; + private final int listSizeSlot; + private final int resultSlot; + + public ListFilterNode( + ExpressionNode listNode, + ExpressionNode functionNode, + Rql2Type resultType, + int generatorSlot, + int functionSlot, + int listSlot, + int currentIdxSlot, + int listSizeSlot, + int resultSlot) { + this.resultType = resultType; + this.listNode = listNode; + this.functionNode = functionNode; + this.generatorSlot = generatorSlot; + this.functionSlot = functionSlot; + this.llistSlot = listSlot; + this.currentIdxSlot = currentIdxSlot; + this.listSizeSlot = listSizeSlot; + this.resultSlot = resultSlot; + this.filterLoopNode = + Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRHasNextConditionNode(generatorSlot), + new OSRListFilterBodyNode(generatorSlot, functionSlot, listSlot))); + toArrayLoopNode = + Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRIsLessThanSizeConditionNode(currentIdxSlot, listSizeSlot), + new OSRToArrayBodyNode(resultType, listSlot, currentIdxSlot, resultSlot))); + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object list = listNode.executeGeneric(frame); + Object function = functionNode.executeGeneric(frame); + Object iterable = toIterableNode.execute(this, list); + Object generator = getGeneratorNode.execute(this, iterable); try { - generatorInitNode.execute(thisNode, generator); - while (generatorHasNextNode.execute(thisNode, generator)) { - Object v = generatorNextNode.execute(thisNode, generator); - Boolean predicate = null; - predicate = - TryableNullable.handlePredicate( - functionExecuteOneNode.execute(thisNode, function, v), false); - if (predicate) { - llist.add(v); - } - } - return new RawArrayList(llist); + generatorInitNode.execute(this, generator); + frame.setObject(generatorSlot, generator); + frame.setObject(functionSlot, function); + frame.setObject(llistSlot, new ArrayList<>()); + filterLoopNode.execute(frame); + @SuppressWarnings("unchecked") + ArrayList llist = (ArrayList) frame.getObject(llistSlot); + int size = llist.size(); + frame.setObject(resultSlot, arrayBuildNode.execute(this, resultType, size)); + frame.setInt(currentIdxSlot, 0); + frame.setInt(listSizeSlot, size); + frame.setObject(llistSlot, llist); + toArrayLoopNode.execute(frame); + return arrayBuildListNode.execute(this, frame.getObject(resultSlot)); } finally { - generatorCloseNode.execute(thisNode, generator); + generatorCloseNode.execute(this, generator); } } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListFromNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListFromNode.java index a1ba4c87b..2f7e6ec82 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListFromNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListFromNode.java @@ -12,308 +12,115 @@ package raw.runtime.truffle.ast.expressions.iterable.list; +import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.nodes.NodeInfo; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import java.util.ArrayList; import raw.compiler.rql2.source.Rql2Type; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.ast.TypeGuards; +import raw.runtime.truffle.ast.expressions.iterable.ArrayOperationNodes; +import raw.runtime.truffle.ast.expressions.iterable.ArrayOperationNodesFactory; +import raw.runtime.truffle.ast.osr.OSRGeneratorNode; +import raw.runtime.truffle.ast.osr.bodies.OSRListFromBodyNode; +import raw.runtime.truffle.ast.osr.bodies.OSRToArrayBodyNode; +import raw.runtime.truffle.ast.osr.conditions.OSRHasNextConditionNode; +import raw.runtime.truffle.ast.osr.conditions.OSRIsLessThanSizeConditionNode; import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; import raw.runtime.truffle.runtime.iterable.IterableNodes; +import raw.runtime.truffle.runtime.iterable.IterableNodesFactory; import raw.runtime.truffle.runtime.list.*; import raw.runtime.truffle.runtime.primitives.ErrorObject; @ImportStatic(value = TypeGuards.class) -@NodeInfo(shortName = "List.From") -@NodeChild("list") -@NodeField(name = "resultType", type = Rql2Type.class) -public abstract class ListFromNode extends ExpressionNode { +public class ListFromNode extends ExpressionNode { - @Idempotent - protected abstract Rql2Type getResultType(); + @Child private ExpressionNode iterableNode; + @Child private LoopNode listFromLoopNode; + @Child private LoopNode toArrayLoopNode; - @Specialization(guards = {"isByteKind(getResultType())"}) - protected Object doByte( - Object iterable, - @Cached(inline = true) @Cached.Shared("getGeneratorNode") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("initNode") - GeneratorNodes.GeneratorInitNode initGeneratorNode, - @Cached(inline = true) @Cached.Shared("hasNextNode") - GeneratorNodes.GeneratorHasNextNode hasNextGeneratorNode, - @Cached(inline = true) @Cached.Shared("nextNode") - GeneratorNodes.GeneratorNextNode nextGeneratorNode, - @Cached(inline = true) @Cached.Shared("closeNode") - GeneratorNodes.GeneratorCloseNode closeGeneratorNode) { - Object generator = getGeneratorNode.execute(this, iterable); - try { - initGeneratorNode.execute(this, generator); - ArrayList llist = new ArrayList<>(); - while (hasNextGeneratorNode.execute(this, generator)) { - llist.add((byte) nextGeneratorNode.execute(this, generator)); - } - byte[] list = new byte[llist.size()]; - for (int i = 0; i < list.length; i++) { - list[i] = llist.get(i); - } - return new ByteList(list); - } catch (RawTruffleRuntimeException ex) { - return new ErrorObject(ex.getMessage()); - } finally { - closeGeneratorNode.execute(this, generator); - } - } + @Child + private GeneratorNodes.GeneratorInitNode generatorInitNode = + GeneratorNodesFactory.GeneratorInitNodeGen.create(); - @Specialization(guards = {"isShortKind(getResultType())"}) - protected Object doShort( - Object iterable, - @Cached(inline = true) @Cached.Shared("getGeneratorNode") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("initNode") - GeneratorNodes.GeneratorInitNode initGeneratorNode, - @Cached(inline = true) @Cached.Shared("hasNextNode") - GeneratorNodes.GeneratorHasNextNode hasNextGeneratorNode, - @Cached(inline = true) @Cached.Shared("nextNode") - GeneratorNodes.GeneratorNextNode nextGeneratorNode, - @Cached(inline = true) @Cached.Shared("closeNode") - GeneratorNodes.GeneratorCloseNode closeGeneratorNode) { - Object generator = getGeneratorNode.execute(this, iterable); - try { - initGeneratorNode.execute(this, generator); - ArrayList llist = new ArrayList<>(); - while (hasNextGeneratorNode.execute(this, generator)) { - llist.add((short) nextGeneratorNode.execute(this, generator)); - } - short[] list = new short[llist.size()]; - for (int i = 0; i < list.length; i++) { - list[i] = llist.get(i); - } - return new ShortList(list); - } catch (RawTruffleRuntimeException ex) { - return new ErrorObject(ex.getMessage()); - } finally { - closeGeneratorNode.execute(this, generator); - } - } + @Child + private IterableNodes.GetGeneratorNode getGeneratorNode = + IterableNodesFactory.GetGeneratorNodeGen.create(); - @Specialization(guards = {"isIntKind(getResultType())"}) - protected Object doInt( - Object iterable, - @Cached(inline = true) @Cached.Shared("getGeneratorNode") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("initNode") - GeneratorNodes.GeneratorInitNode initGeneratorNode, - @Cached(inline = true) @Cached.Shared("hasNextNode") - GeneratorNodes.GeneratorHasNextNode hasNextGeneratorNode, - @Cached(inline = true) @Cached.Shared("nextNode") - GeneratorNodes.GeneratorNextNode nextGeneratorNode, - @Cached(inline = true) @Cached.Shared("closeNode") - GeneratorNodes.GeneratorCloseNode closeGeneratorNode) { - Object generator = getGeneratorNode.execute(this, iterable); - try { - initGeneratorNode.execute(this, generator); - ArrayList llist = new ArrayList<>(); - while (hasNextGeneratorNode.execute(this, generator)) { - llist.add((int) nextGeneratorNode.execute(this, generator)); - } - int[] list = new int[llist.size()]; - for (int i = 0; i < list.length; i++) { - list[i] = llist.get(i); - } - return new IntList(list); - } catch (RawTruffleRuntimeException ex) { - return new ErrorObject(ex.getMessage()); - } finally { - closeGeneratorNode.execute(this, generator); - } - } + @Child + private GeneratorNodes.GeneratorCloseNode generatorCloseNode = + GeneratorNodesFactory.GeneratorCloseNodeGen.create(); - @Specialization(guards = {"isLongKind(getResultType())"}) - protected Object doLong( - Object iterable, - @Cached(inline = true) @Cached.Shared("getGeneratorNode") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("initNode") - GeneratorNodes.GeneratorInitNode initGeneratorNode, - @Cached(inline = true) @Cached.Shared("hasNextNode") - GeneratorNodes.GeneratorHasNextNode hasNextGeneratorNode, - @Cached(inline = true) @Cached.Shared("nextNode") - GeneratorNodes.GeneratorNextNode nextGeneratorNode, - @Cached(inline = true) @Cached.Shared("closeNode") - GeneratorNodes.GeneratorCloseNode closeGeneratorNode) { - Object generator = getGeneratorNode.execute(this, iterable); - try { - initGeneratorNode.execute(this, generator); - ArrayList llist = new ArrayList<>(); - while (hasNextGeneratorNode.execute(this, generator)) { - llist.add((long) nextGeneratorNode.execute(this, generator)); - } - long[] list = new long[llist.size()]; - for (int i = 0; i < list.length; i++) { - list[i] = llist.get(i); - } - return new LongList(list); - } catch (RawTruffleRuntimeException ex) { - return new ErrorObject(ex.getMessage()); - } finally { - closeGeneratorNode.execute(this, generator); - } - } + @Child + private ArrayOperationNodes.ArrayBuildNode arrayBuildNode = + ArrayOperationNodesFactory.ArrayBuildNodeGen.create(); - @Specialization(guards = {"isFloatKind(getResultType())"}) - protected Object doFloat( - Object iterable, - @Cached(inline = true) @Cached.Shared("getGeneratorNode") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("initNode") - GeneratorNodes.GeneratorInitNode initGeneratorNode, - @Cached(inline = true) @Cached.Shared("hasNextNode") - GeneratorNodes.GeneratorHasNextNode hasNextGeneratorNode, - @Cached(inline = true) @Cached.Shared("nextNode") - GeneratorNodes.GeneratorNextNode nextGeneratorNode, - @Cached(inline = true) @Cached.Shared("closeNode") - GeneratorNodes.GeneratorCloseNode closeGeneratorNode) { - Object generator = getGeneratorNode.execute(this, iterable); - try { - initGeneratorNode.execute(this, generator); - ArrayList llist = new ArrayList<>(); - while (hasNextGeneratorNode.execute(this, generator)) { - llist.add((float) nextGeneratorNode.execute(this, generator)); - } - float[] list = new float[llist.size()]; - for (int i = 0; i < list.length; i++) { - list[i] = llist.get(i); - } - return new FloatList(list); - } catch (RawTruffleRuntimeException ex) { - return new ErrorObject(ex.getMessage()); - } finally { - closeGeneratorNode.execute(this, generator); - } - } + @Child + private ArrayOperationNodes.ArrayBuildListNode arrayBuildListNode = + ArrayOperationNodesFactory.ArrayBuildListNodeGen.create(); - @Specialization(guards = {"isDoubleKind(getResultType())"}) - protected Object doDouble( - Object iterable, - @Cached(inline = true) @Cached.Shared("getGeneratorNode") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("initNode") - GeneratorNodes.GeneratorInitNode initGeneratorNode, - @Cached(inline = true) @Cached.Shared("hasNextNode") - GeneratorNodes.GeneratorHasNextNode hasNextGeneratorNode, - @Cached(inline = true) @Cached.Shared("nextNode") - GeneratorNodes.GeneratorNextNode nextGeneratorNode, - @Cached(inline = true) @Cached.Shared("closeNode") - GeneratorNodes.GeneratorCloseNode closeGeneratorNode) { - Object generator = getGeneratorNode.execute(this, iterable); - try { - initGeneratorNode.execute(this, generator); - ArrayList llist = new ArrayList<>(); - while (hasNextGeneratorNode.execute(this, generator)) { - llist.add((double) nextGeneratorNode.execute(this, generator)); - } - double[] list = new double[llist.size()]; - for (int i = 0; i < list.length; i++) { - list[i] = llist.get(i); - } - return new DoubleList(list); - } catch (RawTruffleRuntimeException ex) { - return new ErrorObject(ex.getMessage()); - } finally { - closeGeneratorNode.execute(this, generator); - } - } + private final Rql2Type resultType; - @Specialization(guards = {"isBooleanKind(getResultType())"}) - protected Object doBoolean( - Object iterable, - @Cached(inline = true) @Cached.Shared("getGeneratorNode") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("initNode") - GeneratorNodes.GeneratorInitNode initGeneratorNode, - @Cached(inline = true) @Cached.Shared("hasNextNode") - GeneratorNodes.GeneratorHasNextNode hasNextGeneratorNode, - @Cached(inline = true) @Cached.Shared("nextNode") - GeneratorNodes.GeneratorNextNode nextGeneratorNode, - @Cached(inline = true) @Cached.Shared("closeNode") - GeneratorNodes.GeneratorCloseNode closeGeneratorNode) { - Object generator = getGeneratorNode.execute(this, iterable); - try { - initGeneratorNode.execute(this, generator); - ArrayList llist = new ArrayList<>(); - while (hasNextGeneratorNode.execute(this, generator)) { - llist.add((boolean) nextGeneratorNode.execute(this, generator)); - } - boolean[] list = new boolean[llist.size()]; - for (int i = 0; i < list.length; i++) { - list[i] = llist.get(i); - } - return new BooleanList(list); - } catch (RawTruffleRuntimeException ex) { - return new ErrorObject(ex.getMessage()); - } finally { - closeGeneratorNode.execute(this, generator); - } - } + private final int generatorSlot; + private final int listSlot; + private final int currentIdxSlot; + private final int listSizeSlot; + private final int resultSlot; - @Specialization(guards = {"isStringKind(getResultType())"}) - protected Object doString( - Object iterable, - @Cached(inline = true) @Cached.Shared("getGeneratorNode") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("initNode") - GeneratorNodes.GeneratorInitNode initGeneratorNode, - @Cached(inline = true) @Cached.Shared("hasNextNode") - GeneratorNodes.GeneratorHasNextNode hasNextGeneratorNode, - @Cached(inline = true) @Cached.Shared("nextNode") - GeneratorNodes.GeneratorNextNode nextGeneratorNode, - @Cached(inline = true) @Cached.Shared("closeNode") - GeneratorNodes.GeneratorCloseNode closeGeneratorNode) { - Object generator = getGeneratorNode.execute(this, iterable); - try { - initGeneratorNode.execute(this, generator); - ArrayList llist = new ArrayList<>(); - while (hasNextGeneratorNode.execute(this, generator)) { - llist.add((String) nextGeneratorNode.execute(this, generator)); - } - String[] list = new String[llist.size()]; - for (int i = 0; i < list.length; i++) { - list[i] = llist.get(i); - } - return new StringList(list); - } catch (RawTruffleRuntimeException e) { - return new ErrorObject(e.getMessage()); - } finally { - closeGeneratorNode.execute(this, generator); - } + public ListFromNode( + ExpressionNode iterableNode, + Rql2Type resultType, + int generatorSlot, + int listSlot, + int currentIdxSlot, + int listSizeSlot, + int resultSlot) { + this.resultType = resultType; + this.iterableNode = iterableNode; + this.generatorSlot = generatorSlot; + this.listSlot = listSlot; + this.currentIdxSlot = currentIdxSlot; + this.listSizeSlot = listSizeSlot; + this.resultSlot = resultSlot; + this.listFromLoopNode = + Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRHasNextConditionNode(generatorSlot), + new OSRListFromBodyNode(generatorSlot, listSlot))); + toArrayLoopNode = + Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRIsLessThanSizeConditionNode(currentIdxSlot, listSizeSlot), + new OSRToArrayBodyNode(resultType, listSlot, currentIdxSlot, resultSlot))); } - @Specialization - protected Object doObject( - Object iterable, - @Cached(inline = true) @Cached.Shared("getGeneratorNode") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("initNode") - GeneratorNodes.GeneratorInitNode initGeneratorNode, - @Cached(inline = true) @Cached.Shared("hasNextNode") - GeneratorNodes.GeneratorHasNextNode hasNextGeneratorNode, - @Cached(inline = true) @Cached.Shared("nextNode") - GeneratorNodes.GeneratorNextNode nextGeneratorNode, - @Cached(inline = true) @Cached.Shared("closeNode") - GeneratorNodes.GeneratorCloseNode closeGeneratorNode) { + @Override + public Object executeGeneric(VirtualFrame frame) { + Object iterable = iterableNode.executeGeneric(frame); Object generator = getGeneratorNode.execute(this, iterable); try { - initGeneratorNode.execute(this, generator); - ArrayList llist = new ArrayList<>(); - while (hasNextGeneratorNode.execute(this, generator)) { - llist.add(nextGeneratorNode.execute(this, generator)); - } - return new RawArrayList(llist); - } catch (RawTruffleRuntimeException e) { - return new ErrorObject(e.getMessage()); + generatorInitNode.execute(this, generator); + frame.setObject(generatorSlot, generator); + frame.setObject(listSlot, new ArrayList<>()); + listFromLoopNode.execute(frame); + @SuppressWarnings("unchecked") + ArrayList llist = (ArrayList) frame.getObject(listSlot); + int size = llist.size(); + frame.setObject(resultSlot, arrayBuildNode.execute(this, resultType, size)); + frame.setInt(currentIdxSlot, 0); + frame.setInt(listSizeSlot, size); + frame.setObject(listSlot, llist); + toArrayLoopNode.execute(frame); + return arrayBuildListNode.execute(this, frame.getObject(resultSlot)); + } catch (RawTruffleRuntimeException ex) { + return new ErrorObject(ex.getMessage()); } finally { - closeGeneratorNode.execute(this, generator); + generatorCloseNode.execute(this, generator); } } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListFromUnsafe.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListFromUnsafe.java index 524ecdaf2..f9099861c 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListFromUnsafe.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListFromUnsafe.java @@ -12,290 +12,108 @@ package raw.runtime.truffle.ast.expressions.iterable.list; -import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.NodeInfo; import java.util.ArrayList; import raw.compiler.rql2.source.Rql2Type; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.ast.TypeGuards; +import raw.runtime.truffle.ast.expressions.iterable.ArrayOperationNodes; +import raw.runtime.truffle.ast.expressions.iterable.ArrayOperationNodesFactory; +import raw.runtime.truffle.ast.osr.OSRGeneratorNode; +import raw.runtime.truffle.ast.osr.bodies.OSRListFromBodyNode; +import raw.runtime.truffle.ast.osr.bodies.OSRToArrayBodyNode; +import raw.runtime.truffle.ast.osr.conditions.OSRHasNextConditionNode; +import raw.runtime.truffle.ast.osr.conditions.OSRIsLessThanSizeConditionNode; import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; import raw.runtime.truffle.runtime.iterable.IterableNodes; +import raw.runtime.truffle.runtime.iterable.IterableNodesFactory; import raw.runtime.truffle.runtime.list.*; -@ImportStatic(value = TypeGuards.class) @NodeInfo(shortName = "List.FromUnsafe") -@NodeChild("list") -@NodeField(name = "resultType", type = Rql2Type.class) -public abstract class ListFromUnsafe extends ExpressionNode { +public class ListFromUnsafe extends ExpressionNode { - @Idempotent - protected abstract Rql2Type getResultType(); + @Child private ExpressionNode iterableNode; + @Child private LoopNode listFromLoopNode; + @Child private LoopNode toArrayLoopNode; - @Specialization(guards = {"isByteKind(getResultType())"}) - protected ByteList doByte( - Object iterable, - @Cached(inline = true) @Cached.Shared("getGenerator") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("initNode") - GeneratorNodes.GeneratorInitNode generatorInitNode, - @Cached(inline = true) @Cached.Shared("hasNextNode") - GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) @Cached.Shared("next") - GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) @Cached.Shared("closeNode") - GeneratorNodes.GeneratorCloseNode generatorCloseNode) { - Object generator = getGeneratorNode.execute(this, iterable); - try { - generatorInitNode.execute(this, generator); - ArrayList llist = new ArrayList<>(); - while (generatorHasNextNode.execute(this, generator)) { - llist.add((byte) generatorNextNode.execute(this, generator)); - } - byte[] list = new byte[llist.size()]; - for (int i = 0; i < list.length; i++) { - list[i] = llist.get(i); - } - return new ByteList(list); - } finally { - generatorCloseNode.execute(this, generator); - } - } + @Child + private GeneratorNodes.GeneratorInitNode generatorInitNode = + GeneratorNodesFactory.GeneratorInitNodeGen.create(); - @Specialization(guards = {"isShortKind(getResultType())"}) - protected ShortList doShort( - Object iterable, - @Cached(inline = true) @Cached.Shared("getGenerator") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("initNode") - GeneratorNodes.GeneratorInitNode generatorInitNode, - @Cached(inline = true) @Cached.Shared("hasNextNode") - GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) @Cached.Shared("next") - GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) @Cached.Shared("closeNode") - GeneratorNodes.GeneratorCloseNode generatorCloseNode) { - Object generator = getGeneratorNode.execute(this, iterable); - try { - generatorInitNode.execute(this, generator); - ArrayList llist = new ArrayList<>(); - while (generatorHasNextNode.execute(this, generator)) { - llist.add((short) generatorNextNode.execute(this, generator)); - } - short[] list = new short[llist.size()]; - for (int i = 0; i < list.length; i++) { - list[i] = llist.get(i); - } - return new ShortList(list); - } finally { - generatorCloseNode.execute(this, generator); - } - } + @Child + private IterableNodes.GetGeneratorNode getGeneratorNode = + IterableNodesFactory.GetGeneratorNodeGen.create(); - @Specialization(guards = {"isIntKind(getResultType())"}) - protected IntList doInt( - Object iterable, - @Cached(inline = true) @Cached.Shared("getGenerator") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("initNode") - GeneratorNodes.GeneratorInitNode generatorInitNode, - @Cached(inline = true) @Cached.Shared("hasNextNode") - GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) @Cached.Shared("next") - GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) @Cached.Shared("closeNode") - GeneratorNodes.GeneratorCloseNode generatorCloseNode) { - Object generator = getGeneratorNode.execute(this, iterable); - try { - generatorInitNode.execute(this, generator); - ArrayList llist = new ArrayList<>(); - while (generatorHasNextNode.execute(this, generator)) { - llist.add((int) generatorNextNode.execute(this, generator)); - } - int[] list = new int[llist.size()]; - for (int i = 0; i < list.length; i++) { - list[i] = llist.get(i); - } - return new IntList(list); - } finally { - generatorCloseNode.execute(this, generator); - } - } + @Child + private GeneratorNodes.GeneratorCloseNode generatorCloseNode = + GeneratorNodesFactory.GeneratorCloseNodeGen.create(); - @Specialization(guards = {"isLongKind(getResultType())"}) - protected LongList doLong( - Object iterable, - @Cached(inline = true) @Cached.Shared("getGenerator") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("initNode") - GeneratorNodes.GeneratorInitNode generatorInitNode, - @Cached(inline = true) @Cached.Shared("hasNextNode") - GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) @Cached.Shared("next") - GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) @Cached.Shared("closeNode") - GeneratorNodes.GeneratorCloseNode generatorCloseNode) { - Object generator = getGeneratorNode.execute(this, iterable); - try { - generatorInitNode.execute(this, generator); - ArrayList llist = new ArrayList<>(); - while (generatorHasNextNode.execute(this, generator)) { - llist.add((long) generatorNextNode.execute(this, generator)); - } - long[] list = new long[llist.size()]; - for (int i = 0; i < list.length; i++) { - list[i] = llist.get(i); - } - return new LongList(list); - } finally { - generatorCloseNode.execute(this, generator); - } - } + @Child + private ArrayOperationNodes.ArrayBuildNode arrayBuildNode = + ArrayOperationNodesFactory.ArrayBuildNodeGen.create(); - @Specialization(guards = {"isFloatKind(getResultType())"}) - protected FloatList doFloat( - Object iterable, - @Cached(inline = true) @Cached.Shared("getGenerator") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("initNode") - GeneratorNodes.GeneratorInitNode generatorInitNode, - @Cached(inline = true) @Cached.Shared("hasNextNode") - GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) @Cached.Shared("next") - GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) @Cached.Shared("closeNode") - GeneratorNodes.GeneratorCloseNode generatorCloseNode) { - Object generator = getGeneratorNode.execute(this, iterable); - try { - generatorInitNode.execute(this, generator); - ArrayList llist = new ArrayList<>(); - while (generatorHasNextNode.execute(this, generator)) { - llist.add((float) generatorNextNode.execute(this, generator)); - } - float[] list = new float[llist.size()]; - for (int i = 0; i < list.length; i++) { - list[i] = llist.get(i); - } - return new FloatList(list); - } finally { - generatorCloseNode.execute(this, generator); - } - } + @Child + private ArrayOperationNodes.ArrayBuildListNode arrayBuildListNode = + ArrayOperationNodesFactory.ArrayBuildListNodeGen.create(); - @Specialization(guards = {"isDoubleKind(getResultType())"}) - protected DoubleList doDouble( - Object iterable, - @Cached(inline = true) @Cached.Shared("getGenerator") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("initNode") - GeneratorNodes.GeneratorInitNode generatorInitNode, - @Cached(inline = true) @Cached.Shared("hasNextNode") - GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) @Cached.Shared("next") - GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) @Cached.Shared("closeNode") - GeneratorNodes.GeneratorCloseNode generatorCloseNode) { - Object generator = getGeneratorNode.execute(this, iterable); - try { - generatorInitNode.execute(this, generator); - ArrayList llist = new ArrayList<>(); - while (generatorHasNextNode.execute(this, generator)) { - llist.add((double) generatorNextNode.execute(this, generator)); - } - double[] list = new double[llist.size()]; - for (int i = 0; i < list.length; i++) { - list[i] = llist.get(i); - } - return new DoubleList(list); - } finally { - generatorCloseNode.execute(this, generator); - } - } + private final Rql2Type resultType; - @Specialization(guards = {"isBooleanKind(getResultType())"}) - protected BooleanList doBoolean( - Object iterable, - @Cached(inline = true) @Cached.Shared("getGenerator") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("initNode") - GeneratorNodes.GeneratorInitNode generatorInitNode, - @Cached(inline = true) @Cached.Shared("hasNextNode") - GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) @Cached.Shared("next") - GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) @Cached.Shared("closeNode") - GeneratorNodes.GeneratorCloseNode generatorCloseNode) { - Object generator = getGeneratorNode.execute(this, iterable); - try { - generatorInitNode.execute(this, generator); - ArrayList llist = new ArrayList<>(); - while (generatorHasNextNode.execute(this, generator)) { - llist.add((boolean) generatorNextNode.execute(this, generator)); - } - boolean[] list = new boolean[llist.size()]; - for (int i = 0; i < list.length; i++) { - list[i] = llist.get(i); - } - return new BooleanList(list); - } finally { - generatorCloseNode.execute(this, generator); - } - } + private final int generatorSlot; + private final int listSlot; + private final int currentIdxSlot; + private final int listSizeSlot; + private final int resultSlot; - @Specialization(guards = {"isStringKind(getResultType())"}) - protected StringList doString( - Object iterable, - @Cached(inline = true) @Cached.Shared("getGenerator") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("initNode") - GeneratorNodes.GeneratorInitNode generatorInitNode, - @Cached(inline = true) @Cached.Shared("hasNextNode") - GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) @Cached.Shared("next") - GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) @Cached.Shared("closeNode") - GeneratorNodes.GeneratorCloseNode generatorCloseNode) { - Object generator = getGeneratorNode.execute(this, iterable); - try { - generatorInitNode.execute(this, generator); - ArrayList llist = new ArrayList<>(); - while (generatorHasNextNode.execute(this, generator)) { - llist.add((String) generatorNextNode.execute(this, generator)); - } - String[] list = new String[llist.size()]; - for (int i = 0; i < list.length; i++) { - list[i] = llist.get(i); - } - return new StringList(list); - } finally { - generatorCloseNode.execute(this, generator); - } + public ListFromUnsafe( + ExpressionNode iterableNode, + Rql2Type resultType, + int generatorSlot, + int listSlot, + int currentIdxSlot, + int listSizeSlot, + int resultSlot) { + this.resultType = resultType; + this.iterableNode = iterableNode; + this.generatorSlot = generatorSlot; + this.listSlot = listSlot; + this.currentIdxSlot = currentIdxSlot; + this.listSizeSlot = listSizeSlot; + this.resultSlot = resultSlot; + this.listFromLoopNode = + Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRHasNextConditionNode(generatorSlot), + new OSRListFromBodyNode(generatorSlot, listSlot))); + toArrayLoopNode = + Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRIsLessThanSizeConditionNode(currentIdxSlot, listSizeSlot), + new OSRToArrayBodyNode(resultType, listSlot, currentIdxSlot, resultSlot))); } - @Specialization - protected ObjectList doObject( - Object iterable, - @Cached(inline = true) @Cached.Shared("getGenerator") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("initNode") - GeneratorNodes.GeneratorInitNode generatorInitNode, - @Cached(inline = true) @Cached.Shared("hasNextNode") - GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) @Cached.Shared("next") - GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) @Cached.Shared("closeNode") - GeneratorNodes.GeneratorCloseNode generatorCloseNode) { + @Override + public Object executeGeneric(VirtualFrame frame) { + Object iterable = iterableNode.executeGeneric(frame); Object generator = getGeneratorNode.execute(this, iterable); try { generatorInitNode.execute(this, generator); - ArrayList llist = new ArrayList<>(); - while (generatorHasNextNode.execute(this, generator)) { - llist.add(generatorNextNode.execute(this, generator)); - } - Object[] list = new Object[llist.size()]; - for (int i = 0; i < list.length; i++) { - list[i] = llist.get(i); - } - return new ObjectList(list); + frame.setObject(generatorSlot, generator); + frame.setObject(listSlot, new ArrayList<>()); + listFromLoopNode.execute(frame); + @SuppressWarnings("unchecked") + ArrayList llist = (ArrayList) frame.getObject(listSlot); + int size = llist.size(); + frame.setObject(resultSlot, arrayBuildNode.execute(this, resultType, size)); + frame.setInt(currentIdxSlot, 0); + frame.setInt(listSizeSlot, size); + frame.setObject(listSlot, llist); + toArrayLoopNode.execute(frame); + return arrayBuildListNode.execute(this, frame.getObject(resultSlot)); } finally { generatorCloseNode.execute(this, generator); } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListGroupByNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListGroupByNode.java index 10bcc62fd..fef79247a 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListGroupByNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListGroupByNode.java @@ -12,85 +12,144 @@ package raw.runtime.truffle.ast.expressions.iterable.list; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.nodes.Node; +import static raw.runtime.truffle.runtime.generator.collection.StaticInitializers.getContextValues; + +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.NodeInfo; import java.util.ArrayList; import raw.compiler.rql2.source.Rql2TypeWithProperties; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawContext; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; +import raw.runtime.truffle.ast.osr.OSRGeneratorNode; +import raw.runtime.truffle.ast.osr.bodies.OSRListEquiJoinInitBodyNode; +import raw.runtime.truffle.ast.osr.bodies.OSRListFromBodyNode; +import raw.runtime.truffle.ast.osr.conditions.OSRHasNextConditionNode; import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.OffHeapNodes; +import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.OffHeapNodesFactory; import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.group_by.OffHeapGroupByKey; import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.record_shaper.RecordShaper; import raw.runtime.truffle.runtime.iterable.IterableNodes; +import raw.runtime.truffle.runtime.iterable.IterableNodesFactory; import raw.runtime.truffle.runtime.list.ListNodes; -import raw.runtime.truffle.runtime.list.ObjectList; -import raw.runtime.truffle.runtime.record.RecordObject; -import raw.sources.api.SourceContext; +import raw.runtime.truffle.runtime.list.ListNodesFactory; +import raw.runtime.truffle.runtime.list.RawArrayList; @NodeInfo(shortName = "List.GroupBy") -@NodeChild("input") -@NodeChild("keyFun") -@NodeField(name = "keyType", type = Rql2TypeWithProperties.class) -@NodeField(name = "rowType", type = Rql2TypeWithProperties.class) -public abstract class ListGroupByNode extends ExpressionNode { - - @Idempotent - public abstract Rql2TypeWithProperties getKeyType(); - - @Idempotent - public abstract Rql2TypeWithProperties getRowType(); - - static final int LIB_LIMIT = 2; - - @Specialization - protected static Object doGroup( - Object input, - Object keyFun, - @Bind("this") Node thisNode, - @Cached(inline = true) IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) GeneratorNodes.GeneratorInitNode initNode, - @Cached(inline = true) GeneratorNodes.GeneratorNextNode nextNode, - @Cached(inline = true) GeneratorNodes.GeneratorHasNextNode hasNextNode, - @Cached(inline = true) GeneratorNodes.GeneratorCloseNode closeNode, - @Cached(inline = true) OffHeapNodes.OffHeapGroupByPutNode putNode, - @Cached(inline = true) OffHeapNodes.OffHeapGeneratorNode generatorNode, - @Cached(inline = true) FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode, - @Cached(inline = true) ListNodes.ToIterableNode toIterableNode) { - Object iterable = toIterableNode.execute(thisNode, input); - SourceContext context = RawContext.get(thisNode).getSourceContext(); +public class ListGroupByNode extends ExpressionNode { + + @Child private ExpressionNode inputNode; + @Child private ExpressionNode keyFunNode; + @Child private LoopNode equiJoinInitLoopNode; + @Child private LoopNode listFromLoopNode; + + @Child + private GeneratorNodes.GeneratorInitNode generatorInitNode = + GeneratorNodesFactory.GeneratorInitNodeGen.create(); + + @Child + private IterableNodes.GetGeneratorNode getGeneratorNode = + IterableNodesFactory.GetGeneratorNodeGen.create(); + + @Child + private ListNodes.ToIterableNode toIterableNode = ListNodesFactory.ToIterableNodeGen.create(); + + @Child + private GeneratorNodes.GeneratorCloseNode generatorCloseNode = + GeneratorNodesFactory.GeneratorCloseNodeGen.create(); + + @Child + OffHeapNodes.OffHeapGeneratorNode generatorNode = + OffHeapNodesFactory.OffHeapGeneratorNodeGen.create(); + + private final Rql2TypeWithProperties rowType; + private final Rql2TypeWithProperties keyType; + + private final int generatorSlot; + private final int keyFunctionSlot; + private final int mapSlot; + private final int listSlot; + private final long maxSize; + private final int kryoOutputBufferSize; + private final int kryoInputBufferSize; + + public ListGroupByNode( + ExpressionNode inputNode, + ExpressionNode keyFunNode, + Rql2TypeWithProperties rowType, + Rql2TypeWithProperties keyType, + int generatorSlot, + int keyFunctionSlot, + int mapSlot, + int listSlot) { + this.inputNode = inputNode; + this.keyFunNode = keyFunNode; + this.rowType = rowType; + this.keyType = keyType; + + this.generatorSlot = generatorSlot; + this.keyFunctionSlot = keyFunctionSlot; + + this.mapSlot = mapSlot; + this.listSlot = listSlot; + this.equiJoinInitLoopNode = + Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRHasNextConditionNode(this.generatorSlot), + new OSRListEquiJoinInitBodyNode( + this.generatorSlot, this.keyFunctionSlot, this.mapSlot))); + + this.listFromLoopNode = + Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRHasNextConditionNode(this.generatorSlot), + new OSRListFromBodyNode(this.generatorSlot, this.listSlot))); + + long[] contextValues = getContextValues(this); + this.maxSize = contextValues[0]; + this.kryoOutputBufferSize = (int) contextValues[1]; + this.kryoInputBufferSize = (int) contextValues[2]; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object input = inputNode.executeGeneric(frame); + Object keyFun = keyFunNode.executeGeneric(frame); + Object iterable = toIterableNode.execute(this, input); OffHeapGroupByKey map = new OffHeapGroupByKey( - ((ListGroupByNode) thisNode).getKeyType(), - ((ListGroupByNode) thisNode).getRowType(), - RawLanguage.get(thisNode), - context, - new RecordShaper(RawLanguage.get(thisNode), true)); - Object generator = getGeneratorNode.execute(thisNode, iterable); + this.keyType, + this.rowType, + new RecordShaper(true), + this.maxSize, + this.kryoOutputBufferSize, + this.kryoInputBufferSize); + Object generator = getGeneratorNode.execute(this, iterable); + try { - initNode.execute(thisNode, generator); - while (hasNextNode.execute(thisNode, generator)) { - Object v = nextNode.execute(thisNode, generator); - Object key = functionExecuteOneNode.execute(thisNode, keyFun, v); - putNode.execute(thisNode, map, key, v); - } + generatorInitNode.execute(this, generator); + frame.setObject(generatorSlot, generator); + frame.setObject(keyFunctionSlot, keyFun); + frame.setObject(mapSlot, map); + equiJoinInitLoopNode.execute(frame); } finally { - closeNode.execute(thisNode, generator); + generatorCloseNode.execute(this, generator); } - ArrayList items = new ArrayList<>(); - Object mapGenerator = generatorNode.execute(thisNode, map); + Object mapGenerator = generatorNode.execute(this, map); try { - initNode.execute(thisNode, mapGenerator); - while (hasNextNode.execute(thisNode, mapGenerator)) { - RecordObject record = (RecordObject) nextNode.execute(thisNode, mapGenerator); - items.add(record); - } + generatorInitNode.execute(this, mapGenerator); + frame.setObject(generatorSlot, mapGenerator); + frame.setObject(listSlot, new ArrayList<>()); + listFromLoopNode.execute(frame); + @SuppressWarnings("unchecked") + ArrayList llist = (ArrayList) frame.getObject(listSlot); + return new RawArrayList(llist); } finally { - closeNode.execute(thisNode, mapGenerator); + generatorCloseNode.execute(this, mapGenerator); } - return new ObjectList(items.toArray()); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListMaxNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListMaxNode.java deleted file mode 100644 index 59be7fb75..000000000 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListMaxNode.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2023 RAW Labs S.A. - * - * Use of this software is governed by the Business Source License - * included in the file licenses/BSL.txt. - * - * As of the Change Date specified in that file, in accordance with - * the Business Source License, use of this software will be governed - * by the Apache License, Version 2.0, included in the file - * licenses/APL.txt. - */ - -package raw.runtime.truffle.ast.expressions.iterable.list; - -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.NodeInfo; -import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.runtime.aggregation.AggregationNodes; -import raw.runtime.truffle.runtime.aggregation.SingleAggregation; -import raw.runtime.truffle.runtime.aggregation.aggregator.Aggregators; -import raw.runtime.truffle.runtime.list.ListNodes; - -@NodeInfo(shortName = "List.Max") -@NodeChild("list") -public abstract class ListMaxNode extends ExpressionNode { - - private final SingleAggregation aggregation = new SingleAggregation(Aggregators.MAX); - - @Specialization - protected Object doCollection( - Object list, - @Cached(inline = true) AggregationNodes.Aggregate aggregate, - @Cached(inline = true) ListNodes.ToIterableNode toIterableNode) { - Object iterable = toIterableNode.execute(this, list); - return aggregate.execute(this, aggregation, iterable); - } -} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListMinNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListMinNode.java deleted file mode 100644 index 24c4a3fe5..000000000 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListMinNode.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2023 RAW Labs S.A. - * - * Use of this software is governed by the Business Source License - * included in the file licenses/BSL.txt. - * - * As of the Change Date specified in that file, in accordance with - * the Business Source License, use of this software will be governed - * by the Apache License, Version 2.0, included in the file - * licenses/APL.txt. - */ - -package raw.runtime.truffle.ast.expressions.iterable.list; - -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.NodeInfo; -import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.runtime.aggregation.AggregationNodes; -import raw.runtime.truffle.runtime.aggregation.SingleAggregation; -import raw.runtime.truffle.runtime.aggregation.aggregator.Aggregators; -import raw.runtime.truffle.runtime.list.ListNodes; - -@NodeInfo(shortName = "List.Min") -@NodeChild("list") -public abstract class ListMinNode extends ExpressionNode { - - private final SingleAggregation aggregation = new SingleAggregation(Aggregators.MIN); - - @Specialization - protected Object doCollection( - Object list, - @Cached(inline = true) AggregationNodes.Aggregate aggregate, - @Cached(inline = true) ListNodes.ToIterableNode toIterableNode) { - Object iterable = toIterableNode.execute(this, list); - return aggregate.execute(this, aggregation, iterable); - } -} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListSumNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListSumNode.java deleted file mode 100644 index 3bd8e8e2e..000000000 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListSumNode.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2023 RAW Labs S.A. - * - * Use of this software is governed by the Business Source License - * included in the file licenses/BSL.txt. - * - * As of the Change Date specified in that file, in accordance with - * the Business Source License, use of this software will be governed - * by the Apache License, Version 2.0, included in the file - * licenses/APL.txt. - */ - -package raw.runtime.truffle.ast.expressions.iterable.list; - -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.NodeInfo; -import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.runtime.aggregation.AggregationNodes; -import raw.runtime.truffle.runtime.aggregation.SingleAggregation; -import raw.runtime.truffle.runtime.aggregation.aggregator.Aggregators; -import raw.runtime.truffle.runtime.list.ListNodes; - -@NodeInfo(shortName = "List.Sum") -@NodeChild("list") -public abstract class ListSumNode extends ExpressionNode { - - private final SingleAggregation aggregation = new SingleAggregation(Aggregators.SUM); - - @Specialization - protected Object doCollection( - Object list, - @Cached(inline = true) AggregationNodes.Aggregate aggregate, - @Cached(inline = true) ListNodes.ToIterableNode toIterableNode) { - Object iterable = toIterableNode.execute(this, list); - return aggregate.execute(this, aggregation, iterable); - } -} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListTransformNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListTransformNode.java index 390a60cae..9a3898b9d 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListTransformNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/iterable/list/ListTransformNode.java @@ -12,332 +12,93 @@ package raw.runtime.truffle.ast.expressions.iterable.list; +import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.NodeInfo; import raw.compiler.rql2.source.*; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.ast.TypeGuards; -import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; -import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; -import raw.runtime.truffle.runtime.iterable.IterableNodes; +import raw.runtime.truffle.ast.expressions.iterable.ArrayOperationNodes; +import raw.runtime.truffle.ast.expressions.iterable.ArrayOperationNodesFactory; +import raw.runtime.truffle.ast.osr.OSRGeneratorNode; +import raw.runtime.truffle.ast.osr.bodies.OSRListTransformBodyNode; +import raw.runtime.truffle.ast.osr.conditions.OSRIsLessThanSizeConditionNode; import raw.runtime.truffle.runtime.list.*; -@ImportStatic(value = TypeGuards.class) @NodeInfo(shortName = "List.Transform") -@NodeChild("list") -@NodeChild("function") -@NodeField(name = "resultType", type = Rql2Type.class) -public abstract class ListTransformNode extends ExpressionNode { +public class ListTransformNode extends ExpressionNode { - static final int LIB_LIMIT = 2; + @Child private ExpressionNode listNode; + @Child private ExpressionNode functionNode; + @Child private LoopNode listTransformLoopNode; - @Idempotent - protected abstract Rql2Type getResultType(); + @Child + private ArrayOperationNodes.ArrayBuildListNode arrayBuildListNode = + ArrayOperationNodesFactory.ArrayBuildListNodeGen.create(); - @Specialization(guards = {"isByteKind(getResultType())"}) - protected static ByteList doByte( - Object list, - Object function, - @Bind("this") Node thisNode, - @Cached(inline = true) @Cached.Shared("getGenerator") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("hasNext") - GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) @Cached.Shared("next") - GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) @Cached.Shared("toIterable") ListNodes.ToIterableNode toIterableNode, - @Cached(inline = true) @Cached.Shared("size") ListNodes.SizeNode sizeNode, - @Cached(inline = true) @Cached.Shared("close") GeneratorNodes.GeneratorCloseNode closeNode, - @Cached(inline = true) @Cached.Shared("init") GeneratorNodes.GeneratorInitNode initNode, - @Cached(inline = true) @Cached.Shared("executeOne") - FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { - Object iterable = toIterableNode.execute(thisNode, list); - Object generator = getGeneratorNode.execute(thisNode, iterable); - try { - initNode.execute(thisNode, generator); - byte[] values = new byte[(int) sizeNode.execute(thisNode, list)]; - int cnt = 0; - while (generatorHasNextNode.execute(thisNode, generator)) { - Object v = generatorNextNode.execute(thisNode, generator); - values[cnt] = (byte) functionExecuteOneNode.execute(thisNode, function, v); - cnt++; - } - return new ByteList(values); - } finally { - closeNode.execute(thisNode, generator); - } - } + @Child + private ArrayOperationNodes.ArrayBuildNode arrayBuildNode = + ArrayOperationNodesFactory.ArrayBuildNodeGen.create(); - @Specialization(guards = {"isShortKind(getResultType())"}) - protected static ShortList doShort( - Object list, - Object function, - @Bind("this") Node thisNode, - @Cached(inline = true) @Cached.Shared("getGenerator") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("hasNext") - GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) @Cached.Shared("next") - GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) @Cached.Shared("toIterable") ListNodes.ToIterableNode toIterableNode, - @Cached(inline = true) @Cached.Shared("size") ListNodes.SizeNode sizeNode, - @Cached(inline = true) @Cached.Shared("close") GeneratorNodes.GeneratorCloseNode closeNode, - @Cached(inline = true) @Cached.Shared("init") GeneratorNodes.GeneratorInitNode initNode, - @Cached(inline = true) @Cached.Shared("executeOne") - FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { - Object iterable = toIterableNode.execute(thisNode, list); - Object generator = getGeneratorNode.execute(thisNode, iterable); - try { - initNode.execute(thisNode, generator); - short[] values = new short[(int) sizeNode.execute(thisNode, list)]; - int cnt = 0; - while (generatorHasNextNode.execute(thisNode, generator)) { - Object v = generatorNextNode.execute(thisNode, generator); - values[cnt] = (short) functionExecuteOneNode.execute(thisNode, function, v); - cnt++; - } - return new ShortList(values); - } finally { - closeNode.execute(thisNode, generator); - } - } + @Child private ListNodes.SizeNode sizeNode = ListNodesFactory.SizeNodeGen.create(); - @Specialization(guards = {"isIntKind(getResultType())"}) - protected static IntList doInt( - Object list, - Object function, - @Bind("this") Node thisNode, - @Cached(inline = true) @Cached.Shared("getGenerator") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("hasNext") - GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) @Cached.Shared("next") - GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) @Cached.Shared("toIterable") ListNodes.ToIterableNode toIterableNode, - @Cached(inline = true) @Cached.Shared("size") ListNodes.SizeNode sizeNode, - @Cached(inline = true) @Cached.Shared("close") GeneratorNodes.GeneratorCloseNode closeNode, - @Cached(inline = true) @Cached.Shared("init") GeneratorNodes.GeneratorInitNode initNode, - @Cached(inline = true) @Cached.Shared("executeOne") - FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { - Object iterable = toIterableNode.execute(thisNode, list); - Object generator = getGeneratorNode.execute(thisNode, iterable); - try { - initNode.execute(thisNode, generator); - int[] values = new int[(int) sizeNode.execute(thisNode, list)]; - int cnt = 0; - while (generatorHasNextNode.execute(thisNode, generator)) { - Object v = generatorNextNode.execute(thisNode, generator); - values[cnt] = (int) functionExecuteOneNode.execute(thisNode, function, v); - cnt++; - } - return new IntList(values); - } finally { - closeNode.execute(thisNode, generator); - } - } + private final Rql2Type resultType; - @Specialization(guards = {"isLongKind(getResultType())"}) - protected static LongList doLong( - Object list, - Object function, - @Bind("this") Node thisNode, - @Cached(inline = true) @Cached.Shared("getGenerator") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("hasNext") - GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) @Cached.Shared("next") - GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) @Cached.Shared("toIterable") ListNodes.ToIterableNode toIterableNode, - @Cached(inline = true) @Cached.Shared("size") ListNodes.SizeNode sizeNode, - @Cached(inline = true) @Cached.Shared("close") GeneratorNodes.GeneratorCloseNode closeNode, - @Cached(inline = true) @Cached.Shared("init") GeneratorNodes.GeneratorInitNode initNode, - @Cached(inline = true) @Cached.Shared("executeOne") - FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { - Object iterable = toIterableNode.execute(thisNode, list); - Object generator = getGeneratorNode.execute(thisNode, iterable); - try { - initNode.execute(thisNode, generator); - long[] values = new long[(int) sizeNode.execute(thisNode, list)]; - int cnt = 0; - while (generatorHasNextNode.execute(thisNode, generator)) { - Object v = generatorNextNode.execute(thisNode, generator); - values[cnt] = (long) functionExecuteOneNode.execute(thisNode, function, v); - cnt++; - } - return new LongList(values); - } finally { - closeNode.execute(thisNode, generator); - } - } + private final int currentIndexSlot; + private final int listSizeSlot; + private final int listSlot; + private final int functionSlot; + private final int resultSlot; - @Specialization(guards = {"isFloatKind(getResultType())"}) - protected static FloatList doFloat( - Object list, - Object function, - @Bind("this") Node thisNode, - @Cached(inline = true) @Cached.Shared("getGenerator") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("hasNext") - GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) @Cached.Shared("next") - GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) @Cached.Shared("toIterable") ListNodes.ToIterableNode toIterableNode, - @Cached(inline = true) @Cached.Shared("size") ListNodes.SizeNode sizeNode, - @Cached(inline = true) @Cached.Shared("close") GeneratorNodes.GeneratorCloseNode closeNode, - @Cached(inline = true) @Cached.Shared("init") GeneratorNodes.GeneratorInitNode initNode, - @Cached(inline = true) @Cached.Shared("executeOne") - FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { - Object iterable = toIterableNode.execute(thisNode, list); - Object generator = getGeneratorNode.execute(thisNode, iterable); - try { - initNode.execute(thisNode, generator); - float[] values = new float[(int) sizeNode.execute(thisNode, list)]; - int cnt = 0; - while (generatorHasNextNode.execute(thisNode, generator)) { - Object v = generatorNextNode.execute(thisNode, generator); - values[cnt] = (float) functionExecuteOneNode.execute(thisNode, function, v); - cnt++; - } - return new FloatList(values); - } finally { - closeNode.execute(thisNode, generator); - } - } + public ListTransformNode( + ExpressionNode listNode, + ExpressionNode functionNode, + Rql2Type resultType, + int listSlot, + int functionSlot, + int currentIndexSlot, + int listSizeSlot, + int resultSlot) { + this.listNode = listNode; + this.functionNode = functionNode; + this.resultType = resultType; + this.listSizeSlot = listSizeSlot; + this.currentIndexSlot = currentIndexSlot; + this.functionSlot = functionSlot; + this.resultSlot = resultSlot; + this.listSlot = listSlot; - @Specialization(guards = {"isDoubleKind(getResultType())"}) - protected static DoubleList doDouble( - Object list, - Object function, - @Bind("this") Node thisNode, - @Cached(inline = true) @Cached.Shared("getGenerator") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("hasNext") - GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) @Cached.Shared("next") - GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) @Cached.Shared("toIterable") ListNodes.ToIterableNode toIterableNode, - @Cached(inline = true) @Cached.Shared("size") ListNodes.SizeNode sizeNode, - @Cached(inline = true) @Cached.Shared("close") GeneratorNodes.GeneratorCloseNode closeNode, - @Cached(inline = true) @Cached.Shared("init") GeneratorNodes.GeneratorInitNode initNode, - @Cached(inline = true) @Cached.Shared("executeOne") - FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { - Object iterable = toIterableNode.execute(thisNode, list); - Object generator = getGeneratorNode.execute(thisNode, iterable); - try { - initNode.execute(thisNode, generator); - double[] values = new double[(int) sizeNode.execute(thisNode, list)]; - int cnt = 0; - while (generatorHasNextNode.execute(thisNode, generator)) { - Object v = generatorNextNode.execute(thisNode, generator); - values[cnt] = (double) functionExecuteOneNode.execute(thisNode, function, v); - cnt++; - } - return new DoubleList(values); - } finally { - closeNode.execute(thisNode, generator); - } + this.listTransformLoopNode = + Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRIsLessThanSizeConditionNode(this.currentIndexSlot, this.listSizeSlot), + new OSRListTransformBodyNode( + this.listSlot, this.functionSlot, this.currentIndexSlot, this.resultSlot))); } - @Specialization(guards = {"isBooleanKind(getResultType())"}) - protected BooleanList doBoolean( - Object list, - Object function, - @Bind("$node") Node thisNode, - @Cached(inline = true) @Cached.Shared("getGenerator") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("hasNext") - GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) @Cached.Shared("next") - GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) @Cached.Shared("toIterable") ListNodes.ToIterableNode toIterableNode, - @Cached(inline = true) @Cached.Shared("size") ListNodes.SizeNode sizeNode, - @Cached(inline = true) @Cached.Shared("close") GeneratorNodes.GeneratorCloseNode closeNode, - @Cached(inline = true) @Cached.Shared("init") GeneratorNodes.GeneratorInitNode initNode, - @Cached(inline = true) @Cached.Shared("executeOne") - FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { - Object iterable = toIterableNode.execute(thisNode, list); - Object generator = getGeneratorNode.execute(thisNode, iterable); - try { - initNode.execute(thisNode, generator); - boolean[] values = new boolean[(int) sizeNode.execute(thisNode, list)]; - int cnt = 0; - while (generatorHasNextNode.execute(thisNode, generator)) { - Object v = generatorNextNode.execute(thisNode, generator); - values[cnt] = (boolean) functionExecuteOneNode.execute(thisNode, function, v); - cnt++; - } - return new BooleanList(values); - } finally { - closeNode.execute(thisNode, generator); - } - } + @Override + public Object executeGeneric(VirtualFrame frame) { + Object list = listNode.executeGeneric(frame); + Object function = functionNode.executeGeneric(frame); + + int listSize = (int) sizeNode.execute(this, list); + + frame.setObject(this.listSlot, list); + frame.setObject(this.functionSlot, function); + frame.setInt(this.currentIndexSlot, 0); + frame.setInt(this.listSizeSlot, listSize); + frame.setObject(this.resultSlot, arrayBuildNode.execute(this, this.resultType, listSize)); + + listTransformLoopNode.execute(frame); + Object result = frame.getObject(this.resultSlot); - @Specialization(guards = {"isStringKind(getResultType())"}) - protected static StringList doString( - Object list, - Object function, - @Bind("this") Node thisNode, - @Cached(inline = true) @Cached.Shared("getGenerator") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("hasNext") - GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) @Cached.Shared("next") - GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) @Cached.Shared("toIterable") ListNodes.ToIterableNode toIterableNode, - @Cached(inline = true) @Cached.Shared("size") ListNodes.SizeNode sizeNode, - @Cached(inline = true) @Cached.Shared("close") GeneratorNodes.GeneratorCloseNode closeNode, - @Cached(inline = true) @Cached.Shared("init") GeneratorNodes.GeneratorInitNode initNode, - @Cached(inline = true) @Cached.Shared("executeOne") - FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { - Object iterable = toIterableNode.execute(thisNode, list); - Object generator = getGeneratorNode.execute(thisNode, iterable); - try { - initNode.execute(thisNode, generator); - String[] values = new String[(int) sizeNode.execute(thisNode, list)]; - int cnt = 0; - while (generatorHasNextNode.execute(thisNode, generator)) { - Object v = generatorNextNode.execute(thisNode, generator); - values[cnt] = (String) functionExecuteOneNode.execute(thisNode, function, v); - cnt++; - } - return new StringList(values); - } finally { - closeNode.execute(thisNode, generator); - } + return arrayBuildListNode.execute(this, result); } - @Specialization - protected ObjectList doObject( - Object list, - Object function, - @Bind("$node") Node thisNode, - @Cached(inline = true) @Cached.Shared("getGenerator") - IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = true) @Cached.Shared("hasNext") - GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached(inline = true) @Cached.Shared("next") - GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached(inline = true) @Cached.Shared("toIterable") ListNodes.ToIterableNode toIterableNode, - @Cached(inline = true) @Cached.Shared("size") ListNodes.SizeNode sizeNode, - @Cached(inline = true) @Cached.Shared("close") GeneratorNodes.GeneratorCloseNode closeNode, - @Cached(inline = true) @Cached.Shared("init") GeneratorNodes.GeneratorInitNode initNode, - @Cached(inline = true) @Cached.Shared("executeOne") - FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { - Object iterable = toIterableNode.execute(thisNode, list); - Object generator = getGeneratorNode.execute(thisNode, iterable); - try { - initNode.execute(thisNode, generator); - Object[] values = new Object[(int) sizeNode.execute(thisNode, list)]; - int cnt = 0; - while (generatorHasNextNode.execute(thisNode, generator)) { - Object v = generatorNextNode.execute(thisNode, generator); - values[cnt] = functionExecuteOneNode.execute(thisNode, function, v); - cnt++; - } - return new ObjectList(values); - } finally { - closeNode.execute(thisNode, generator); - } + @Override + public boolean executeBoolean(VirtualFrame virtualFrame) { + return (boolean) executeGeneric(virtualFrame); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionFlatMapNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionFlatMapNode.java index 4e9f54c0e..e117f49af 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionFlatMapNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionFlatMapNode.java @@ -12,13 +12,12 @@ package raw.runtime.truffle.ast.expressions.option; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.ImportStatic; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; +import raw.runtime.truffle.runtime.primitives.NullObject; import raw.runtime.truffle.tryable_nullable.Nullable; @NodeInfo(shortName = "Option.FlatMap") @@ -27,16 +26,17 @@ @ImportStatic(Nullable.class) public abstract class OptionFlatMapNode extends ExpressionNode { - @Specialization(guards = "isNotNull(option)") - protected Object notNullFlatMap( + @Specialization(guards = "isNull(option)") + protected static Object exec(NullObject option, Object function) { + return option; + } + + @Specialization(guards = "!isNull(option)") + protected static Object exec( Object option, Object function, + @Bind("this") Node thisNode, @Cached(inline = true) FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { - return functionExecuteOneNode.execute(this, function, option); - } - - @Specialization(guards = "isNull(option)") - protected Object optionFlatMap(Object option, Object function) { - return option; + return functionExecuteOneNode.execute(thisNode, function, option); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionGetOrElseNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionGetOrElseNode.java index ad355be42..3b5f71785 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionGetOrElseNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionGetOrElseNode.java @@ -17,6 +17,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.runtime.primitives.NullObject; import raw.runtime.truffle.tryable_nullable.Nullable; @NodeInfo(shortName = "Option.FlatMap") @@ -25,13 +26,13 @@ @ImportStatic(Nullable.class) public abstract class OptionGetOrElseNode extends ExpressionNode { - @Specialization(guards = "isNotNull(option)") - protected Object optionGet(Object option, Object orElse) { - return option; - } - @Specialization(guards = "isNull(option)") - protected Object optionOrElse(Object option, Object orElse) { + protected Object optionOrElse(NullObject option, Object orElse) { return orElse; } + + @Specialization(guards = "!isNull(option)") + protected Object optionGet(Object option, Object orElse) { + return option; + } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionIsDefinedNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionIsDefinedNode.java index 70dbe7daa..efdecdead 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionIsDefinedNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionIsDefinedNode.java @@ -12,18 +12,20 @@ package raw.runtime.truffle.ast.expressions.option; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.tryable_nullable.Nullable; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; @NodeInfo(shortName = "Option.IsDefined") @NodeChild("option") public abstract class OptionIsDefinedNode extends ExpressionNode { @Specialization - protected boolean isDefined(Object option) { - return Nullable.isNotNull(option); + protected boolean isDefined( + Object option, @Cached(inline = true) TryableNullableNodes.IsNullNode isNullNode) { + return !isNullNode.execute(this, option); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionMapNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionMapNode.java index 723f36ee9..cc88f766c 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionMapNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionMapNode.java @@ -12,13 +12,12 @@ package raw.runtime.truffle.ast.expressions.option; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.ImportStatic; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; +import raw.runtime.truffle.runtime.primitives.NullObject; import raw.runtime.truffle.tryable_nullable.Nullable; @NodeInfo(shortName = "Option.Map") @@ -27,16 +26,17 @@ @ImportStatic(Nullable.class) public abstract class OptionMapNode extends ExpressionNode { - @Specialization(guards = "isNotNull(option)") - protected Object optionMapNotNull( + @Specialization(guards = "isNull(option)") + protected static Object optionMapNull(NullObject option, Object function) { + return option; + } + + @Specialization(guards = "!isNull(option)") + protected static Object optionMapNotNull( Object option, Object function, + @Bind("this") Node thisNode, @Cached(inline = true) FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { - return functionExecuteOneNode.execute(this, function, option); - } - - @Specialization(guards = "isNull(option)") - protected Object optionMapNull(Object option, Object function) { - return option; + return functionExecuteOneNode.execute(thisNode, function, option); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionUnsafeGetNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionUnsafeGetNode.java index 2ed36d294..f683afa0b 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionUnsafeGetNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/option/OptionUnsafeGetNode.java @@ -18,19 +18,21 @@ import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.runtime.exceptions.RawTruffleUnexpectedNullException; +import raw.runtime.truffle.runtime.primitives.NullObject; import raw.runtime.truffle.tryable_nullable.Nullable; @NodeInfo(shortName = "Option.UnsafeGet") @NodeChild("option") @ImportStatic(Nullable.class) public abstract class OptionUnsafeGetNode extends ExpressionNode { - @Specialization(guards = "isNotNull(option)") - protected Object doObjectIsNotNull(Object option) { - return option; - } @Specialization(guards = "isNull(option)") - protected Object doObject(Object option) { + protected Object doObject(NullObject option) { throw new RawTruffleUnexpectedNullException(this); } + + @Specialization(guards = "!isNull(option)") + protected Object doObjectIsNotNull(Object option) { + return option; + } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordAddFieldNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordAddFieldNode.java index 78ef3c4be..fa3cd8c40 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordAddFieldNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordAddFieldNode.java @@ -12,39 +12,62 @@ package raw.runtime.truffle.ast.expressions.record; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.interop.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; +import java.util.ArrayList; +import java.util.List; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.runtime.record.RecordNodes; -import raw.runtime.truffle.runtime.record.RecordObject; @NodeInfo(shortName = "Record.AddField") @NodeChild("inRecordNode") @NodeChild("keyNode") @NodeChild("valueNode") +@ImportStatic(RecordStaticInitializers.class) public abstract class RecordAddFieldNode extends ExpressionNode { + public static boolean hasDuplicateKeysWithKey(Object[] keys, Object key) { + List list = new ArrayList<>(List.of(keys)); + list.add(key); + return list.size() != list.stream().distinct().count(); + } + @Specialization - protected Object doAddField( + protected static Object doAddField( Object rec, String newKey, Object newValue, - @Cached(inline = true) RecordNodes.WriteIndexNode writeIndexNode, - @Cached(inline = true) RecordNodes.ReadIndexNode readIndexNode) { - RecordObject record = (RecordObject) rec; - RecordObject newRecord = RawLanguage.get(this).createRecord(); - String[] keys = record.keys(); - int length = keys.length; - String member; - for (int i = 0; i < length; i++) { - member = keys[i]; - writeIndexNode.execute(this, newRecord, i, member, readIndexNode.execute(this, record, i)); + @Bind("$node") Node thisNode, + @Cached(value = "getCachedLanguage(thisNode)", neverDefault = true) RawLanguage lang, + @Cached(inline = true) RecordNodes.GetKeysNode getKeysNode, + @Cached(value = "getKeysNode.execute(thisNode, rec)", neverDefault = true, dimensions = 1) + Object[] objKeys, + @Cached(value = "hasDuplicateKeysWithKey(objKeys, newKey)", neverDefault = false) + boolean hasDuplicateKeys, + @Cached(value = "getValueNode(objKeys.length)", neverDefault = true) + RecordNodes.GetValueNode[] getValueNode, + @Cached(value = "getAddPropNodePlusOne(objKeys.length)", neverDefault = true) + RecordNodes.AddPropNode[] addPropNode) { + + Object result; + if (hasDuplicateKeys) { + result = lang.createDuplicateKeyRecord(); + } else { + result = lang.createPureRecord(); } - writeIndexNode.execute(this, newRecord, length, newKey, newValue); - return newRecord; + + for (int i = 0; i < objKeys.length; i++) { + addPropNode[i].execute( + thisNode, + result, + objKeys[i], + getValueNode[i].execute(thisNode, rec, objKeys[i]), + hasDuplicateKeys); + } + + addPropNode[objKeys.length].execute(thisNode, result, newKey, newValue, hasDuplicateKeys); + return result; } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordBuildNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordBuildNode.java index 18ce8c086..3e5854d36 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordBuildNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordBuildNode.java @@ -16,36 +16,49 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.NodeInfo; +import java.util.List; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.runtime.record.RecordNodes; import raw.runtime.truffle.runtime.record.RecordNodesFactory; -import raw.runtime.truffle.runtime.record.RecordObject; @NodeInfo(shortName = "Record.Build") public class RecordBuildNode extends ExpressionNode { - @Child - private RecordNodes.WriteIndexNode writeIndexNode = RecordNodesFactory.WriteIndexNodeGen.create(); + @Children private final RecordNodes.AddPropNode[] addPropNode; @Children private final ExpressionNode[] elementNodes; - public RecordBuildNode(ExpressionNode[] elementsNodes) { + private final String[] keys; + + private final boolean hasDuplicateKeys; + + private final RawLanguage language = RawLanguage.get(this); + + public RecordBuildNode(ExpressionNode[] elementsNodes, String[] keys) { CompilerAsserts.compilationConstant(elementsNodes.length); - // elementsNodes is a an array of k1, v1, k2, v2, ..., kn, vn. - assert elementsNodes.length % 2 == 0; this.elementNodes = elementsNodes; + List listOfKeys = List.of(keys); + hasDuplicateKeys = listOfKeys.size() != listOfKeys.stream().distinct().count(); + this.keys = keys; + this.addPropNode = new RecordNodes.AddPropNode[elementsNodes.length]; + for (int i = 0; i < addPropNode.length; i++) { + this.addPropNode[i] = RecordNodesFactory.AddPropNodeGen.create(); + } } @ExplodeLoop @Override - public RecordObject executeGeneric(VirtualFrame frame) { - RecordObject record = RawLanguage.get(this).createRecord(); - for (int i = 0, j = 0; i < elementNodes.length; i += 2, j++) { - // i jump by 2 because we have k1, v1, k2, v2, ..., kn, vn. - Object key = elementNodes[i].executeGeneric(frame); - Object value = elementNodes[i + 1].executeGeneric(frame); - writeIndexNode.execute(this, record, j, (String) key, value); + public Object executeGeneric(VirtualFrame frame) { + Object record; + if (hasDuplicateKeys) { + record = language.createDuplicateKeyRecord(); + } else { + record = language.createPureRecord(); + } + for (int i = 0; i < elementNodes.length; i++) { + Object value = elementNodes[i].executeGeneric(frame); + addPropNode[i].execute(this, record, keys[i], value, hasDuplicateKeys); } return record; } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordConcatNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordConcatNode.java index 8e7fe9564..fc52bdd1a 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordConcatNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordConcatNode.java @@ -12,43 +12,77 @@ package raw.runtime.truffle.ast.expressions.record; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.ExplodeLoop; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; +import java.util.ArrayList; +import java.util.List; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.runtime.record.RecordNodes; -import raw.runtime.truffle.runtime.record.RecordObject; @NodeInfo(shortName = "Record.Concat") @NodeChild("record1") @NodeChild("record2") +@ImportStatic(RecordStaticInitializers.class) public abstract class RecordConcatNode extends ExpressionNode { + public static boolean hasDuplicateKeysBetween(Object[] keys1, Object[] keys2) { + List list = new ArrayList<>(List.of(keys1)); + list.addAll(List.of(keys2)); + return list.size() != list.stream().distinct().count(); + } + @Specialization - protected Object doConcat( + @ExplodeLoop + protected static Object doConcat( Object rec1, Object rec2, - @Cached(inline = true) RecordNodes.WriteIndexNode writeIndexNode, - @Cached(inline = true) RecordNodes.ReadIndexNode readIndexNode) { - RecordObject newRecord = RawLanguage.get(this).createRecord(); - RecordObject record1 = (RecordObject) rec1; - RecordObject record2 = (RecordObject) rec2; - String[] keys1 = record1.keys(); - String[] keys2 = record2.keys(); - int length1 = keys1.length; - int length2 = keys2.length; - String member; - for (int i = 0; i < length1; i++) { - member = keys1[i]; - writeIndexNode.execute(this, newRecord, i, member, readIndexNode.execute(this, record1, i)); + @Bind("$node") Node thisNode, + @Cached(value = "getCachedLanguage(thisNode)", neverDefault = true) RawLanguage lang, + @Cached(inline = true) RecordNodes.GetKeysNode getKeysNode1, + @Cached(inline = true) RecordNodes.GetKeysNode getKeysNode2, + @Cached(value = "getKeysNode1.execute(thisNode, rec1)", neverDefault = true, dimensions = 1) + Object[] objKeys1, + @Cached(value = "getKeysNode2.execute(thisNode, rec2)", neverDefault = true, dimensions = 1) + Object[] objKeys2, + @Cached(value = "getValueNode(objKeys1.length)", neverDefault = true) + RecordNodes.GetValueNode[] getValueNode1, + @Cached(value = "getValueNode(objKeys2.length)", neverDefault = true) + RecordNodes.GetValueNode[] getValueNode2, + @Cached(value = "getAddPropNode(objKeys1.length)", neverDefault = true) + RecordNodes.AddPropNode[] addPropNode1, + @Cached(value = "getAddPropNode(objKeys2.length)", neverDefault = true) + RecordNodes.AddPropNode[] addPropNode2, + @Cached(value = "hasDuplicateKeysBetween(objKeys1, objKeys2)", neverDefault = false) + boolean hasDuplicateKeys) { + + Object result; + if (hasDuplicateKeys) { + result = lang.createDuplicateKeyRecord(); + } else { + result = lang.createPureRecord(); } - for (int i = 0; i < length2; i++) { - member = keys2[i]; - writeIndexNode.execute( - this, newRecord, i + length1, member, readIndexNode.execute(this, record2, i)); + + for (int i = 0; i < objKeys1.length; i++) { + addPropNode1[i].execute( + thisNode, + result, + objKeys1[i], + getValueNode1[i].execute(thisNode, rec1, objKeys1[i]), + hasDuplicateKeys); } - return newRecord; + + for (int i = 0; i < objKeys2.length; i++) { + addPropNode2[i].execute( + thisNode, + result, + objKeys2[i], + getValueNode2[i].execute(thisNode, rec2, objKeys2[i]), + hasDuplicateKeys); + } + + return result; } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordFieldsNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordFieldsNode.java index 068f869a6..19cf2a9e6 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordFieldsNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordFieldsNode.java @@ -12,36 +12,24 @@ package raw.runtime.truffle.ast.expressions.record; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.InvalidArrayIndexException; -import com.oracle.truffle.api.interop.UnsupportedMessageException; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.NodeInfo; +import java.util.Arrays; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; import raw.runtime.truffle.runtime.list.StringList; +import raw.runtime.truffle.runtime.record.RecordNodes; @NodeInfo(shortName = "Record.Fields") @NodeChild("record") public abstract class RecordFieldsNode extends ExpressionNode { - @Specialization(limit = "3") + @Specialization protected StringList doFields( - Object record, - @CachedLibrary("record") InteropLibrary records, - @CachedLibrary(limit = "1") InteropLibrary libraries) { - try { - Object keys = records.getMembers(record); - long length = libraries.getArraySize(keys); - String[] members = new String[(int) length]; - for (int i = 0; i < length; i++) { - members[i] = (String) libraries.readArrayElement(keys, i); - } - return new StringList(members); - } catch (UnsupportedMessageException | InvalidArrayIndexException e) { - throw new RawTruffleInternalErrorException(e, this); - } + Object record, @Cached(inline = true) RecordNodes.GetKeysNode getKeysNode) { + Object[] keys = getKeysNode.execute(this, record); + String[] result = Arrays.stream(keys).map(Object::toString).toArray(String[]::new); + return new StringList(result); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordProjNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordProjNode.java index 4b056e10d..29bceec24 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordProjNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordProjNode.java @@ -18,7 +18,6 @@ import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.runtime.record.RecordNodes; -import raw.runtime.truffle.runtime.record.RecordObject; @NodeInfo(shortName = "Record.Project") @NodeChild("receiverNode") @@ -27,17 +26,15 @@ public abstract class RecordProjNode extends ExpressionNode { @Specialization protected Object readMember( - RecordObject record, - String key, - @Cached(inline = true) RecordNodes.ReadByKeyNode readByKeyNode) { - return readByKeyNode.execute(this, record, key); + Object record, String key, @Cached(inline = true) RecordNodes.GetValueNode getValueNode) { + return getValueNode.execute(this, record, key); } @Specialization protected Object readMember( - RecordObject record, + Object record, int index, - @Cached(inline = true) RecordNodes.ReadIndexNode readIndexNode) { - return readIndexNode.execute(this, record, index - 1); + @Cached(inline = true) RecordNodes.GetValueByIndexNode getValueByIndexNode) { + return getValueByIndexNode.execute(this, record, index - 1); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordRemoveFieldNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordRemoveFieldNode.java index 3f7f0518e..82d9d0c87 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordRemoveFieldNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordRemoveFieldNode.java @@ -12,45 +12,59 @@ package raw.runtime.truffle.ast.expressions.record; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.interop.*; -import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; +import java.util.ArrayList; +import java.util.List; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; -import raw.runtime.truffle.runtime.record.RecordObject; +import raw.runtime.truffle.runtime.record.RecordNodes; @NodeInfo(shortName = "Record.RemoveField") @NodeChild("record") @NodeChild("dropKey") +@ImportStatic(RecordStaticInitializers.class) public abstract class RecordRemoveFieldNode extends ExpressionNode { - @Specialization(limit = "3") - protected Object doRemoveField( - RecordObject record, - String dropKey, - @CachedLibrary("record") InteropLibrary records, - @CachedLibrary(limit = "2") InteropLibrary libraries) { - RecordObject newRecord = RawLanguage.get(this).createRecord(); - try { - Object keys = records.getMembers(record); - long length = libraries.getArraySize(keys); - String member; - for (int i = 0; i < length; i++) { - member = (String) libraries.readArrayElement(keys, i); - if (member.equals(dropKey)) { - continue; - } - libraries.writeMember(newRecord, member, records.readMember(record, member)); + public static boolean hasDuplicateKeysWithoutKey(Object[] keys, Object key) { + List list = new ArrayList<>(List.of(keys)); + list.remove(key); + return list.size() != list.stream().distinct().count(); + } + + @Specialization + protected static Object doRemoveField( + Object record, + Object dropKey, + @Bind("$node") Node thisNode, + @Cached(value = "getCachedLanguage(thisNode)", neverDefault = true) RawLanguage lang, + @Cached(inline = true) RecordNodes.GetKeysNode getKeysNode, + @Cached(value = "getKeysNode.execute(thisNode, record)", neverDefault = true, dimensions = 1) + Object[] objKeys, + @Cached(value = "hasDuplicateKeysWithoutKey(objKeys, dropKey)", neverDefault = false) + boolean hasDuplicateKeys, + @Cached(value = "getValueNode(objKeys.length)", neverDefault = true) + RecordNodes.GetValueNode[] getValueNode, + @Cached(value = "getAddPropNode(objKeys.length)", neverDefault = true) + RecordNodes.AddPropNode[] addPropNode) { + Object result; + if (hasDuplicateKeys) { + result = lang.createDuplicateKeyRecord(); + } else { + result = lang.createPureRecord(); + } + + for (int i = 0; i < objKeys.length; i++) { + if (!objKeys[i].equals(dropKey)) { + addPropNode[i].execute( + thisNode, + result, + objKeys[i], + getValueNode[i].execute(thisNode, record, objKeys[i]), + hasDuplicateKeys); } - return newRecord; - } catch (UnsupportedMessageException - | UnknownIdentifierException - | UnsupportedTypeException - | InvalidArrayIndexException e) { - throw new RawTruffleInternalErrorException(e, this); } + return result; } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordStaticInitializers.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordStaticInitializers.java new file mode 100644 index 000000000..65281e78e --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordStaticInitializers.java @@ -0,0 +1,52 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.expressions.record; + +import com.oracle.truffle.api.nodes.Node; +import java.util.ArrayList; +import java.util.List; +import raw.runtime.truffle.RawLanguage; +import raw.runtime.truffle.runtime.record.RecordNodes; +import raw.runtime.truffle.runtime.record.RecordNodesFactory; + +public class RecordStaticInitializers { + + public static RawLanguage getCachedLanguage(Node node) { + return RawLanguage.get(node); + } + + public static boolean hasDuplicateKeys(Object[] keys) { + List list = new ArrayList<>(List.of(keys)); + return list.size() != list.stream().distinct().count(); + } + + public static RecordNodes.AddPropNode[] getAddPropNode(int size) { + RecordNodes.AddPropNode[] result = new RecordNodes.AddPropNode[size]; + for (int i = 0; i < result.length; i++) { + result[i] = RecordNodesFactory.AddPropNodeGen.create(); + } + return result; + } + + public static RecordNodes.AddPropNode[] getAddPropNodePlusOne(int size) { + return getAddPropNode(size + 1); + } + + public static RecordNodes.GetValueNode[] getValueNode(int size) { + RecordNodes.GetValueNode[] result = new RecordNodes.GetValueNode[size]; + for (int i = 0; i < result.length; i++) { + result[i] = RecordNodesFactory.GetValueNodeGen.create(); + } + return result; + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordWriteNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordWriteNode.java deleted file mode 100644 index 0a2e68c74..000000000 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/record/RecordWriteNode.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2023 RAW Labs S.A. - * - * Use of this software is governed by the Business Source License - * included in the file licenses/BSL.txt. - * - * As of the Change Date specified in that file, in accordance with - * the Business Source License, use of this software will be governed - * by the Apache License, Version 2.0, included in the file - * licenses/APL.txt. - */ - -package raw.runtime.truffle.ast.expressions.record; - -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.UnknownIdentifierException; -import com.oracle.truffle.api.interop.UnsupportedMessageException; -import com.oracle.truffle.api.interop.UnsupportedTypeException; -import com.oracle.truffle.api.library.CachedLibrary; -import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; - -@NodeChild("receiverNode") -@NodeChild("nameNode") -@NodeChild("valueNode") -public abstract class RecordWriteNode extends ExpressionNode { - - static final int LIMIT = 3; - - @Specialization(limit = "LIMIT") - protected Object writeObject( - Object record, String name, Object value, @CachedLibrary("record") InteropLibrary records) { - try { - records.writeMember(record, name, value); - } catch (UnsupportedMessageException - | UnknownIdentifierException - | UnsupportedTypeException e) { - throw new RawTruffleInternalErrorException(e, this); - } - return value; - } -} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableFlatMapNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableFlatMapNode.java index 05a11bd97..70b290001 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableFlatMapNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableFlatMapNode.java @@ -12,13 +12,12 @@ package raw.runtime.truffle.ast.expressions.tryable; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.ImportStatic; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; +import raw.runtime.truffle.runtime.primitives.ErrorObject; import raw.runtime.truffle.tryable_nullable.Tryable; @NodeInfo(shortName = "Tryable.FlatMap") @@ -27,16 +26,17 @@ @ImportStatic(Tryable.class) public abstract class TryableFlatMapNode extends ExpressionNode { - @Specialization(guards = "isSuccess(tryable)") - protected Object doObjectIsSuccess( + @Specialization(guards = "isError(tryable)") + protected Object exec(ErrorObject tryable, Object function) { + return tryable; + } + + @Specialization(guards = "!isError(tryable)") + protected static Object exec( Object tryable, Object function, + @Bind("this") Node thisNode, @Cached(inline = true) FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { - return functionExecuteOneNode.execute(this, function, tryable); - } - - @Specialization(guards = "isFailure(tryable)") - protected Object doObjectFailure(Object tryable, Object function) { - return tryable; + return functionExecuteOneNode.execute(thisNode, function, tryable); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableGetFailureNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableGetFailureNode.java index ecea75117..a38c477cd 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableGetFailureNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableGetFailureNode.java @@ -12,17 +12,19 @@ package raw.runtime.truffle.ast.expressions.tryable; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.tryable_nullable.Tryable; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; @NodeInfo(shortName = "Tryable.GetFailure") @NodeChild("tryable") public abstract class TryableGetFailureNode extends ExpressionNode { @Specialization - protected String getFailure(Object tryable) { - return Tryable.getFailure(tryable); + protected String getFailure( + Object tryable, @Cached(inline = true) TryableNullableNodes.GetErrorNode getFailureNode) { + return getFailureNode.execute(this, tryable); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableIsFailureNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableIsFailureNode.java index bc131d558..171887725 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableIsFailureNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableIsFailureNode.java @@ -12,18 +12,20 @@ package raw.runtime.truffle.ast.expressions.tryable; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.tryable_nullable.Tryable; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; @NodeInfo(shortName = "Tryable.isError") @NodeChild("tryable") public abstract class TryableIsFailureNode extends ExpressionNode { @Specialization - protected boolean isFailureTryable(Object tryable) { - return Tryable.isFailure(tryable); + protected boolean isFailureTryable( + Object tryable, @Cached(inline = true) TryableNullableNodes.IsErrorNode isFailureNode) { + return isFailureNode.execute(this, tryable); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableIsSuccessNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableIsSuccessNode.java index 0191a38cc..4845fd0fc 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableIsSuccessNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableIsSuccessNode.java @@ -12,18 +12,20 @@ package raw.runtime.truffle.ast.expressions.tryable; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.tryable_nullable.Tryable; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; @NodeInfo(shortName = "Tryable.isSuccess") @NodeChild("tryable") public abstract class TryableIsSuccessNode extends ExpressionNode { @Specialization - protected boolean isSuccess(Object tryable) { - return Tryable.isSuccess(tryable); + protected boolean isSuccess( + Object tryable, @Cached(inline = true) TryableNullableNodes.IsErrorNode isErrorNode) { + return !isErrorNode.execute(this, tryable); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableMapNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableMapNode.java index 7d3044652..19f5fb11f 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableMapNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableMapNode.java @@ -12,13 +12,12 @@ package raw.runtime.truffle.ast.expressions.tryable; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.ImportStatic; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; +import raw.runtime.truffle.runtime.primitives.ErrorObject; import raw.runtime.truffle.tryable_nullable.Tryable; @NodeInfo(shortName = "Tryable.Map") @@ -27,16 +26,17 @@ @ImportStatic(Tryable.class) public abstract class TryableMapNode extends ExpressionNode { - @Specialization(guards = "isSuccess(tryable)") - protected Object doObjectIsSuccess( + @Specialization(guards = "isError(tryable)") + protected static Object exec(ErrorObject tryable, Object function) { + return tryable; + } + + @Specialization(guards = "!isError(tryable)") + protected static Object exec( Object tryable, Object function, + @Bind("this") Node thisNode, @Cached(inline = true) FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { - return functionExecuteOneNode.execute(this, function, tryable); - } - - @Specialization(guards = "isFailure(tryable)") - protected Object doObjectIsFailure(Object tryable, Object function) { - return tryable; + return functionExecuteOneNode.execute(thisNode, function, tryable); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableNullableFlatMapNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableNullableFlatMapNode.java index e7c6f35da..57f8ba452 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableNullableFlatMapNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableNullableFlatMapNode.java @@ -12,31 +12,38 @@ package raw.runtime.truffle.ast.expressions.tryable; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.ImportStatic; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; -import raw.runtime.truffle.tryable_nullable.TryableNullable; +import raw.runtime.truffle.runtime.primitives.ErrorObject; +import raw.runtime.truffle.runtime.primitives.NullObject; +import raw.runtime.truffle.tryable_nullable.Nullable; +import raw.runtime.truffle.tryable_nullable.Tryable; @NodeInfo(shortName = "TryableNullable.FlatMap") @NodeChild("tryable") @NodeChild("function") -@ImportStatic(TryableNullable.class) +@ImportStatic({Nullable.class, Tryable.class}) public abstract class TryableNullableFlatMapNode extends ExpressionNode { - @Specialization(guards = "isValue(maybeTryableNullable)") - protected Object doTryableValue( - Object maybeTryableNullable, - Object function, - @Cached(inline = true) FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { - return functionExecuteOneNode.execute(this, function, maybeTryableNullable); + @Specialization(guards = "isError(maybeTryableNullable)") + protected static Object exec(ErrorObject maybeTryableNullable, Object function) { + return maybeTryableNullable; } - @Specialization(guards = "!isValue(maybeTryableNullable)") - protected Object doTryableNotValue(Object maybeTryableNullable, Object function) { + @Specialization(guards = "isNull(maybeTryableNullable)") + protected static Object exec(NullObject maybeTryableNullable, Object function) { return maybeTryableNullable; } + + @Specialization(guards = {"!isError(maybeTryableNullable)", "!isNull(maybeTryableNullable)"}) + protected static Object exec( + Object maybeTryableNullable, + Object function, + @Bind("this") Node thisNode, + @Cached(inline = true) FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { + return functionExecuteOneNode.execute(thisNode, function, maybeTryableNullable); + } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableUnsafeGetNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableUnsafeGetNode.java index 1213e590b..cfb8a5a53 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableUnsafeGetNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/expressions/tryable/TryableUnsafeGetNode.java @@ -12,25 +12,30 @@ package raw.runtime.truffle.ast.expressions.tryable; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; +import raw.runtime.truffle.runtime.primitives.ErrorObject; import raw.runtime.truffle.tryable_nullable.Tryable; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; @NodeInfo(shortName = "Try.UnsafeGet") @NodeChild("tryable") -@ImportStatic(Tryable.class) +@ImportStatic({Tryable.class}) public abstract class TryableUnsafeGetNode extends ExpressionNode { - @Specialization(guards = "isSuccess(tryable)") - protected Object doObjectIsSuccess(Object tryable) { - return tryable; + @Specialization(guards = "isError(tryable)") + protected Object exec( + ErrorObject tryable, + @Cached(inline = true) TryableNullableNodes.GetErrorNode getFailureNode) { + throw new RawTruffleRuntimeException(getFailureNode.execute(this, tryable), this); } - @Specialization(guards = "isFailure(tryable)") - protected Object doObject(Object tryable) { - throw new RawTruffleRuntimeException(Tryable.getFailure(tryable), this); + @Specialization(guards = "!isError(tryable)") + protected Object exec(Object tryable) { + return tryable; } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/binary/BinaryWriterNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/binary/BinaryWriterNode.java index 111003161..105201258 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/binary/BinaryWriterNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/binary/BinaryWriterNode.java @@ -15,13 +15,11 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.NodeInfo; -import java.io.IOException; import java.io.OutputStream; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.RawContext; import raw.runtime.truffle.StatementNode; import raw.runtime.truffle.ast.ProgramStatementNode; -import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; @NodeInfo(shortName = "Binary.Write") public class BinaryWriterNode extends StatementNode { @@ -30,6 +28,8 @@ public class BinaryWriterNode extends StatementNode { @Child private DirectCallNode innerWriter; + private final OutputStream os = RawContext.get(this).getOutput(); + public BinaryWriterNode(ExpressionNode binaryNode, ProgramStatementNode innerWriter) { this.innerWriter = DirectCallNode.create(innerWriter.getCallTarget()); this.binaryNode = binaryNode; @@ -38,10 +38,6 @@ public BinaryWriterNode(ExpressionNode binaryNode, ProgramStatementNode innerWri @Override public void executeVoid(VirtualFrame frame) { Object binaryObject = binaryNode.executeGeneric(frame); - try (OutputStream os = RawContext.get(this).getOutput()) { - innerWriter.call(binaryObject, os); - } catch (IOException e) { - throw new RawTruffleRuntimeException(e.getMessage(), e, this); - } + innerWriter.call(binaryObject, os); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/binary/NullableBinaryWriterNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/binary/NullableBinaryWriterNode.java index 72f240d53..23daf7e88 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/binary/NullableBinaryWriterNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/binary/NullableBinaryWriterNode.java @@ -18,13 +18,18 @@ import java.io.OutputStream; import raw.runtime.truffle.StatementNode; import raw.runtime.truffle.ast.ProgramStatementNode; -import raw.runtime.truffle.tryable_nullable.Nullable; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodesFactory; @NodeInfo(shortName = "Binary.NullableWrite") public class NullableBinaryWriterNode extends StatementNode { @Child private DirectCallNode innerWriter; + @Child + private TryableNullableNodes.IsNullNode isNullNode = + TryableNullableNodesFactory.IsNullNodeGen.create(); + public NullableBinaryWriterNode(ProgramStatementNode innerWriter) { this.innerWriter = DirectCallNode.create(innerWriter.getCallTarget()); } @@ -34,7 +39,7 @@ public void executeVoid(VirtualFrame frame) { Object[] args = frame.getArguments(); Object nullable = args[0]; OutputStream output = (OutputStream) args[1]; - if (Nullable.isNotNull(nullable)) { + if (!isNullNode.execute(this, nullable)) { // the nullable is defined, write its bytes using the inner writer (the plain binary // writer) innerWriter.call(nullable, output); diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/binary/TryableBinaryWriterNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/binary/TryableBinaryWriterNode.java index 5a64f7e73..270fd6fa1 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/binary/TryableBinaryWriterNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/binary/TryableBinaryWriterNode.java @@ -19,13 +19,22 @@ import raw.runtime.truffle.StatementNode; import raw.runtime.truffle.ast.ProgramStatementNode; import raw.runtime.truffle.runtime.exceptions.binary.BinaryWriterRawTruffleException; -import raw.runtime.truffle.tryable_nullable.Tryable; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodesFactory; @NodeInfo(shortName = "Binary.TryableWrite") public class TryableBinaryWriterNode extends StatementNode { @Child private DirectCallNode innerWriter; + @Child + private TryableNullableNodes.IsErrorNode isErrorNode = + TryableNullableNodesFactory.IsErrorNodeGen.create(); + + @Child + private TryableNullableNodes.GetErrorNode getFailureNode = + TryableNullableNodesFactory.GetErrorNodeGen.create(); + public TryableBinaryWriterNode(ProgramStatementNode innerWriter) { this.innerWriter = DirectCallNode.create(innerWriter.getCallTarget()); } @@ -35,12 +44,12 @@ public void executeVoid(VirtualFrame frame) { Object[] args = frame.getArguments(); Object tryable = args[0]; OutputStream output = (OutputStream) args[1]; - if (Tryable.isSuccess(tryable)) { + if (!isErrorNode.execute(this, tryable)) { // the tryable is a success, write its bytes using the inner writer. innerWriter.call(tryable, output); } else { // else throw. - throw new BinaryWriterRawTruffleException(Tryable.getFailure(tryable), this); + throw new BinaryWriterRawTruffleException(getFailureNode.execute(this, tryable), this); } } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/reader/parser/IterableParseCsvFile.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/reader/parser/IterableParseCsvFile.java index 2e5f7d8b4..50c015b75 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/reader/parser/IterableParseCsvFile.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/reader/parser/IterableParseCsvFile.java @@ -17,14 +17,13 @@ import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.UnexpectedResultException; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawContext; import raw.runtime.truffle.ast.ProgramExpressionNode; import raw.runtime.truffle.runtime.exceptions.csv.CsvParserRawTruffleException; import raw.runtime.truffle.runtime.iterable.sources.CsvCollection; import raw.runtime.truffle.runtime.list.StringList; import raw.runtime.truffle.runtime.primitives.LocationObject; -import raw.runtime.truffle.tryable_nullable.Nullable; -import raw.sources.api.SourceContext; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodesFactory; @NodeInfo(shortName = "IterableParseCsvFile") public class IterableParseCsvFile extends ExpressionNode { @@ -42,6 +41,10 @@ public class IterableParseCsvFile extends ExpressionNode { @Child private ExpressionNode timeFormatExp; @Child private ExpressionNode datetimeFormatExp; + @Child + private TryableNullableNodes.IsNullNode isNullNode = + TryableNullableNodesFactory.IsNullNodeGen.create(); + public IterableParseCsvFile( ExpressionNode location, ExpressionNode encodingExp, @@ -71,7 +74,6 @@ public IterableParseCsvFile( public Object executeGeneric(VirtualFrame frame) { LocationObject locationValue = (LocationObject) location.executeGeneric(frame); - SourceContext context = RawContext.get(this).getSourceContext(); try { String encodingValue = encodingExp.executeString(frame); int skipValue = skipExp.executeInt(frame); @@ -79,7 +81,7 @@ public Object executeGeneric(VirtualFrame frame) { Object quoteValue = quoteExp.executeGeneric(frame); char quoteChar = 0; boolean useQuote = false; - if (Nullable.isNotNull(quoteValue)) { + if (!isNullNode.execute(this, quoteValue)) { String quoteCharString = (String) quoteValue; if (!quoteCharString.isEmpty()) { useQuote = true; @@ -88,7 +90,7 @@ public Object executeGeneric(VirtualFrame frame) { } Object escapeValue = escapeExp.executeGeneric(frame); char escapeChar = 0; - if (Nullable.isNotNull(escapeValue)) { + if (!isNullNode.execute(this, escapeValue)) { String escapeCharString = (String) escapeValue; if (!escapeCharString.isEmpty()) { escapeChar = escapeCharString.charAt(0); @@ -111,8 +113,7 @@ public Object executeGeneric(VirtualFrame frame) { dateFormat, timeFormat, datetimeFormat); - return new CsvCollection( - locationValue, context, parserRootCallTarget, encodingValue, settings); + return new CsvCollection(locationValue, parserRootCallTarget, encodingValue, settings); } catch (UnexpectedResultException ex) { throw new CsvParserRawTruffleException(ex.getMessage(), 0, 0, ex, this); } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/reader/parser/IterableParseCsvString.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/reader/parser/IterableParseCsvString.java index 4692913ba..0af75508f 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/reader/parser/IterableParseCsvString.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/reader/parser/IterableParseCsvString.java @@ -21,7 +21,8 @@ import raw.runtime.truffle.runtime.exceptions.csv.CsvParserRawTruffleException; import raw.runtime.truffle.runtime.iterable.sources.CsvFromStringCollection; import raw.runtime.truffle.runtime.list.StringList; -import raw.runtime.truffle.tryable_nullable.Nullable; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodesFactory; @NodeInfo(shortName = "IterableParseCsvString") public class IterableParseCsvString extends ExpressionNode { @@ -39,6 +40,10 @@ public class IterableParseCsvString extends ExpressionNode { @Child private ExpressionNode timeFormatExp; @Child private ExpressionNode datetimeFormatExp; + @Child + private TryableNullableNodes.IsNullNode isNullNode = + TryableNullableNodesFactory.IsNullNodeGen.create(); + public IterableParseCsvString( ExpressionNode strExp, ExpressionNode skipExp, @@ -72,7 +77,7 @@ public Object executeGeneric(VirtualFrame frame) { Object quoteValue = quoteExp.executeGeneric(frame); char quoteChar = 0; boolean useQuote = false; - if (Nullable.isNotNull(quoteValue)) { + if (!isNullNode.execute(this, quoteValue)) { String quoteCharString = (String) quoteValue; if (!quoteCharString.isEmpty()) { useQuote = true; @@ -81,7 +86,7 @@ public Object executeGeneric(VirtualFrame frame) { } Object escapeValue = escapeExp.executeGeneric(frame); char escapeChar = 0; - if (Nullable.isNotNull(escapeValue)) { + if (!isNullNode.execute(this, escapeValue)) { String escapeCharString = (String) escapeValue; if (!escapeCharString.isEmpty()) { escapeChar = escapeCharString.charAt(0); diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/reader/parser/RecordParseCsvNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/reader/parser/RecordParseCsvNode.java index 73779a6b0..309bd2365 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/reader/parser/RecordParseCsvNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/reader/parser/RecordParseCsvNode.java @@ -16,30 +16,41 @@ import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.NodeInfo; +import java.util.Arrays; +import java.util.List; import raw.compiler.rql2.source.Rql2AttrType; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.ast.ProgramExpressionNode; import raw.runtime.truffle.runtime.record.RecordNodes; import raw.runtime.truffle.runtime.record.RecordNodesFactory; -import raw.runtime.truffle.runtime.record.RecordObject; @NodeInfo(shortName = "RecordParseCsv") public class RecordParseCsvNode extends ExpressionNode { - @Child - private RecordNodes.WriteIndexNode writeIndexNode = RecordNodesFactory.WriteIndexNodeGen.create(); + @Children private final RecordNodes.AddPropNode[] addPropNode; - @Children private DirectCallNode[] childDirectCalls; + @Children private final DirectCallNode[] childDirectCalls; private final Rql2AttrType[] columns; + private final boolean hasDuplicateKeys; + private final RawLanguage language = RawLanguage.get(this); + public RecordParseCsvNode(ProgramExpressionNode[] columnParsers, Rql2AttrType[] columns) { this.columns = columns; this.childDirectCalls = new DirectCallNode[columnParsers.length]; for (int i = 0; i < columnParsers.length; i++) { this.childDirectCalls[i] = DirectCallNode.create(columnParsers[i].getCallTarget()); } + addPropNode = new RecordNodes.AddPropNode[columns.length]; + for (int i = 0; i < columns.length; i++) { + addPropNode[i] = RecordNodesFactory.AddPropNodeGen.create(); + } + + List keys = Arrays.stream(columns).map(Rql2AttrType::idn).toList(); + + hasDuplicateKeys = keys.size() != keys.stream().distinct().count(); } @Override @@ -48,12 +59,17 @@ public Object executeGeneric(VirtualFrame frame) { Object[] args = frame.getArguments(); RawTruffleCsvParser parser = (RawTruffleCsvParser) args[0]; assert (parser.startingNewLine(this)); - RecordObject record = RawLanguage.get(this).createRecord(); + Object record; + if (hasDuplicateKeys) { + record = language.createDuplicateKeyRecord(); + } else { + record = language.createPureRecord(); + } for (int i = 0; i < columns.length; i++) { String fieldName = columns[i].idn(); parser.getNextField(); Object value = childDirectCalls[i].call(parser); - writeIndexNode.execute(this, record, i, fieldName, value); + addPropNode[i].execute(this, record, fieldName, value, hasDuplicateKeys); } parser.finishLine(this); return record; diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/CsvIterableWriterNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/CsvIterableWriterNode.java index 268fb8f2b..1cb18d016 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/CsvIterableWriterNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/CsvIterableWriterNode.java @@ -62,6 +62,8 @@ public class CsvIterableWriterNode extends StatementNode { private final String[] columnNames; private final String lineSeparator; + private final OutputStream os = RawContext.get(this).getOutput(); + public CsvIterableWriterNode( ExpressionNode dataNode, RootCallTarget writeRootCallTarget, @@ -77,8 +79,7 @@ public CsvIterableWriterNode( public void executeVoid(VirtualFrame frame) { Object iterable = dataNode.executeGeneric(frame); Object generator = getGeneratorNode.execute(this, iterable); - try (OutputStream os = RawContext.get(this).getOutput(); - CsvGenerator gen = createGenerator(os)) { + try (CsvGenerator gen = createGenerator(os)) { generatorInitNode.execute(this, generator); while (generatorHasNextNode.execute(this, generator)) { Object item = generatorNextNode.execute(this, generator); diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/CsvListWriterNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/CsvListWriterNode.java index 8b7d0f107..165628db7 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/CsvListWriterNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/CsvListWriterNode.java @@ -44,6 +44,7 @@ public class CsvListWriterNode extends StatementNode { private final String[] columnNames; private final String lineSeparator; + private final OutputStream os; public CsvListWriterNode( ExpressionNode dataNode, @@ -54,12 +55,12 @@ public CsvListWriterNode( itemWriter = DirectCallNode.create(writeRootCallTarget); this.columnNames = columnNames; this.lineSeparator = lineSeparator; + this.os = RawContext.get(this).getOutput(); } @Override public void executeVoid(VirtualFrame frame) { - try (OutputStream os = RawContext.get(this).getOutput(); - CsvGenerator gen = createGenerator(os)) { + try (CsvGenerator gen = createGenerator(os)) { ObjectList list = (ObjectList) dataNode.executeGeneric(frame); long size = sizeNode.execute(this, list); for (long i = 0; i < size; i++) { diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/internal/NullableWriteCsvNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/internal/NullableWriteCsvNode.java index a0f070825..4af652d5e 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/internal/NullableWriteCsvNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/internal/NullableWriteCsvNode.java @@ -21,13 +21,18 @@ import raw.runtime.truffle.StatementNode; import raw.runtime.truffle.ast.ProgramStatementNode; import raw.runtime.truffle.runtime.exceptions.csv.CsvWriterRawTruffleException; -import raw.runtime.truffle.tryable_nullable.Nullable; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodesFactory; @NodeInfo(shortName = "NullableWriteCsv") public class NullableWriteCsvNode extends StatementNode { @Child private DirectCallNode valueWriter; + @Child + private TryableNullableNodes.IsNullNode isNullNode = + TryableNullableNodesFactory.IsNullNodeGen.create(); + public NullableWriteCsvNode(ProgramStatementNode valueWriter) { this.valueWriter = DirectCallNode.create(valueWriter.getCallTarget()); } @@ -36,7 +41,7 @@ public void executeVoid(VirtualFrame frame) { Object[] args = frame.getArguments(); Object nullable = args[0]; CsvGenerator generator = (CsvGenerator) args[1]; - if (Nullable.isNotNull(nullable)) { + if (!isNullNode.execute(this, nullable)) { valueWriter.call(nullable, generator); } else { doWriteNull(generator); diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/internal/RecordWriteCsvNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/internal/RecordWriteCsvNode.java index cfd50d0ba..991ec631e 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/internal/RecordWriteCsvNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/internal/RecordWriteCsvNode.java @@ -17,7 +17,6 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.InvalidArrayIndexException; -import com.oracle.truffle.api.interop.UnknownIdentifierException; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.ExplodeLoop; @@ -27,14 +26,15 @@ import raw.runtime.truffle.ast.ProgramStatementNode; import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; import raw.runtime.truffle.runtime.exceptions.csv.CsvWriterRawTruffleException; -import raw.runtime.truffle.runtime.record.RecordObject; +import raw.runtime.truffle.runtime.record.RecordNodes; +import raw.runtime.truffle.runtime.record.RecordNodesFactory; @NodeInfo(shortName = "RecordWriteCsv") public class RecordWriteCsvNode extends StatementNode { @Children private DirectCallNode[] valueWriter; - @Child private InteropLibrary records = InteropLibrary.getFactory().createDispatched(3); + @Child private RecordNodes.GetValueNode getValue = RecordNodesFactory.GetValueNodeGen.create(); @Child private InteropLibrary keysArrays = InteropLibrary.getFactory().createDispatched(1); @@ -48,7 +48,7 @@ public RecordWriteCsvNode(ProgramStatementNode[] valueWriter) { @ExplodeLoop public void executeVoid(VirtualFrame frame) { Object[] args = frame.getArguments(); - RecordObject record = (RecordObject) args[0]; + Object record = args[0]; CsvGenerator generator = (CsvGenerator) args[1]; try { Object keys = keysArrays.getMembers(record); @@ -56,13 +56,11 @@ public void executeVoid(VirtualFrame frame) { doStartRow(generator); for (int idx = 0; idx < nFields; idx++) { String fieldName = (String) keysArrays.readArrayElement(keys, idx); - Object value = records.readMember(record, fieldName); + Object value = getValue.execute(this, record, fieldName); valueWriter[idx].call(value, generator); } doEndRow(generator); - } catch (UnsupportedMessageException - | InvalidArrayIndexException - | UnknownIdentifierException e) { + } catch (UnsupportedMessageException | InvalidArrayIndexException e) { throw new RawTruffleInternalErrorException(e, this); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/internal/TryableWriteCsvNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/internal/TryableWriteCsvNode.java index a5422702a..e76c28d4c 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/internal/TryableWriteCsvNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/csv/writer/internal/TryableWriteCsvNode.java @@ -21,13 +21,22 @@ import raw.runtime.truffle.StatementNode; import raw.runtime.truffle.ast.ProgramStatementNode; import raw.runtime.truffle.runtime.exceptions.csv.CsvWriterRawTruffleException; -import raw.runtime.truffle.tryable_nullable.Tryable; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodesFactory; @NodeInfo(shortName = "TryableWriteCsv") public class TryableWriteCsvNode extends StatementNode { @Child private DirectCallNode valueWriter; + @Child + private TryableNullableNodes.IsErrorNode isErrorNode = + TryableNullableNodesFactory.IsErrorNodeGen.create(); + + @Child + private TryableNullableNodes.GetErrorNode getFailureNode = + TryableNullableNodesFactory.GetErrorNodeGen.create(); + public TryableWriteCsvNode(ProgramStatementNode valueWriter) { this.valueWriter = DirectCallNode.create(valueWriter.getCallTarget()); } @@ -36,10 +45,10 @@ public void executeVoid(VirtualFrame frame) { Object[] args = frame.getArguments(); Object tryable = args[0]; CsvGenerator generator = (CsvGenerator) args[1]; - if (Tryable.isSuccess(tryable)) { + if (!isErrorNode.execute(this, tryable)) { valueWriter.call(tryable, generator); } else { - doWriteError(Tryable.getFailure(tryable), generator); + doWriteError(getFailureNode.execute(this, tryable), generator); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/jdbc/JdbcQueryNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/jdbc/JdbcQueryNode.java index dda54ffb7..c5860cc13 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/jdbc/JdbcQueryNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/jdbc/JdbcQueryNode.java @@ -29,8 +29,8 @@ public class JdbcQueryNode extends ExpressionNode { @Child private ExpressionNode locationExp; @Child private ExpressionNode queryExp; private final RootCallTarget makeRowCallTarget; - private final JdbcExceptionHandler exceptionHandler; + private final SourceContext context = RawContext.get(this).getSourceContext(); public JdbcQueryNode( ExpressionNode locationExp, @@ -47,7 +47,6 @@ public JdbcQueryNode( public Object executeGeneric(VirtualFrame virtualFrame) { LocationObject dbLocation = (LocationObject) locationExp.executeGeneric(virtualFrame); String query = (String) this.queryExp.executeGeneric(virtualFrame); - SourceContext context = RawContext.get(this).getSourceContext(); return new JdbcQueryCollection(dbLocation, query, context, makeRowCallTarget, exceptionHandler); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/jdbc/RecordReadJdbcQuery.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/jdbc/RecordReadJdbcQuery.java index 8b10528c9..6de9519b6 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/jdbc/RecordReadJdbcQuery.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/jdbc/RecordReadJdbcQuery.java @@ -13,58 +13,60 @@ package raw.runtime.truffle.ast.io.jdbc; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.UnknownIdentifierException; -import com.oracle.truffle.api.interop.UnsupportedMessageException; -import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.NodeInfo; +import java.util.Arrays; +import java.util.List; import raw.compiler.rql2.source.Rql2AttrType; import raw.runtime.truffle.ExpressionNode; import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.ast.ProgramExpressionNode; -import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; -import raw.runtime.truffle.runtime.record.RecordObject; +import raw.runtime.truffle.runtime.record.RecordNodes; +import raw.runtime.truffle.runtime.record.RecordNodesFactory; @NodeInfo(shortName = "Jdbc.RecordRead") public class RecordReadJdbcQuery extends ExpressionNode { - @Children private DirectCallNode[] childDirectCalls; + @Children private final DirectCallNode[] childDirectCalls; - @Child private InteropLibrary records = InteropLibrary.getFactory().createDispatched(2); + @Children private final RecordNodes.AddPropNode[] addPropNode; private final Rql2AttrType[] columns; + private final RawLanguage language = RawLanguage.get(this); + + private final boolean hasDuplicateKeys; + public RecordReadJdbcQuery(ProgramExpressionNode[] columnParsers, Rql2AttrType[] columns) { this.columns = columns; this.childDirectCalls = new DirectCallNode[columnParsers.length]; for (int i = 0; i < columnParsers.length; i++) { this.childDirectCalls[i] = DirectCallNode.create(columnParsers[i].getCallTarget()); } - } - - @Override - public Object executeGeneric(VirtualFrame frame) { - return this.executeRecord(frame); + addPropNode = new RecordNodes.AddPropNode[columns.length]; + for (int i = 0; i < columns.length; i++) { + addPropNode[i] = RecordNodesFactory.AddPropNodeGen.create(); + } + List listOfKeys = Arrays.stream(columns).map(Rql2AttrType::idn).toList(); + hasDuplicateKeys = listOfKeys.size() != listOfKeys.stream().distinct().count(); } @Override @ExplodeLoop - public final RecordObject executeRecord(VirtualFrame frame) { + public Object executeGeneric(VirtualFrame frame) { Object[] args = frame.getArguments(); JdbcQuery rs = (JdbcQuery) args[0]; - RecordObject record = RawLanguage.get(this).createRecord(); + Object record; + if (hasDuplicateKeys) { + record = language.createDuplicateKeyRecord(); + } else { + record = language.createPureRecord(); + } for (int i = 0; i < columns.length; i++) { String fieldName = columns[i].idn(); Object value = childDirectCalls[i].call(rs); - try { - records.writeMember(record, fieldName, value); - } catch (UnsupportedMessageException - | UnknownIdentifierException - | UnsupportedTypeException ex) { - throw new RawTruffleInternalErrorException(ex, this); - } + addPropNode[i].execute(this, record, fieldName, value, hasDuplicateKeys); } return record; } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/JsonParserNodes.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/JsonParserNodes.java index ba856acc9..68c2c3869 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/JsonParserNodes.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/JsonParserNodes.java @@ -20,11 +20,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.TruffleLogger; import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.UnknownIdentifierException; -import com.oracle.truffle.api.interop.UnsupportedMessageException; -import com.oracle.truffle.api.interop.UnsupportedTypeException; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import java.io.IOException; @@ -39,14 +34,14 @@ import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.ast.expressions.builtin.temporals.DateTimeFormatCache; import raw.runtime.truffle.ast.expressions.builtin.temporals.interval_package.IntervalNodes; -import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; +import raw.runtime.truffle.ast.expressions.record.RecordStaticInitializers; import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; import raw.runtime.truffle.runtime.exceptions.json.JsonParserRawTruffleException; import raw.runtime.truffle.runtime.exceptions.json.JsonReaderRawTruffleException; import raw.runtime.truffle.runtime.exceptions.json.JsonUnexpectedTokenException; -import raw.runtime.truffle.runtime.list.ObjectList; +import raw.runtime.truffle.runtime.list.RawArrayList; import raw.runtime.truffle.runtime.primitives.*; -import raw.runtime.truffle.runtime.record.RecordObject; +import raw.runtime.truffle.runtime.record.RecordNodes; import raw.runtime.truffle.utils.TruffleCharInputStream; public final class JsonParserNodes { @@ -516,7 +511,7 @@ static TimestampObject doParse( } @NodeInfo(shortName = "JsonParser.ParseAny") - @ImportStatic(JsonNodeType.class) + @ImportStatic({JsonNodeType.class, RecordStaticInitializers.class}) @GenerateInline public abstract static class ParseAnyJsonParserNode extends Node { @@ -607,7 +602,7 @@ public boolean isNull(JsonParser parser) { } @Specialization(guards = {"isArray(parser)"}) - protected static ObjectList doParseList( + protected static RawArrayList doParseList( Node node, JsonParser parser, @Bind("$node") Node thisNode, @@ -625,30 +620,27 @@ protected static ObjectList doParseList( ArrayList alist = new ArrayList<>(); + // (az) To do, make OSR when we use any type while (currentToken.execute(thisNode, parser) != JsonToken.END_ARRAY) { alist.add(parse.execute(thisNode, parser)); } - nextToken.execute(thisNode, parser); - - Object[] result = new Object[alist.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = alist.get(i); - } - return new ObjectList(result); + nextToken.execute(thisNode, parser); + return new RawArrayList(alist); } @Specialization(guards = {"isObject(parser)"}) - protected static RecordObject doParse( + protected static Object doParse( Node node, JsonParser parser, @Bind("$node") Node thisNode, + @Cached("getCachedLanguage(thisNode)") RawLanguage lang, @Cached(inline = false) @Cached.Shared("parseAny") ParseAnyJsonParserNode parse, @Cached @Cached.Shared("nextToken") JsonParserNodes.NextTokenJsonParserNode nextToken, @Cached @Cached.Shared("currentToken") JsonParserNodes.CurrentTokenJsonParserNode currentToken, @Cached JsonParserNodes.CurrentFieldJsonParserNode currentField, - @CachedLibrary(limit = "3") InteropLibrary records) { + @Cached RecordNodes.AddPropNode addPropNode) { if (currentToken.execute(thisNode, parser) != JsonToken.START_OBJECT) { throw new JsonUnexpectedTokenException( JsonToken.START_OBJECT.asString(), @@ -658,19 +650,14 @@ protected static RecordObject doParse( nextToken.execute(thisNode, parser); - RecordObject record = RawLanguage.get(thisNode).createRecord(); - try { - while (currentToken.execute(thisNode, parser) != JsonToken.END_OBJECT) { - String fieldName = currentField.execute(thisNode, parser); - nextToken.execute(thisNode, parser); // skip the field name - records.writeMember(record, fieldName, parse.execute(thisNode, parser)); - } - nextToken.execute(thisNode, parser); // skip the END_OBJECT token - } catch (UnsupportedMessageException - | UnknownIdentifierException - | UnsupportedTypeException e) { - throw new RawTruffleInternalErrorException(e, thisNode); + Object record = RawLanguage.get(thisNode).createDuplicateKeyRecord(); + while (currentToken.execute(thisNode, parser) != JsonToken.END_OBJECT) { + String fieldName = currentField.execute(thisNode, parser); + nextToken.execute(thisNode, parser); // skip the field name + addPropNode.execute(thisNode, record, fieldName, parse.execute(thisNode, parser), true); } + nextToken.execute(thisNode, parser); // skip the END_OBJECT token + return record; } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/JsonReadCollectionNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/JsonReadCollectionNode.java index 932b1e6e7..d07d4a032 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/JsonReadCollectionNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/JsonReadCollectionNode.java @@ -16,11 +16,9 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawContext; import raw.runtime.truffle.ast.ProgramExpressionNode; import raw.runtime.truffle.runtime.iterable.sources.JsonReadCollection; import raw.runtime.truffle.runtime.primitives.LocationObject; -import raw.sources.api.SourceContext; @NodeInfo(shortName = "Json.ReadCollection") public class JsonReadCollectionNode extends ExpressionNode { @@ -41,8 +39,6 @@ public JsonReadCollectionNode( public Object executeGeneric(VirtualFrame virtualFrame) { LocationObject locationObject = (LocationObject) locationExp.executeGeneric(virtualFrame); String encoding = (String) encodingExp.executeGeneric(virtualFrame); - - SourceContext context = RawContext.get(this).getSourceContext(); - return new JsonReadCollection(locationObject, encoding, context, rootCallTarget); + return new JsonReadCollection(locationObject, encoding, rootCallTarget); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/JsonReadValueNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/JsonReadValueNode.java index 93e163ac0..bc5e1d7c3 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/JsonReadValueNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/JsonReadValueNode.java @@ -37,8 +37,7 @@ public class JsonReadValueNode extends ExpressionNode { @Child private DirectCallNode childDirectCall; @Child - private InitJsonParserNode initParserNode = - JsonParserNodesFactory.InitJsonParserNodeGen.getUncached(); + private InitJsonParserNode initParserNode = JsonParserNodesFactory.InitJsonParserNodeGen.create(); @Child private CloseJsonParserNode closeParserNode = @@ -48,6 +47,8 @@ public class JsonReadValueNode extends ExpressionNode { private NextTokenJsonParserNode nextTokenNode = JsonParserNodesFactory.NextTokenJsonParserNodeGen.create(); + private final SourceContext sourceContext = RawContext.get(this).getSourceContext(); + private JsonParser parser; public JsonReadValueNode( @@ -63,8 +64,7 @@ public Object executeGeneric(VirtualFrame virtualFrame) { LocationObject locationObject = (LocationObject) locationExp.executeGeneric(virtualFrame); String encoding = (String) encodingExp.executeGeneric(virtualFrame); - SourceContext context = RawContext.get(this).getSourceContext(); - TruffleInputStream truffleInputStream = new TruffleInputStream(locationObject, context); + TruffleInputStream truffleInputStream = new TruffleInputStream(locationObject, sourceContext); TruffleCharInputStream stream = new TruffleCharInputStream(truffleInputStream, encoding); parser = initParserNode.execute(this, stream); diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/parser/ListParseJsonNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/parser/ListParseJsonNode.java index 7cb2d9eb6..c7819c879 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/parser/ListParseJsonNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/parser/ListParseJsonNode.java @@ -15,105 +15,91 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.oracle.truffle.api.RootCallTarget; -import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.DirectCallNode; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.NodeInfo; import java.util.ArrayList; import raw.compiler.rql2.source.Rql2Type; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.ast.TypeGuards; +import raw.runtime.truffle.ast.expressions.iterable.ArrayOperationNodes; +import raw.runtime.truffle.ast.expressions.iterable.ArrayOperationNodesFactory; import raw.runtime.truffle.ast.io.json.reader.JsonParserNodes; +import raw.runtime.truffle.ast.io.json.reader.JsonParserNodesFactory; +import raw.runtime.truffle.ast.osr.OSRGeneratorNode; +import raw.runtime.truffle.ast.osr.bodies.OSRListParseJsonBodyNode; +import raw.runtime.truffle.ast.osr.bodies.OSRToArrayBodyNode; +import raw.runtime.truffle.ast.osr.conditions.OSRIsLessThanSizeConditionNode; +import raw.runtime.truffle.ast.osr.conditions.OSRListParseJsonConditionNode; import raw.runtime.truffle.runtime.exceptions.json.JsonUnexpectedTokenException; import raw.runtime.truffle.runtime.list.*; -@ImportStatic(value = TypeGuards.class) @NodeInfo(shortName = "IterableParseJson") -@NodeField(name = "resultType", type = Rql2Type.class) -@NodeField(name = "childCallTarget", type = RootCallTarget.class) -public abstract class ListParseJsonNode extends ExpressionNode { - - @Idempotent - protected abstract Rql2Type getResultType(); - - @Idempotent - protected abstract RootCallTarget getChildCallTarget(); - - @Specialization(guards = {"isByteKind(getResultType())"}) - protected ByteList doByte( - VirtualFrame frame, - @Cached("create(getChildCallTarget())") @Cached.Shared("callTarget") - DirectCallNode childCallNode, - @Cached(inline = true) @Cached.Shared("currentToken") - JsonParserNodes.CurrentTokenJsonParserNode currentToken, - @Cached(inline = true) @Cached.Shared("nextToken") - JsonParserNodes.NextTokenJsonParserNode nextToken) { - Object[] args = frame.getArguments(); - JsonParser parser = (JsonParser) args[0]; - - if (currentToken.execute(this, parser) != JsonToken.START_ARRAY) { - throw new JsonUnexpectedTokenException( - JsonToken.START_ARRAY.asString(), currentToken.execute(this, parser).toString(), this); - } - nextToken.execute(this, parser); - - ArrayList alist = new ArrayList<>(); - - while (currentToken.execute(this, parser) != JsonToken.END_ARRAY) { - alist.add((Byte) childCallNode.call(parser)); - } - nextToken.execute(this, parser); - - byte[] result = new byte[alist.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = alist.get(i); - } - - return new ByteList(result); - } - - @Specialization(guards = {"isShortKind(getResultType())"}) - protected ShortList doShort( - VirtualFrame frame, - @Cached("create(getChildCallTarget())") @Cached.Shared("callTarget") - DirectCallNode childCallNode, - @Cached(inline = true) @Cached.Shared("currentToken") - JsonParserNodes.CurrentTokenJsonParserNode currentToken, - @Cached(inline = true) @Cached.Shared("nextToken") - JsonParserNodes.NextTokenJsonParserNode nextToken) { - Object[] args = frame.getArguments(); - JsonParser parser = (JsonParser) args[0]; - - if (currentToken.execute(this, parser) != JsonToken.START_ARRAY) { - throw new JsonUnexpectedTokenException( - JsonToken.START_ARRAY.asString(), currentToken.execute(this, parser).toString(), this); - } - nextToken.execute(this, parser); - - ArrayList alist = new ArrayList<>(); - - while (currentToken.execute(this, parser) != JsonToken.END_ARRAY) { - alist.add((Short) childCallNode.call(parser)); - } - nextToken.execute(this, parser); - - short[] result = new short[alist.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = alist.get(i); - } - - return new ShortList(result); +public class ListParseJsonNode extends ExpressionNode { + + @Child private LoopNode listParseLoopNode; + + @Child private LoopNode toArrayLoopNode; + + @Child + private JsonParserNodes.CurrentTokenJsonParserNode currentToken = + JsonParserNodesFactory.CurrentTokenJsonParserNodeGen.create(); + + @Child + private JsonParserNodes.NextTokenJsonParserNode nextToken = + JsonParserNodesFactory.NextTokenJsonParserNodeGen.create(); + + @Child + private ArrayOperationNodes.ArrayBuildListNode arrayBuildListNode = + ArrayOperationNodesFactory.ArrayBuildListNodeGen.create(); + + @Child + private ArrayOperationNodes.ArrayBuildNode arrayBuildNode = + ArrayOperationNodesFactory.ArrayBuildNodeGen.create(); + + private final Rql2Type resultType; + + private final int currentIdxSlot; + private final int listSizeSlot; + private final int llistSlot; + private final int resultSlot; + + private final int parserSlot; + + public ListParseJsonNode( + Rql2Type resultType, + RootCallTarget childCallTarget, + int parserSlot, + int llistSlot, + int currentIdxSlot, + int listSizeSlot, + int resultSlot) { + this.parserSlot = parserSlot; + this.resultType = resultType; + this.listSizeSlot = listSizeSlot; + this.currentIdxSlot = currentIdxSlot; + this.resultSlot = resultSlot; + this.llistSlot = llistSlot; + + this.listParseLoopNode = + Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRListParseJsonConditionNode(this.parserSlot), + new OSRListParseJsonBodyNode( + childCallTarget, this.llistSlot, this.parserSlot))); + + toArrayLoopNode = + Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRIsLessThanSizeConditionNode(currentIdxSlot, listSizeSlot), + new OSRToArrayBodyNode( + this.resultType, this.llistSlot, this.currentIdxSlot, this.resultSlot))); } - @Specialization(guards = {"isIntKind(getResultType())"}) - protected IntList doInt( - VirtualFrame frame, - @Cached("create(getChildCallTarget())") @Cached.Shared("callTarget") - DirectCallNode childCallNode, - @Cached(inline = true) @Cached.Shared("currentToken") - JsonParserNodes.CurrentTokenJsonParserNode currentToken, - @Cached(inline = true) @Cached.Shared("nextToken") - JsonParserNodes.NextTokenJsonParserNode nextToken) { + @Override + public Object executeGeneric(VirtualFrame frame) { Object[] args = frame.getArguments(); JsonParser parser = (JsonParser) args[0]; @@ -123,216 +109,21 @@ protected IntList doInt( } nextToken.execute(this, parser); - ArrayList alist = new ArrayList<>(); + frame.setObject(parserSlot, parser); + frame.setObject(llistSlot, new ArrayList<>()); + listParseLoopNode.execute(frame); - while (currentToken.execute(this, parser) != JsonToken.END_ARRAY) { - alist.add((Integer) childCallNode.call(parser)); - } - nextToken.execute(this, parser); - - int[] result = new int[alist.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = alist.get(i); - } - - return new IntList(result); - } - - @Specialization(guards = {"isLongKind(getResultType())"}) - protected LongList doLong( - VirtualFrame frame, - @Cached("create(getChildCallTarget())") @Cached.Shared("callTarget") - DirectCallNode childCallNode, - @Cached(inline = true) @Cached.Shared("currentToken") - JsonParserNodes.CurrentTokenJsonParserNode currentToken, - @Cached(inline = true) @Cached.Shared("nextToken") - JsonParserNodes.NextTokenJsonParserNode nextToken) { - Object[] args = frame.getArguments(); - JsonParser parser = (JsonParser) args[0]; - - if (currentToken.execute(this, parser) != JsonToken.START_ARRAY) { - throw new JsonUnexpectedTokenException( - JsonToken.START_ARRAY.asString(), currentToken.execute(this, parser).toString(), this); - } - nextToken.execute(this, parser); - - ArrayList alist = new ArrayList<>(); - - while (currentToken.execute(this, parser) != JsonToken.END_ARRAY) { - alist.add((Long) childCallNode.call(parser)); - } - nextToken.execute(this, parser); - - long[] result = new long[alist.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = alist.get(i); - } - - return new LongList(result); - } - - @Specialization(guards = {"isFloatKind(getResultType())"}) - protected FloatList doFloat( - VirtualFrame frame, - @Cached("create(getChildCallTarget())") @Cached.Shared("callTarget") - DirectCallNode childCallNode, - @Cached(inline = true) @Cached.Shared("currentToken") - JsonParserNodes.CurrentTokenJsonParserNode currentToken, - @Cached(inline = true) @Cached.Shared("nextToken") - JsonParserNodes.NextTokenJsonParserNode nextToken) { - Object[] args = frame.getArguments(); - JsonParser parser = (JsonParser) args[0]; - - if (currentToken.execute(this, parser) != JsonToken.START_ARRAY) { - throw new JsonUnexpectedTokenException( - JsonToken.START_ARRAY.asString(), currentToken.execute(this, parser).toString(), this); - } - nextToken.execute(this, parser); - - ArrayList alist = new ArrayList<>(); - - while (currentToken.execute(this, parser) != JsonToken.END_ARRAY) { - alist.add((Float) childCallNode.call(parser)); - } nextToken.execute(this, parser); - float[] result = new float[alist.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = alist.get(i); - } - - return new FloatList(result); - } - - @Specialization(guards = {"isDoubleKind(getResultType())"}) - protected DoubleList doDouble( - VirtualFrame frame, - @Cached("create(getChildCallTarget())") @Cached.Shared("callTarget") - DirectCallNode childCallNode, - @Cached(inline = true) @Cached.Shared("currentToken") - JsonParserNodes.CurrentTokenJsonParserNode currentToken, - @Cached(inline = true) @Cached.Shared("nextToken") - JsonParserNodes.NextTokenJsonParserNode nextToken) { - Object[] args = frame.getArguments(); - JsonParser parser = (JsonParser) args[0]; - - if (currentToken.execute(this, parser) != JsonToken.START_ARRAY) { - throw new JsonUnexpectedTokenException( - JsonToken.START_ARRAY.asString(), currentToken.execute(this, parser).toString(), this); - } - nextToken.execute(this, parser); - - ArrayList alist = new ArrayList<>(); - - while (currentToken.execute(this, parser) != JsonToken.END_ARRAY) { - alist.add((Double) childCallNode.call(parser)); - } - nextToken.execute(this, parser); - - double[] result = new double[alist.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = alist.get(i); - } - - return new DoubleList(result); - } - - @Specialization(guards = {"isBooleanKind(getResultType())"}) - protected BooleanList doBoolean( - VirtualFrame frame, - @Cached("create(getChildCallTarget())") @Cached.Shared("callTarget") - DirectCallNode childCallNode, - @Cached(inline = true) @Cached.Shared("currentToken") - JsonParserNodes.CurrentTokenJsonParserNode currentToken, - @Cached(inline = true) @Cached.Shared("nextToken") - JsonParserNodes.NextTokenJsonParserNode nextToken) { - Object[] args = frame.getArguments(); - JsonParser parser = (JsonParser) args[0]; - - if (currentToken.execute(this, parser) != JsonToken.START_ARRAY) { - throw new JsonUnexpectedTokenException( - JsonToken.START_ARRAY.asString(), currentToken.execute(this, parser).toString(), this); - } - nextToken.execute(this, parser); - - ArrayList alist = new ArrayList<>(); - - while (currentToken.execute(this, parser) != JsonToken.END_ARRAY) { - alist.add((Boolean) childCallNode.call(parser)); - } - nextToken.execute(this, parser); - - boolean[] result = new boolean[alist.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = alist.get(i); - } - - return new BooleanList(result); - } - - @Specialization(guards = {"isStringKind(getResultType())"}) - protected StringList doString( - VirtualFrame frame, - @Cached("create(getChildCallTarget())") @Cached.Shared("callTarget") - DirectCallNode childCallNode, - @Cached(inline = true) @Cached.Shared("currentToken") - JsonParserNodes.CurrentTokenJsonParserNode currentToken, - @Cached(inline = true) @Cached.Shared("nextToken") - JsonParserNodes.NextTokenJsonParserNode nextToken) { - Object[] args = frame.getArguments(); - JsonParser parser = (JsonParser) args[0]; - - if (currentToken.execute(this, parser) != JsonToken.START_ARRAY) { - throw new JsonUnexpectedTokenException( - JsonToken.START_ARRAY.asString(), currentToken.execute(this, parser).toString(), this); - } - nextToken.execute(this, parser); - - ArrayList alist = new ArrayList<>(); - - while (currentToken.execute(this, parser) != JsonToken.END_ARRAY) { - alist.add((String) childCallNode.call(parser)); - } - nextToken.execute(this, parser); - - String[] result = new String[alist.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = alist.get(i); - } - - return new StringList(result); - } - - @Specialization - protected ObjectList doObject( - VirtualFrame frame, - @Cached("create(getChildCallTarget())") @Cached.Shared("callTarget") - DirectCallNode childCallNode, - @Cached(inline = true) @Cached.Shared("currentToken") - JsonParserNodes.CurrentTokenJsonParserNode currentToken, - @Cached(inline = true) @Cached.Shared("nextToken") - JsonParserNodes.NextTokenJsonParserNode nextToken) { - Object[] args = frame.getArguments(); - JsonParser parser = (JsonParser) args[0]; - - if (currentToken.execute(this, parser) != JsonToken.START_ARRAY) { - throw new JsonUnexpectedTokenException( - JsonToken.START_ARRAY.asString(), currentToken.execute(this, parser).toString(), this); - } - nextToken.execute(this, parser); - - ArrayList alist = new ArrayList<>(); - - while (currentToken.execute(this, parser) != JsonToken.END_ARRAY) { - alist.add(childCallNode.call(parser)); - } - nextToken.execute(this, parser); - - Object[] result = new Object[alist.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = alist.get(i); - } + @SuppressWarnings("unchecked") + ArrayList llist = (ArrayList) frame.getObject(llistSlot); + int size = llist.size(); - return new ObjectList(result); + frame.setObject(resultSlot, arrayBuildNode.execute(this, resultType, size)); + frame.setInt(this.currentIdxSlot, 0); + frame.setInt(listSizeSlot, size); + frame.setObject(llistSlot, llist); + toArrayLoopNode.execute(frame); + return arrayBuildListNode.execute(this, frame.getObject(resultSlot)); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/parser/NullableParseJsonNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/parser/NullableParseJsonNode.java index 8c411b43c..15c36997e 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/parser/NullableParseJsonNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/parser/NullableParseJsonNode.java @@ -30,11 +30,11 @@ public class NullableParseJsonNode extends ExpressionNode { @Child private JsonParserNodes.NextTokenJsonParserNode nextTokenNode = - JsonParserNodesFactory.NextTokenJsonParserNodeGen.getUncached(); + JsonParserNodesFactory.NextTokenJsonParserNodeGen.create(); @Child private JsonParserNodes.CurrentTokenJsonParserNode currentTokenNode = - JsonParserNodesFactory.CurrentTokenJsonParserNodeGen.getUncached(); + JsonParserNodesFactory.CurrentTokenJsonParserNodeGen.create(); public NullableParseJsonNode(ProgramExpressionNode childProgramStatementNode) { this.childDirectCall = DirectCallNode.create(childProgramStatementNode.getCallTarget()); diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/parser/OrParseJsonNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/parser/OrParseJsonNode.java index f67125d2d..c65c3ece5 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/parser/OrParseJsonNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/parser/OrParseJsonNode.java @@ -35,15 +35,15 @@ public class OrParseJsonNode extends ExpressionNode { @Child private JsonParserNodes.InitJsonParserNode initParserNode = - JsonParserNodesFactory.InitJsonParserNodeGen.getUncached(); + JsonParserNodesFactory.InitJsonParserNodeGen.create(); @Child private JsonParserNodes.CloseJsonParserNode closeParserNode = - JsonParserNodesFactory.CloseJsonParserNodeGen.getUncached(); + JsonParserNodesFactory.CloseJsonParserNodeGen.create(); @Child private JsonParserNodes.NextTokenJsonParserNode nextTokenNode = - JsonParserNodesFactory.NextTokenJsonParserNodeGen.getUncached(); + JsonParserNodesFactory.NextTokenJsonParserNodeGen.create(); public OrParseJsonNode(ProgramExpressionNode[] childProgramExpressionNode) { this.childDirectCalls = new DirectCallNode[childProgramExpressionNode.length]; diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/parser/RecordParseJsonNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/parser/RecordParseJsonNode.java index 4d05428e5..bd222dcc8 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/parser/RecordParseJsonNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/reader/parser/RecordParseJsonNode.java @@ -20,6 +20,7 @@ import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; +import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.NodeInfo; import java.util.BitSet; import java.util.LinkedHashMap; @@ -36,42 +37,45 @@ import raw.runtime.truffle.runtime.primitives.NullObject; import raw.runtime.truffle.runtime.record.RecordNodes; import raw.runtime.truffle.runtime.record.RecordNodesFactory; -import raw.runtime.truffle.runtime.record.RecordObject; @NodeInfo(shortName = "RecordParseJson") @ImportStatic(RawTruffleBoundaries.class) public class RecordParseJsonNode extends ExpressionNode { - @Children private DirectCallNode[] childDirectCalls; + @Children private final DirectCallNode[] childDirectCalls; @Child private JsonParserNodes.SkipNextJsonParserNode skipNode = - JsonParserNodesFactory.SkipNextJsonParserNodeGen.getUncached(); + JsonParserNodesFactory.SkipNextJsonParserNodeGen.create(); @Child private JsonParserNodes.CurrentFieldJsonParserNode currentFieldNode = - JsonParserNodesFactory.CurrentFieldJsonParserNodeGen.getUncached(); + JsonParserNodesFactory.CurrentFieldJsonParserNodeGen.create(); @Child private JsonParserNodes.CurrentTokenJsonParserNode currentTokenNode = - JsonParserNodesFactory.CurrentTokenJsonParserNodeGen.getUncached(); + JsonParserNodesFactory.CurrentTokenJsonParserNodeGen.create(); @Child private JsonParserNodes.NextTokenJsonParserNode nextTokenNode = - JsonParserNodesFactory.NextTokenJsonParserNodeGen.getUncached(); + JsonParserNodesFactory.NextTokenJsonParserNodeGen.create(); - @Child - private RecordNodes.WriteIndexNode writeIndexNode = RecordNodesFactory.WriteIndexNodeGen.create(); + @Children private final RecordNodes.AddPropNode[] addPropNode; // Field name and its index in the childDirectCalls array private final LinkedHashMap fieldNamesMap; private final int fieldsSize; private final Rql2TypeWithProperties[] fieldTypes; + private final RawLanguage language = RawLanguage.get(this); + + private final boolean hasDuplicateKeys; + public RecordParseJsonNode( ProgramExpressionNode[] childProgramExpressionNode, LinkedHashMap fieldNamesMap, - Rql2TypeWithProperties[] fieldTypes) { + Rql2TypeWithProperties[] fieldTypes, + boolean hasDuplicateKeys) { this.fieldTypes = fieldTypes; this.fieldNamesMap = fieldNamesMap; this.fieldsSize = childProgramExpressionNode.length; @@ -80,6 +84,11 @@ public RecordParseJsonNode( this.childDirectCalls[i] = DirectCallNode.create(childProgramExpressionNode[i].getCallTarget()); } + this.addPropNode = new RecordNodes.AddPropNode[this.fieldsSize]; + for (int i = 0; i < this.fieldsSize; i++) { + this.addPropNode[i] = RecordNodesFactory.AddPropNodeGen.create(); + } + this.hasDuplicateKeys = hasDuplicateKeys; } @CompilerDirectives.TruffleBoundary @@ -88,10 +97,23 @@ private Integer getFieldNameIndex(String fieldName) { } @CompilerDirectives.TruffleBoundary - private Object callChild(int index, JsonParser parser) { - return childDirectCalls[index].call(parser); + private void executeWhileLoop(JsonParser parser, BitSet currentBitSet, Object record) { + while (currentTokenNode.execute(this, parser) != JsonToken.END_OBJECT) { + String fieldName = currentFieldNode.execute(this, parser); + Integer index = this.getFieldNameIndex(fieldName); + nextTokenNode.execute(this, parser); // skip the field name + if (index != null) { + setBitSet(currentBitSet, index); + addPropNode[index].execute( + this, record, fieldName, childDirectCalls[index].call(parser), hasDuplicateKeys); + } else { + // skip the field value + skipNode.execute(this, parser); + } + } } + @ExplodeLoop public Object executeGeneric(VirtualFrame frame) { Object[] args = frame.getArguments(); JsonParser parser = (JsonParser) args[0]; @@ -105,43 +127,47 @@ public Object executeGeneric(VirtualFrame frame) { } nextTokenNode.execute(this, parser); - RecordObject record = RawLanguage.get(this).createRecord(); + Object record; + if (hasDuplicateKeys) { + record = language.createDuplicateKeyRecord(); + } else { + record = language.createPureRecord(); + } // todo: (az) need to find a solution for the array of direct calls, // the json object can be out of order, the child nodes cannot be inlined - while (currentTokenNode.execute(this, parser) != JsonToken.END_OBJECT) { - String fieldName = currentFieldNode.execute(this, parser); - Integer index = this.getFieldNameIndex(fieldName); - nextTokenNode.execute(this, parser); // skip the field name - if (index != null) { - setBitSet(currentBitSet, index); - writeIndexNode.execute(this, record, index, fieldName, callChild(index, parser)); - } else { - // skip the field value - skipNode.execute(this, parser); - } - } + executeWhileLoop(parser, currentBitSet, record); nextTokenNode.execute(this, parser); // skip the END_OBJECT token if (bitSetCardinality(currentBitSet) != this.fieldsSize) { // not all fields were found in the JSON. Fill the missing nullable ones with nulls or // fail. - Object[] fields = fieldNamesMap.keySet().toArray(); + String[] fields = getKeySet(); for (int i = 0; i < this.fieldsSize; i++) { if (!bitSetGet(currentBitSet, i)) { - if (fieldTypes[i].props().contains(Rql2IsNullableTypeProperty.apply())) { + if (propsContainNullable(i)) { // It's OK, the field is nullable. If it's tryable, make a success null, // else a plain // null. Object nullValue = NullObject.INSTANCE; - writeIndexNode.execute(this, record, i, fields[i].toString(), nullValue); + addPropNode[i].execute(this, record, fields[i], nullValue, hasDuplicateKeys); } else { - throw new JsonRecordFieldNotFoundException(fields[i].toString(), this); + throw new JsonRecordFieldNotFoundException(fields[i], this); } } } } return record; } + + @CompilerDirectives.TruffleBoundary + private String[] getKeySet() { + return fieldNamesMap.keySet().toArray(new String[0]); + } + + @CompilerDirectives.TruffleBoundary + private boolean propsContainNullable(int index) { + return fieldTypes[index].props().contains(Rql2IsNullableTypeProperty.apply()); + } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/JsonWriteNodes.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/JsonWriteNodes.java index 48a2538ee..fc586b3da 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/JsonWriteNodes.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/JsonWriteNodes.java @@ -19,11 +19,6 @@ import com.fasterxml.jackson.databind.node.JsonNodeType; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.InvalidArrayIndexException; -import com.oracle.truffle.api.interop.UnknownIdentifierException; -import com.oracle.truffle.api.interop.UnsupportedMessageException; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import java.io.IOException; @@ -32,12 +27,13 @@ import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.util.Base64; -import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; import raw.runtime.truffle.runtime.exceptions.json.JsonWriterRawTruffleException; import raw.runtime.truffle.runtime.list.ObjectList; import raw.runtime.truffle.runtime.primitives.*; -import raw.runtime.truffle.runtime.record.RecordObject; +import raw.runtime.truffle.runtime.record.DuplicateKeyRecord; +import raw.runtime.truffle.runtime.record.PureRecord; +import raw.runtime.truffle.runtime.record.RecordNodes; public final class JsonWriteNodes { @@ -464,33 +460,53 @@ protected static void doWriteList( @Specialization protected static void doWriteRecord( Node node, - RecordObject record, + PureRecord record, JsonGenerator gen, @Bind("$node") Node thisNode, @Cached(inline = false) @Cached.Shared("writeAny") WriteAnyJsonParserNode writeAny, - @Cached WriteFieldNameJsonWriterNode writeField, - @Cached WriteStartObjectJsonWriterNode startObject, - @Cached WriteEndObjectJsonWriterNode endObject, - @CachedLibrary(limit = "3") InteropLibrary interops) { - try { - Object keys = interops.getMembers(record); - int size = (int) interops.getArraySize(keys); - - startObject.execute(thisNode, gen); - String fieldName; - Object member; - for (int i = 0; i < size; i++) { - fieldName = (String) interops.readArrayElement(keys, i); - writeField.execute(thisNode, fieldName, gen); - member = interops.readMember(record, fieldName); - writeAny.execute(thisNode, member, gen); - } - endObject.execute(thisNode, gen); - } catch (UnsupportedMessageException - | InvalidArrayIndexException - | UnknownIdentifierException e) { - throw new RawTruffleInternalErrorException(e); + @Cached @Cached.Shared("write") WriteFieldNameJsonWriterNode writeField, + @Cached @Cached.Shared("start") WriteStartObjectJsonWriterNode startObject, + @Cached @Cached.Shared("end") WriteEndObjectJsonWriterNode endObject, + @Cached @Cached.Shared("getValue") RecordNodes.GetValueNode getValue, + @Cached @Cached.Shared("getKeys") RecordNodes.GetKeysNode getKeys) { + Object[] keys = getKeys.execute(thisNode, record); + + startObject.execute(thisNode, gen); + String fieldName; + Object member; + for (Object key : keys) { + fieldName = (String) key; + writeField.execute(thisNode, fieldName, gen); + member = getValue.execute(thisNode, record, fieldName); + writeAny.execute(thisNode, member, gen); + } + endObject.execute(thisNode, gen); + } + + @Specialization + protected static void doWriteRecord( + Node node, + DuplicateKeyRecord record, + JsonGenerator gen, + @Bind("$node") Node thisNode, + @Cached(inline = false) @Cached.Shared("writeAny") WriteAnyJsonParserNode writeAny, + @Cached @Cached.Shared("write") WriteFieldNameJsonWriterNode writeField, + @Cached @Cached.Shared("start") WriteStartObjectJsonWriterNode startObject, + @Cached @Cached.Shared("end") WriteEndObjectJsonWriterNode endObject, + @Cached @Cached.Shared("getValue") RecordNodes.GetValueNode getValue, + @Cached @Cached.Shared("getKeys") RecordNodes.GetKeysNode getKeys) { + Object[] keys = getKeys.execute(thisNode, record); + + startObject.execute(thisNode, gen); + String fieldName; + Object member; + for (Object key : keys) { + fieldName = (String) key; + writeField.execute(thisNode, fieldName, gen); + member = getValue.execute(thisNode, record, fieldName); + writeAny.execute(thisNode, member, gen); } + endObject.execute(thisNode, gen); } @Specialization diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/JsonWriterNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/JsonWriterNode.java index d68e63413..63971b783 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/JsonWriterNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/JsonWriterNode.java @@ -25,13 +25,14 @@ import java.io.IOException; import java.io.OutputStream; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawContext; import raw.runtime.truffle.StatementNode; import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; +import raw.runtime.truffle.runtime.generator.collection.StaticInitializers; @NodeInfo(shortName = "Json.Write") @NodeChild(value = "value", type = ExpressionNode.class) @NodeField(name = "childCallTarget", type = RootCallTarget.class) +@ImportStatic(StaticInitializers.class) public abstract class JsonWriterNode extends StatementNode { protected abstract RootCallTarget getChildCallTarget(); @@ -41,9 +42,9 @@ public void doWrite( Object value, @Bind("$node") Node thisNode, @Cached(inline = true) JsonWriteNodes.InitGeneratorJsonWriterNode initGeneratorNode, - @Cached("create(getChildCallTarget())") DirectCallNode childDirectCall) { - try (OutputStream os = RawContext.get(this).getOutput(); - JsonGenerator gen = initGeneratorNode.execute(this, os)) { + @Cached("create(getChildCallTarget())") DirectCallNode childDirectCall, + @Cached(value = "getOutputStream(thisNode)", neverDefault = true) OutputStream outputStream) { + try (JsonGenerator gen = initGeneratorNode.execute(this, outputStream)) { childDirectCall.call(value, gen); } catch (IOException e) { throw new RawTruffleRuntimeException(e.getMessage(), e, thisNode); diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/internal/NullableWriteJsonNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/internal/NullableWriteJsonNode.java index 8c08688d4..56054fd23 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/internal/NullableWriteJsonNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/internal/NullableWriteJsonNode.java @@ -20,7 +20,8 @@ import raw.runtime.truffle.ast.ProgramStatementNode; import raw.runtime.truffle.ast.io.json.writer.JsonWriteNodes; import raw.runtime.truffle.ast.io.json.writer.JsonWriteNodesFactory; -import raw.runtime.truffle.tryable_nullable.Nullable; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodesFactory; @NodeInfo(shortName = "NullableWriteJson") public class NullableWriteJsonNode extends StatementNode { @@ -31,6 +32,10 @@ public class NullableWriteJsonNode extends StatementNode { JsonWriteNodes.WriteNullJsonWriterNode writeNullNode = JsonWriteNodesFactory.WriteNullJsonWriterNodeGen.create(); + @Child + private TryableNullableNodes.IsNullNode isNullNode = + TryableNullableNodesFactory.IsNullNodeGen.create(); + public NullableWriteJsonNode(ProgramStatementNode childProgramStatementNode) { this.childDirectCall = DirectCallNode.create(childProgramStatementNode.getCallTarget()); } @@ -40,7 +45,7 @@ public void executeVoid(VirtualFrame frame) { Object[] args = frame.getArguments(); Object option = args[0]; JsonGenerator gen = (JsonGenerator) args[1]; - if (Nullable.isNotNull(option)) { + if (!isNullNode.execute(this, option)) { childDirectCall.call(option, gen); } else { writeNullNode.execute(this, gen); diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/internal/RecordWriteJsonNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/internal/RecordWriteJsonNode.java index 2521670ce..3ea504751 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/internal/RecordWriteJsonNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/internal/RecordWriteJsonNode.java @@ -14,9 +14,6 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.InvalidArrayIndexException; -import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.ExplodeLoop; import raw.runtime.truffle.StatementNode; @@ -26,28 +23,26 @@ import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; import raw.runtime.truffle.runtime.record.RecordNodes; import raw.runtime.truffle.runtime.record.RecordNodesFactory; -import raw.runtime.truffle.runtime.record.RecordObject; public class RecordWriteJsonNode extends StatementNode { @Children private DirectCallNode[] childDirectCalls; - @Child private InteropLibrary interops = InteropLibrary.getFactory().createDispatched(2); - @Child private JsonWriteNodes.WriteStartObjectJsonWriterNode writeStartObjectNode = - JsonWriteNodesFactory.WriteStartObjectJsonWriterNodeGen.getUncached(); + JsonWriteNodesFactory.WriteStartObjectJsonWriterNodeGen.create(); @Child private JsonWriteNodes.WriteEndObjectJsonWriterNode writeEndObjectNode = - JsonWriteNodesFactory.WriteEndObjectJsonWriterNodeGen.getUncached(); + JsonWriteNodesFactory.WriteEndObjectJsonWriterNodeGen.create(); @Child private JsonWriteNodes.WriteFieldNameJsonWriterNode writeFieldNameNode = - JsonWriteNodesFactory.WriteFieldNameJsonWriterNodeGen.getUncached(); + JsonWriteNodesFactory.WriteFieldNameJsonWriterNodeGen.create(); - @Child - private RecordNodes.ReadIndexNode readIndexNode = RecordNodesFactory.ReadIndexNodeGen.create(); + @Child private RecordNodes.GetKeysNode getKeysNode = RecordNodesFactory.GetKeysNodeGen.create(); + + @Child RecordNodes.GetValueNode getValueNode = RecordNodesFactory.GetValueNodeGen.create(); public RecordWriteJsonNode(ProgramStatementNode[] childProgramStatementNode) { this.childDirectCalls = new DirectCallNode[childProgramStatementNode.length]; @@ -62,21 +57,20 @@ public RecordWriteJsonNode(ProgramStatementNode[] childProgramStatementNode) { public void executeVoid(VirtualFrame frame) { try { Object[] args = frame.getArguments(); - RecordObject record = (RecordObject) args[0]; + Object record = args[0]; JsonGenerator gen = (JsonGenerator) args[1]; - Object keys = interops.getMembers(record); + Object[] keys = getKeysNode.execute(this, record); Object item; writeStartObjectNode.execute(this, gen); for (int i = 0; i < childDirectCalls.length; i++) { - String member = (String) interops.readArrayElement(keys, i); - item = readIndexNode.execute(this, record, i); - writeFieldNameNode.execute(this, member, gen); + item = getValueNode.execute(this, record, (String) keys[i]); + writeFieldNameNode.execute(this, (String) keys[i], gen); childDirectCalls[i].call(item, gen); } writeEndObjectNode.execute(this, gen); - } catch (RuntimeException | UnsupportedMessageException | InvalidArrayIndexException e) { + } catch (RuntimeException e) { throw new RawTruffleInternalErrorException(e, this); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/internal/TryableUnsafeWriteJsonNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/internal/TryableUnsafeWriteJsonNode.java index 2b80ab3e8..be1523118 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/internal/TryableUnsafeWriteJsonNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/internal/TryableUnsafeWriteJsonNode.java @@ -19,13 +19,22 @@ import raw.runtime.truffle.StatementNode; import raw.runtime.truffle.ast.ProgramStatementNode; import raw.runtime.truffle.runtime.exceptions.json.JsonWriterRawTruffleException; -import raw.runtime.truffle.tryable_nullable.Tryable; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodesFactory; @NodeInfo(shortName = "TryableUnsafeWriteJson") public class TryableUnsafeWriteJsonNode extends StatementNode { @Child private DirectCallNode childDirectCall; + @Child + private TryableNullableNodes.IsErrorNode isErrorNode = + TryableNullableNodesFactory.IsErrorNodeGen.create(); + + @Child + private TryableNullableNodes.GetErrorNode getFailureNode = + TryableNullableNodesFactory.GetErrorNodeGen.create(); + public TryableUnsafeWriteJsonNode(ProgramStatementNode childProgramStatementNode) { this.childDirectCall = DirectCallNode.create(childProgramStatementNode.getCallTarget()); } @@ -35,10 +44,10 @@ public void executeVoid(VirtualFrame frame) { Object[] args = frame.getArguments(); Object tryable = args[0]; JsonGenerator gen = (JsonGenerator) args[1]; - if (Tryable.isSuccess(tryable)) { + if (!isErrorNode.execute(this, tryable)) { childDirectCall.call(tryable, gen); } else { - throw new JsonWriterRawTruffleException(Tryable.getFailure(tryable), this); + throw new JsonWriterRawTruffleException(getFailureNode.execute(this, tryable), this); } } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/internal/TryableWriteJsonNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/internal/TryableWriteJsonNode.java index 9882bf03a..98f938934 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/internal/TryableWriteJsonNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/json/writer/internal/TryableWriteJsonNode.java @@ -20,7 +20,8 @@ import raw.runtime.truffle.ast.ProgramStatementNode; import raw.runtime.truffle.ast.io.json.writer.JsonWriteNodes; import raw.runtime.truffle.ast.io.json.writer.JsonWriteNodesFactory; -import raw.runtime.truffle.tryable_nullable.Tryable; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodesFactory; @NodeInfo(shortName = "TryableWriteJson") public class TryableWriteJsonNode extends StatementNode { @@ -31,6 +32,14 @@ public class TryableWriteJsonNode extends StatementNode { JsonWriteNodes.WriteStringJsonWriterNode writeString = JsonWriteNodesFactory.WriteStringJsonWriterNodeGen.create(); + @Child + private TryableNullableNodes.IsErrorNode isErrorNode = + TryableNullableNodesFactory.IsErrorNodeGen.create(); + + @Child + private TryableNullableNodes.GetErrorNode getErrorNode = + TryableNullableNodesFactory.GetErrorNodeGen.create(); + public TryableWriteJsonNode(ProgramStatementNode childProgramStatementNode) { this.childDirectCall = DirectCallNode.create(childProgramStatementNode.getCallTarget()); } @@ -40,10 +49,10 @@ public void executeVoid(VirtualFrame frame) { Object[] args = frame.getArguments(); Object tryable = args[0]; JsonGenerator gen = (JsonGenerator) args[1]; - if (Tryable.isSuccess(tryable)) { + if (!isErrorNode.execute(this, tryable)) { childDirectCall.call(tryable, gen); } else { - writeString.execute(this, Tryable.getFailure(tryable), gen); + writeString.execute(this, getErrorNode.execute(this, tryable), gen); } } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/kryo/KryoFromNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/kryo/KryoFromNode.java index 4f20f5226..f87b1e25b 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/kryo/KryoFromNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/kryo/KryoFromNode.java @@ -17,7 +17,6 @@ import java.io.ByteArrayInputStream; import raw.compiler.rql2.source.Rql2TypeWithProperties; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.runtime.kryo.KryoNodes; import raw.runtime.truffle.runtime.kryo.KryoNodesFactory; @@ -35,7 +34,7 @@ public KryoFromNode(ExpressionNode valueNode, Rql2TypeWithProperties t) { public Object executeGeneric(VirtualFrame virtualFrame) { byte[] binary = (byte[]) valueNode.executeGeneric(virtualFrame); Input input = new Input(new ByteArrayInputStream(binary)); - Object object = reader.execute(this, RawLanguage.get(this), input, t); + Object object = reader.execute(this, input, t); input.close(); return object; } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/xml/parser/RecordParseXmlNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/xml/parser/RecordParseXmlNode.java index b18dcd00f..456a7c4af 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/xml/parser/RecordParseXmlNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/xml/parser/RecordParseXmlNode.java @@ -12,6 +12,8 @@ package raw.runtime.truffle.ast.io.xml.parser; +import static raw.runtime.truffle.ast.expressions.record.RecordStaticInitializers.hasDuplicateKeys; + import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; @@ -27,15 +29,13 @@ import raw.runtime.truffle.runtime.primitives.NullObject; import raw.runtime.truffle.runtime.record.RecordNodes; import raw.runtime.truffle.runtime.record.RecordNodesFactory; -import raw.runtime.truffle.runtime.record.RecordObject; @NodeInfo(shortName = "RecordParseXml") public class RecordParseXmlNode extends ExpressionNode { - @Child - private RecordNodes.WriteIndexNode writeIndexNode = RecordNodesFactory.WriteIndexNodeGen.create(); + @Children private final RecordNodes.AddPropNode[] addPropNode; - @Children private DirectCallNode[] childDirectCalls; + @Children private final DirectCallNode[] childDirectCalls; // Field name and its index in the childDirectCalls array private final int fieldsSize; @@ -47,6 +47,9 @@ public class RecordParseXmlNode extends ExpressionNode { private final Map collectionsIndex = new HashMap<>(); private final BitSet refBitSet; private final BitSet bitSet; + private final boolean hasDuplicateKeys; + + private final RawLanguage language = RawLanguage.get(this); public RecordParseXmlNode( ProgramExpressionNode[] childProgramExpressionNode, @@ -56,6 +59,7 @@ public RecordParseXmlNode( this.fields = fieldNames; this.fieldsSize = childProgramExpressionNode.length; this.childDirectCalls = new DirectCallNode[this.fieldsSize]; + this.addPropNode = new RecordNodes.AddPropNode[this.fieldsSize]; refBitSet = new BitSet(this.fieldsSize); for (int index = 0; index < this.fieldsSize; index++) { String fieldName = fieldNames[index]; @@ -73,8 +77,11 @@ public RecordParseXmlNode( collectionsIndex.put(fieldName, index); refBitSet.set(index); } + this.addPropNode[index] = RecordNodesFactory.AddPropNodeGen.create(); } bitSet = new BitSet(); + + hasDuplicateKeys = hasDuplicateKeys(fieldNames); } public Object executeGeneric(VirtualFrame frame) { @@ -94,7 +101,12 @@ private Object doExecute(RawTruffleXmlParser parser) { bitSet.or(refBitSet); // the record to be returned - RecordObject record = RawLanguage.get(this).createRecord(); + Object record; + if (hasDuplicateKeys) { + record = language.createDuplicateKeyRecord(); + } else { + record = language.createPureRecord(); + } Vector attributes = parser.attributes(); int nAttributes = attributes.size(); @@ -130,20 +142,22 @@ private Object doExecute(RawTruffleXmlParser parser) { parser.expectEndTag(recordTag); parser.nextToken(); // skip the END_OBJECT token + String[] keys = getKeySet(); // processing lists and collections - for (String fieldName : collectionValues.keySet()) { + for (int i = 0; i < keys.length; i++) { // build an object list (for all cases) - ArrayList items = collectionValues.get(fieldName); + ArrayList items = collectionValues.get(keys[i]); ObjectList list = new ObjectList(items.toArray()); - int index = collectionsIndex.get(fieldName); + int index = collectionsIndex.get(keys[i]); Type fieldType = fieldTypes[index]; if (fieldType instanceof Rql2IterableType) { // if the collection is an iterable, convert the list to an iterable. - writeIndexNode.execute(this, record, index, fieldName, list.toIterable()); + addPropNode[i].execute(this, record, keys[i], list.toIterable(), hasDuplicateKeys); } else { - writeIndexNode.execute(this, record, index, fieldName, list); + addPropNode[i].execute(this, record, keys[i], list, hasDuplicateKeys); } } + // process nullable fields (null when not found) if (bitSet.cardinality() != this.fieldsSize) { // not all fields were found in the JSON. Fill the missing nullable ones with nulls or @@ -156,7 +170,7 @@ private Object doExecute(RawTruffleXmlParser parser) { // else a plain // null. Object nullValue = NullObject.INSTANCE; - writeIndexNode.execute(this, record, i, fieldName, nullValue); + addPropNode[i].execute(this, record, fieldName, nullValue, hasDuplicateKeys); } else { throw new XmlParserRawTruffleException("field not found: " + fieldName, parser, this); } @@ -166,7 +180,12 @@ private Object doExecute(RawTruffleXmlParser parser) { return record; } - private void parseTagContent(RawTruffleXmlParser parser, String fieldName, RecordObject record) { + @TruffleBoundary + private String[] getKeySet() { + return collectionValues.keySet().toArray(new String[0]); + } + + private void parseTagContent(RawTruffleXmlParser parser, String fieldName, Object record) { Integer index = fieldsIndex.get(fieldName); if (index != null) { applyParser(parser, index, fieldName, record); @@ -176,13 +195,12 @@ private void parseTagContent(RawTruffleXmlParser parser, String fieldName, Recor } } - private void applyParser( - RawTruffleXmlParser parser, int index, String fieldName, RecordObject record) { + private void applyParser(RawTruffleXmlParser parser, int index, String fieldName, Object record) { Object value = childDirectCalls[index].call(parser); storeFieldValue(fieldName, index, value, record); } - private void storeFieldValue(String fieldName, int index, Object value, RecordObject record) { + private void storeFieldValue(String fieldName, int index, Object value, Object record) { ArrayList collectionField = collectionValues.get(fieldName); if (collectionField != null) { // if the field is a collection or a list, add the item to the list instead writing it @@ -190,7 +208,7 @@ private void storeFieldValue(String fieldName, int index, Object value, RecordOb // record. collectionField.add(value); } else { - writeIndexNode.execute(this, record, index, fieldName, value); + addPropNode[index].execute(this, record, fieldName, value, hasDuplicateKeys); bitSet.set(index); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/xml/parser/XmlParseCollectionNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/xml/parser/XmlParseCollectionNode.java index 1441947e2..726c430bd 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/xml/parser/XmlParseCollectionNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/xml/parser/XmlParseCollectionNode.java @@ -52,6 +52,6 @@ public Object executeGeneric(VirtualFrame virtualFrame) { RawTruffleXmlParserSettings settings = new RawTruffleXmlParserSettings(dateFormat, timeFormat, datetimeFormat); SourceContext context = RawContext.get(this).getSourceContext(); - return new XmlParseCollection(text, context, parseNextRootCallTarget, settings); + return new XmlParseCollection(text, parseNextRootCallTarget, settings); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/xml/parser/XmlReadCollectionNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/xml/parser/XmlReadCollectionNode.java index 2550d9c42..c3775f9ae 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/xml/parser/XmlReadCollectionNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/xml/parser/XmlReadCollectionNode.java @@ -16,11 +16,9 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.NodeInfo; import raw.runtime.truffle.ExpressionNode; -import raw.runtime.truffle.RawContext; import raw.runtime.truffle.ast.ProgramExpressionNode; import raw.runtime.truffle.runtime.iterable.sources.XmlReadCollection; import raw.runtime.truffle.runtime.primitives.LocationObject; -import raw.sources.api.SourceContext; @NodeInfo(shortName = "XmlReadCollection") public class XmlReadCollectionNode extends ExpressionNode { @@ -56,7 +54,6 @@ public Object executeGeneric(VirtualFrame virtualFrame) { String datetimeFormat = (String) datetimeFormatExp.executeGeneric(virtualFrame); RawTruffleXmlParserSettings settings = new RawTruffleXmlParserSettings(dateFormat, timeFormat, datetimeFormat); - SourceContext context = RawContext.get(this).getSourceContext(); - return new XmlReadCollection(locationObject, encoding, context, parseRootCallTarget, settings); + return new XmlReadCollection(locationObject, encoding, parseRootCallTarget, settings); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/xml/parser/XmlReadValueNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/xml/parser/XmlReadValueNode.java index 44283f4fb..46f91fc06 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/xml/parser/XmlReadValueNode.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/io/xml/parser/XmlReadValueNode.java @@ -37,6 +37,8 @@ public class XmlReadValueNode extends ExpressionNode { @Child private DirectCallNode childDirectCall; + private final SourceContext sourceContext = RawContext.get(this).getSourceContext(); + public XmlReadValueNode( ExpressionNode locationExp, ExpressionNode encodingExp, @@ -58,9 +60,8 @@ public Object executeGeneric(VirtualFrame virtualFrame) { try { LocationObject locationObject = (LocationObject) locationExp.executeGeneric(virtualFrame); String encoding = (String) encodingExp.executeGeneric(virtualFrame); - SourceContext context = RawContext.get(this).getSourceContext(); - - TruffleInputStream truffleInputStream = new TruffleInputStream(locationObject, context); + TruffleInputStream truffleInputStream = + new TruffleInputStream(locationObject, this.sourceContext); TruffleCharInputStream stream = new TruffleCharInputStream(truffleInputStream, encoding); String dateFormat = (String) dateFormatExp.executeGeneric(virtualFrame); String timeFormat = (String) timeFormatExp.executeGeneric(virtualFrame); diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/OSRGeneratorNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/OSRGeneratorNode.java new file mode 100644 index 000000000..452f5220c --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/OSRGeneratorNode.java @@ -0,0 +1,49 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.RepeatingNode; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; + +public class OSRGeneratorNode extends Node implements RepeatingNode { + + @Child private ExpressionNode conditionNode; + + @Child private ExpressionNode bodyNode; + + public OSRGeneratorNode(ExpressionNode conditionNode, ExpressionNode bodyNode) { + this.conditionNode = conditionNode; + this.bodyNode = bodyNode; + } + + public boolean executeRepeating(VirtualFrame frame) { + try { + if (conditionNode.executeBoolean(frame)) { + bodyNode.executeVoid(frame); + return true; + } + return false; + } catch (UnexpectedResultException e) { + throw new RawTruffleInternalErrorException(e); + } + } + + @Override + public String toString() { + return bodyNode.toString(); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRCollectionEquiJoinInitBodyNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRCollectionEquiJoinInitBodyNode.java new file mode 100644 index 000000000..e210080ad --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRCollectionEquiJoinInitBodyNode.java @@ -0,0 +1,63 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.bodies; + +import com.oracle.truffle.api.frame.VirtualFrame; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; +import raw.runtime.truffle.runtime.function.FunctionExecuteNodesFactory; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; +import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.OffHeapNodes; +import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.OffHeapNodesFactory; + +public class OSRCollectionEquiJoinInitBodyNode extends ExpressionNode { + + @Child + private GeneratorNodes.GeneratorNextNode nextNode = + GeneratorNodesFactory.GeneratorNextNodeGen.create(); + + @Child + FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode = + FunctionExecuteNodesFactory.FunctionExecuteOneNodeGen.create(); + + @Child + OffHeapNodes.OffHeapGroupByPutNode putNode = + OffHeapNodesFactory.OffHeapGroupByPutNodeGen.create(); + + private final int generatorSlot; + private final int keyFunctionSlot; + private final int mapSlot; + + public OSRCollectionEquiJoinInitBodyNode(int generatorSlot, int keyFunctionSlot, int mapSlot) { + this.generatorSlot = generatorSlot; + this.keyFunctionSlot = keyFunctionSlot; + this.mapSlot = mapSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object generator = frame.getObject(generatorSlot); + Object keyFunc = frame.getObject(keyFunctionSlot); + Object map = frame.getObject(mapSlot); + Object item = nextNode.execute(this, generator); + Object key = functionExecuteOneNode.execute(this, keyFunc, item); + putNode.execute(this, map, key, item); + return null; + } + + @Override + public void executeVoid(VirtualFrame virtualFrame) { + executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRCollectionFilterBodyNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRCollectionFilterBodyNode.java new file mode 100644 index 000000000..2bc7b420f --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRCollectionFilterBodyNode.java @@ -0,0 +1,69 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.bodies; + +import com.oracle.truffle.api.frame.VirtualFrame; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; +import raw.runtime.truffle.runtime.function.FunctionExecuteNodesFactory; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodesFactory; + +public class OSRCollectionFilterBodyNode extends ExpressionNode { + + @Child + private GeneratorNodes.GeneratorNextNode nextNode = + GeneratorNodesFactory.GeneratorNextNodeGen.create(); + + @Child + FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode = + FunctionExecuteNodesFactory.FunctionExecuteOneNodeGen.create(); + + @Child + TryableNullableNodes.HandlePredicateNode handlePredicateNode = + TryableNullableNodesFactory.HandlePredicateNodeGen.create(); + + private final int generatorSlot; + + private final int functionSlot; + + private final int resultSlot; + + public OSRCollectionFilterBodyNode(int generatorSlot, int functionSlot, int resultSlot) { + this.generatorSlot = generatorSlot; + this.functionSlot = functionSlot; + this.resultSlot = resultSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object generator = frame.getObject(generatorSlot); + Object predicate = frame.getObject(functionSlot); + Object v = nextNode.execute(this, generator); + + boolean isPredicateTrue = + handlePredicateNode.execute( + this, functionExecuteOneNode.execute(this, predicate, v), false); + if (isPredicateTrue) { + frame.setObject(resultSlot, v); + } + return null; + } + + @Override + public void executeVoid(VirtualFrame virtualFrame) { + executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRCollectionJoinInitBodyNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRCollectionJoinInitBodyNode.java new file mode 100644 index 000000000..a2d609939 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRCollectionJoinInitBodyNode.java @@ -0,0 +1,58 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.bodies; + +import com.esotericsoftware.kryo.io.Output; +import com.oracle.truffle.api.frame.VirtualFrame; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; +import raw.runtime.truffle.runtime.generator.collection.abstract_generator.compute_next.operations.JoinComputeNext; +import raw.runtime.truffle.runtime.kryo.KryoNodes; +import raw.runtime.truffle.runtime.kryo.KryoNodesFactory; + +public class OSRCollectionJoinInitBodyNode extends ExpressionNode { + + @Child + private GeneratorNodes.GeneratorNextNode nextNode = + GeneratorNodesFactory.GeneratorNextNodeGen.create(); + + @Child KryoNodes.KryoWriteNode kryoWrite = KryoNodesFactory.KryoWriteNodeGen.create(); + + private final int generatorSlot; + private final int computeNextSlot; + private final int outputBufferSlot; + + public OSRCollectionJoinInitBodyNode( + int generatorSlot, int computeNextSlot, int outputBufferSlot) { + this.generatorSlot = generatorSlot; + this.computeNextSlot = computeNextSlot; + this.outputBufferSlot = outputBufferSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object generator = frame.getObject(generatorSlot); + JoinComputeNext computeNext = (JoinComputeNext) frame.getObject(computeNextSlot); + Output buffer = (Output) frame.getObject(outputBufferSlot); + Object row = nextNode.execute(this, generator); + kryoWrite.execute(this, buffer, computeNext.getRightRowType(), row); + computeNext.setSpilledRight(computeNext.getSpilledRight() + 1); + return null; + } + + @Override + public void executeVoid(VirtualFrame virtualFrame) { + executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRCollectionMkStringBodyNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRCollectionMkStringBodyNode.java new file mode 100644 index 000000000..f66002f64 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRCollectionMkStringBodyNode.java @@ -0,0 +1,57 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.bodies; + +import com.oracle.truffle.api.frame.VirtualFrame; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; +import raw.runtime.truffle.runtime.operators.OperatorNodes; +import raw.runtime.truffle.runtime.operators.OperatorNodesFactory; + +public class OSRCollectionMkStringBodyNode extends ExpressionNode { + + @Child + private GeneratorNodes.GeneratorNextNode nextNode = + GeneratorNodesFactory.GeneratorNextNodeGen.create(); + + @Child OperatorNodes.AddNode add = OperatorNodesFactory.AddNodeGen.create(); + + private final int generatorSlot; + + private final int sepSlot; + + private final int resultSlot; + + public OSRCollectionMkStringBodyNode(int generatorSlot, int sepSlot, int resultSlot) { + this.generatorSlot = generatorSlot; + this.sepSlot = sepSlot; + this.resultSlot = resultSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object generator = frame.getObject(generatorSlot); + Object next = nextNode.execute(this, generator); + String sep = frame.getObject(sepSlot).toString(); + String resultString = frame.getObject(resultSlot).toString(); + String newResult = (String) add.execute(this, resultString + sep, next); + frame.setObject(resultSlot, newResult); + return null; + } + + @Override + public void executeVoid(VirtualFrame virtualFrame) { + executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRDistinctGetGeneratorNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRDistinctGetGeneratorNode.java new file mode 100644 index 000000000..1b9f13c35 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRDistinctGetGeneratorNode.java @@ -0,0 +1,56 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.bodies; + +import com.oracle.truffle.api.frame.VirtualFrame; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; +import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.OffHeapNodes; +import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.OffHeapNodesFactory; +import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.distinct.OffHeapDistinct; + +public class OSRDistinctGetGeneratorNode extends ExpressionNode { + + @Child + private GeneratorNodes.GeneratorNextNode nextNode = + GeneratorNodesFactory.GeneratorNextNodeGen.create(); + + @Child + OffHeapNodes.OffHeapGroupByPutNode putNode = + OffHeapNodesFactory.OffHeapGroupByPutNodeGen.create(); + + private final int generatorSlot; + + private final int offHeapDistinctSlot; + + public OSRDistinctGetGeneratorNode(int generatorSlot, int offHeapDistinctSlot) { + this.generatorSlot = generatorSlot; + this.offHeapDistinctSlot = offHeapDistinctSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object generator = frame.getObject(generatorSlot); + OffHeapDistinct index = (OffHeapDistinct) frame.getObject(offHeapDistinctSlot); + + Object next = nextNode.execute(this, generator); + putNode.execute(this, index, next, null); + return null; + } + + @Override + public void executeVoid(VirtualFrame virtualFrame) { + executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSREquiJoinNextBodyNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSREquiJoinNextBodyNode.java new file mode 100644 index 000000000..ffaa4091c --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSREquiJoinNextBodyNode.java @@ -0,0 +1,106 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.bodies; + +import com.oracle.truffle.api.frame.VirtualFrame; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.runtime.exceptions.BreakException; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; +import raw.runtime.truffle.runtime.generator.collection.abstract_generator.compute_next.operations.EquiJoinComputeNext; +import raw.runtime.truffle.runtime.operators.OperatorNodes; +import raw.runtime.truffle.runtime.operators.OperatorNodesFactory; + +public class OSREquiJoinNextBodyNode extends ExpressionNode { + + @Child + private GeneratorNodes.GeneratorHasNextNode hasNextNode1 = + GeneratorNodesFactory.GeneratorHasNextNodeGen.create(); + + @Child + private GeneratorNodes.GeneratorHasNextNode hasNextNode2 = + GeneratorNodesFactory.GeneratorHasNextNodeGen.create(); + + @Child + private GeneratorNodes.GeneratorNextNode nextNode1 = + GeneratorNodesFactory.GeneratorNextNodeGen.create(); + + @Child + private GeneratorNodes.GeneratorNextNode nextNode2 = + GeneratorNodesFactory.GeneratorNextNodeGen.create(); + + @Child OperatorNodes.CompareNode compareKey = OperatorNodesFactory.CompareNodeGen.create(); + + private final int computeNextSlot; + private final int shouldContinueSlot; + + public OSREquiJoinNextBodyNode(int computeNextSlot, int shouldContinueSlot) { + this.computeNextSlot = computeNextSlot; + this.shouldContinueSlot = shouldContinueSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + EquiJoinComputeNext computeNext = (EquiJoinComputeNext) frame.getObject(computeNextSlot); + if (computeNext.getLeftKey() == null || computeNext.getRightKey() == null) { + if (computeNext.getLeftKey() == null) { + if (hasNextNode1.execute(this, computeNext.getLeftMapGenerator())) { + computeNext.setLeftEntry( + (Object[]) nextNode1.execute(this, computeNext.getLeftMapGenerator())); + computeNext.setLeftKey(computeNext.getLeftEntry()[0]); + } else { + throw new BreakException(); + } + } + + if (computeNext.getRightKey() == null) { + if (hasNextNode2.execute(this, computeNext.getRightMapGenerator())) { + computeNext.setRightEntry( + (Object[]) nextNode2.execute(this, computeNext.getRightMapGenerator())); + computeNext.setRightKey(computeNext.getRightEntry()[0]); + } else { + throw new BreakException(); + } + } + + int compare = compareKey.execute(this, computeNext.getLeftKey(), computeNext.getRightKey()); + // if keys aren't equal, reset the smallest of both (it will be read in the next + // iteration and + // will be larger) + if (compare < 0) { + computeNext.setLeftKey(null); + } else if (compare > 0) { + computeNext.setRightKey(null); + } else { + // keys are equal, prepare to do the cartesian product between both. + // leftRows and rightRows are the arrays of rows with the same key. + // We'll iterate over them to produce the cartesian product. + computeNext.setLeftRows((Object[]) computeNext.getLeftEntry()[1]); + computeNext.setRightRows((Object[]) computeNext.getRightEntry()[1]); + computeNext.setLeftIndex(0); + computeNext.setRightIndex(0); + frame.setBoolean(shouldContinueSlot, false); + return null; + } + frame.setBoolean(shouldContinueSlot, true); + return null; + } + frame.setBoolean(shouldContinueSlot, false); + return null; + } + + @Override + public void executeVoid(VirtualFrame virtualFrame) { + executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRExistsBodyNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRExistsBodyNode.java new file mode 100644 index 000000000..458f0d0d7 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRExistsBodyNode.java @@ -0,0 +1,65 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.bodies; + +import com.oracle.truffle.api.frame.VirtualFrame; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; +import raw.runtime.truffle.runtime.function.FunctionExecuteNodesFactory; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodesFactory; + +public class OSRExistsBodyNode extends ExpressionNode { + + @Child + private GeneratorNodes.GeneratorNextNode nextNode = + GeneratorNodesFactory.GeneratorNextNodeGen.create(); + + @Child + FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode = + FunctionExecuteNodesFactory.FunctionExecuteOneNodeGen.create(); + + @Child + TryableNullableNodes.HandlePredicateNode handlePredicateNode = + TryableNullableNodesFactory.HandlePredicateNodeGen.create(); + + private final int generatorSlot; + private final int functionSlot; + private final int predicateResultSlot; + + public OSRExistsBodyNode(int generatorSlot, int functionSlot, int predicateResultSlot) { + this.generatorSlot = generatorSlot; + this.functionSlot = functionSlot; + this.predicateResultSlot = predicateResultSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object generator = frame.getObject(generatorSlot); + Object function = frame.getObject(functionSlot); + boolean result = + handlePredicateNode.execute( + this, + functionExecuteOneNode.execute(this, function, nextNode.execute(this, generator)), + false); + frame.setBoolean(predicateResultSlot, result); + return null; + } + + @Override + public void executeVoid(VirtualFrame virtualFrame) { + executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRJoinNextBodyNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRJoinNextBodyNode.java new file mode 100644 index 000000000..5a29cc030 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRJoinNextBodyNode.java @@ -0,0 +1,160 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.bodies; + +import com.esotericsoftware.kryo.io.Input; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.runtime.exceptions.BreakException; +import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; +import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; +import raw.runtime.truffle.runtime.function.FunctionExecuteNodesFactory; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; +import raw.runtime.truffle.runtime.generator.collection.abstract_generator.compute_next.operations.JoinComputeNext; +import raw.runtime.truffle.runtime.kryo.KryoNodes; +import raw.runtime.truffle.runtime.kryo.KryoNodesFactory; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodesFactory; + +public class OSRJoinNextBodyNode extends ExpressionNode { + + @Child + private GeneratorNodes.GeneratorHasNextNode hasNextNode = + GeneratorNodesFactory.GeneratorHasNextNodeGen.create(); + + @Child + private GeneratorNodes.GeneratorNextNode nextNode = + GeneratorNodesFactory.GeneratorNextNodeGen.create(); + + @Child + FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode = + FunctionExecuteNodesFactory.FunctionExecuteOneNodeGen.create(); + + @Child + FunctionExecuteNodes.FunctionExecuteTwo functionExecuteTwoNode = + FunctionExecuteNodesFactory.FunctionExecuteTwoNodeGen.create(); + + @Child KryoNodes.KryoReadNode kryoReadNode = KryoNodesFactory.KryoReadNodeGen.create(); + + @Child + TryableNullableNodes.HandlePredicateNode handlePredicateNode = + TryableNullableNodesFactory.HandlePredicateNodeGen.create(); + + private final int computeNextSlot; + private final int shouldContinueSlot; + private final int resultSlot; + + public OSRJoinNextBodyNode(int computeNextSlot, int shouldContinueSlot, int resultSlot) { + this.computeNextSlot = computeNextSlot; + this.shouldContinueSlot = shouldContinueSlot; + this.resultSlot = resultSlot; + } + + @CompilerDirectives.TruffleBoundary + private Input createInput(File file, Node node) { + try { + return new Input(new FileInputStream(file)); + } catch (FileNotFoundException e) { + throw new RawTruffleRuntimeException(e.getMessage(), e, node); + } + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object row = null; + JoinComputeNext computeNext = (JoinComputeNext) frame.getObject(computeNextSlot); + if (computeNext.getLeftRow() == null || computeNext.getRightRow() == null) { + if (computeNext.getLeftRow() == null) { + if (hasNextNode.execute(this, computeNext.getLeftGen())) { + computeNext.setLeftRow(nextNode.execute(this, computeNext.getLeftGen())); + } else { + // end of left, nothing else to read + throw new BreakException(); + } + } + if (computeNext.getKryoRight() == null) { + computeNext.setKryoRight(createInput(computeNext.getDiskRight(), this)); + computeNext.setReadRight(0); + } + if (computeNext.getRightRow() == null) { + if (computeNext.getReadRight() < computeNext.getSpilledRight()) { + computeNext.setRightRow( + kryoReadNode.execute( + this, computeNext.getKryoRight(), computeNext.getRightRowType())); + boolean pass; + if (computeNext.getReshapeBeforePredicate()) { + row = + functionExecuteTwoNode.execute( + this, + computeNext.getRemap(), + computeNext.getLeftRow(), + computeNext.getRightRow()); + pass = + handlePredicateNode.execute( + this, + functionExecuteOneNode.execute(this, computeNext.getPredicate(), row), + false); + if (!pass) row = null; + } else { + pass = + handlePredicateNode.execute( + this, + functionExecuteTwoNode.execute( + this, + computeNext.getPredicate(), + computeNext.getLeftRow(), + computeNext.getRightRow()), + false); + if (pass) + row = + functionExecuteTwoNode.execute( + this, + computeNext.getRemap(), + computeNext.getLeftRow(), + computeNext.getRightRow()); + } + + computeNext.setReadRight(computeNext.getReadRight() + 1); + computeNext.setRightRow(null); + } else { + // end of right, reset currentLeft to make sure we try another round + computeNext.setLeftRow(null); + closeInput(computeNext.getKryoRight()); + computeNext.setRightRow(null); + computeNext.setKryoRight(null); + } + } + } + if (row != null) { + frame.setBoolean(shouldContinueSlot, false); + frame.setObject(resultSlot, row); + } + return null; + } + + @CompilerDirectives.TruffleBoundary + private void closeInput(Input input) { + input.close(); + } + + @Override + public void executeVoid(VirtualFrame virtualFrame) { + executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListEquiJoinInitBodyNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListEquiJoinInitBodyNode.java new file mode 100644 index 000000000..ee9dad301 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListEquiJoinInitBodyNode.java @@ -0,0 +1,63 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.bodies; + +import com.oracle.truffle.api.frame.VirtualFrame; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; +import raw.runtime.truffle.runtime.function.FunctionExecuteNodesFactory; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; +import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.OffHeapNodes; +import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.OffHeapNodesFactory; + +public class OSRListEquiJoinInitBodyNode extends ExpressionNode { + + @Child + private GeneratorNodes.GeneratorNextNode nextNode = + GeneratorNodesFactory.GeneratorNextNodeGen.create(); + + @Child + FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode = + FunctionExecuteNodesFactory.FunctionExecuteOneNodeGen.create(); + + @Child + OffHeapNodes.OffHeapGroupByPutNode putNode = + OffHeapNodesFactory.OffHeapGroupByPutNodeGen.create(); + + private final int generatorSlot; + private final int keyFunctionSlot; + private final int mapSlot; + + public OSRListEquiJoinInitBodyNode(int generatorSlot, int keyFunctionSlot, int mapSlot) { + this.generatorSlot = generatorSlot; + this.keyFunctionSlot = keyFunctionSlot; + this.mapSlot = mapSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object generator = frame.getObject(generatorSlot); + Object keyFunc = frame.getObject(keyFunctionSlot); + Object map = frame.getObject(mapSlot); + Object item = nextNode.execute(this, generator); + Object key = functionExecuteOneNode.execute(this, keyFunc, item); + putNode.execute(this, map, key, item); + return null; + } + + @Override + public void executeVoid(VirtualFrame virtualFrame) { + executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListFilterBodyNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListFilterBodyNode.java new file mode 100644 index 000000000..00d166dce --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListFilterBodyNode.java @@ -0,0 +1,69 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.bodies; + +import com.oracle.truffle.api.frame.VirtualFrame; +import java.util.ArrayList; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; +import raw.runtime.truffle.runtime.function.FunctionExecuteNodesFactory; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodesFactory; + +public class OSRListFilterBodyNode extends ExpressionNode { + + @Child + private GeneratorNodes.GeneratorNextNode nextNode = + GeneratorNodesFactory.GeneratorNextNodeGen.create(); + + @Child + FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode = + FunctionExecuteNodesFactory.FunctionExecuteOneNodeGen.create(); + + @Child + TryableNullableNodes.HandlePredicateNode handlePredicateNode = + TryableNullableNodesFactory.HandlePredicateNodeGen.create(); + + private final int generatorSlot; + private final int functionSlot; + private final int llistSlot; + + public OSRListFilterBodyNode(int generatorSlot, int functionSlot, int llistSlot) { + this.generatorSlot = generatorSlot; + this.functionSlot = functionSlot; + this.llistSlot = llistSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object generator = frame.getObject(generatorSlot); + Object v = nextNode.execute(this, generator); + Boolean predicate = null; + Object function = frame.getObject(functionSlot); + predicate = + handlePredicateNode.execute(this, functionExecuteOneNode.execute(this, function, v), false); + if (predicate) { + @SuppressWarnings("unchecked") + ArrayList llist = (ArrayList) frame.getObject(llistSlot); + llist.add(v); + } + return null; + } + + @Override + public void executeVoid(VirtualFrame virtualFrame) { + executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListFromBodyNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListFromBodyNode.java new file mode 100644 index 000000000..486b620bf --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListFromBodyNode.java @@ -0,0 +1,48 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.bodies; + +import com.oracle.truffle.api.frame.VirtualFrame; +import java.util.ArrayList; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; + +public class OSRListFromBodyNode extends ExpressionNode { + + @Child + private GeneratorNodes.GeneratorNextNode nextNode = + GeneratorNodesFactory.GeneratorNextNodeGen.create(); + + private final int generatorSlot; + private final int llistSlot; + + public OSRListFromBodyNode(int generatorSlot, int llistSlot) { + this.generatorSlot = generatorSlot; + this.llistSlot = llistSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object generator = frame.getObject(generatorSlot); + @SuppressWarnings("unchecked") + ArrayList llist = (ArrayList) frame.getObject(llistSlot); + llist.add(nextNode.execute(this, generator)); + return null; + } + + @Override + public void executeVoid(VirtualFrame virtualFrame) { + executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListParseJsonBodyNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListParseJsonBodyNode.java new file mode 100644 index 000000000..0be92ba6e --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListParseJsonBodyNode.java @@ -0,0 +1,48 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.bodies; + +import com.oracle.truffle.api.RootCallTarget; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.DirectCallNode; +import java.util.ArrayList; +import raw.runtime.truffle.ExpressionNode; + +public class OSRListParseJsonBodyNode extends ExpressionNode { + + @Child DirectCallNode childCallNode; + + private final int llistSlot; + private final int parserSlot; + + public OSRListParseJsonBodyNode( + RootCallTarget childRootCallTarget, int llistSlot, int parserSlot) { + this.childCallNode = DirectCallNode.create(childRootCallTarget); + this.llistSlot = llistSlot; + this.parserSlot = parserSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object parser = frame.getObject(parserSlot); + @SuppressWarnings("unchecked") + ArrayList llist = (ArrayList) frame.getObject(llistSlot); + llist.add(childCallNode.call(parser)); + return null; + } + + @Override + public void executeVoid(VirtualFrame virtualFrame) { + executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListTransformBodyNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListTransformBodyNode.java new file mode 100644 index 000000000..1c712c08a --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRListTransformBodyNode.java @@ -0,0 +1,70 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.bodies; + +import com.oracle.truffle.api.frame.VirtualFrame; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.ast.expressions.iterable.ArrayOperationNodes; +import raw.runtime.truffle.ast.expressions.iterable.ArrayOperationNodesFactory; +import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; +import raw.runtime.truffle.runtime.function.FunctionExecuteNodesFactory; +import raw.runtime.truffle.runtime.list.ListNodes; +import raw.runtime.truffle.runtime.list.ListNodesFactory; + +public class OSRListTransformBodyNode extends ExpressionNode { + + @Child + FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode = + FunctionExecuteNodesFactory.FunctionExecuteOneNodeGen.create(); + + @Child ListNodes.GetNode getNode = ListNodesFactory.GetNodeGen.create(); + + @Child + ArrayOperationNodes.ArraySetArrayItemNode arraySetNode = + ArrayOperationNodesFactory.ArraySetArrayItemNodeGen.create(); + + private final int listSlot; + private final int functionSlot; + private final int currentIdxSlot; + private final int resultSlot; + + public OSRListTransformBodyNode( + int listSlot, int functionSlot, int currentIdxSlot, int resultSlot) { + this.currentIdxSlot = currentIdxSlot; + this.resultSlot = resultSlot; + this.listSlot = listSlot; + this.functionSlot = functionSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + int currentIdx = frame.getInt(currentIdxSlot); + Object transformFunction = frame.getObject(functionSlot); + Object transformingList = frame.getObject(listSlot); + Object resultArray = frame.getObject(resultSlot); + + Object transformedItem = + functionExecuteOneNode.execute( + this, transformFunction, getNode.execute(this, transformingList, currentIdx)); + + arraySetNode.execute(this, resultArray, transformedItem, currentIdx); + + frame.setInt(currentIdxSlot, currentIdx + 1); + return null; + } + + @Override + public void executeVoid(VirtualFrame virtualFrame) { + executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRMultiAggregationBodyNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRMultiAggregationBodyNode.java new file mode 100644 index 000000000..fefe24432 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRMultiAggregationBodyNode.java @@ -0,0 +1,59 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.bodies; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.ExplodeLoop; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.ast.expressions.aggregation.AggregatorNodes; +import raw.runtime.truffle.ast.expressions.aggregation.AggregatorNodesFactory; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; + +public class OSRMultiAggregationBodyNode extends ExpressionNode { + + @Child + private GeneratorNodes.GeneratorNextNode nextNode = + GeneratorNodesFactory.GeneratorNextNodeGen.create(); + + @Child AggregatorNodes.Merge mergeNode = AggregatorNodesFactory.MergeNodeGen.create(); + private final byte[] aggregationTypes; + private final int resultSlot; + private final int generatorSlot; + private final int aggregationLength; + + public OSRMultiAggregationBodyNode(byte[] aggregationTypes, int generatorSlot, int resultSlot) { + this.resultSlot = resultSlot; + this.generatorSlot = generatorSlot; + this.aggregationTypes = aggregationTypes; + this.aggregationLength = aggregationTypes.length; + } + + @Override + @ExplodeLoop + public Object executeGeneric(VirtualFrame frame) { + Object generator = frame.getObject(generatorSlot); + Object next = nextNode.execute(this, generator); + Object[] currentResults = (Object[]) frame.getObject(resultSlot); + for (int i = 0; i < aggregationLength; i++) { + currentResults[i] = mergeNode.execute(this, aggregationTypes[i], currentResults[i], next); + } + frame.setObject(resultSlot, currentResults); + return null; + } + + @Override + public void executeVoid(VirtualFrame virtualFrame) { + executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSROrderByGetGeneratorNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSROrderByGetGeneratorNode.java new file mode 100644 index 000000000..baa958019 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSROrderByGetGeneratorNode.java @@ -0,0 +1,74 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.bodies; + +import com.oracle.truffle.api.frame.VirtualFrame; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; +import raw.runtime.truffle.runtime.function.FunctionExecuteNodesFactory; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; +import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.OffHeapNodes; +import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.OffHeapNodesFactory; +import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.order_by.OffHeapGroupByKeys; +import raw.runtime.truffle.runtime.iterable.operations.OrderByCollection; + +public class OSROrderByGetGeneratorNode extends ExpressionNode { + + @Child + private GeneratorNodes.GeneratorNextNode nextNode = + GeneratorNodesFactory.GeneratorNextNodeGen.create(); + + @Child + OffHeapNodes.OffHeapGroupByPutNode putNode = + OffHeapNodesFactory.OffHeapGroupByPutNodeGen.create(); + + @Child + private FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode = + FunctionExecuteNodesFactory.FunctionExecuteOneNodeGen.create(); + + private final int generatorSlot; + private final int collectionSlot; + private final int offHeapGroupByKeysSlot; + + public OSROrderByGetGeneratorNode( + int generatorSlot, int collectionSlot, int offHeapGroupByKeysSlot) { + this.generatorSlot = generatorSlot; + this.collectionSlot = collectionSlot; + this.offHeapGroupByKeysSlot = offHeapGroupByKeysSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object generator = frame.getObject(generatorSlot); + + OrderByCollection collection = (OrderByCollection) frame.getObject(collectionSlot); + + OffHeapGroupByKeys groupByKeys = (OffHeapGroupByKeys) frame.getObject(offHeapGroupByKeysSlot); + + int funLen = collection.getKeyFunctions().length; + + Object v = nextNode.execute(this, generator); + Object[] key = new Object[funLen]; + for (int i = 0; i < funLen; i++) { + key[i] = functionExecuteOneNode.execute(this, collection.getKeyFunctions()[i], v); + } + putNode.execute(this, groupByKeys, key, v); + return null; + } + + @Override + public void executeVoid(VirtualFrame virtualFrame) { + executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRSingleAggregationBodyNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRSingleAggregationBodyNode.java new file mode 100644 index 000000000..4273a633b --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRSingleAggregationBodyNode.java @@ -0,0 +1,59 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.bodies; + +import com.oracle.truffle.api.frame.VirtualFrame; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.ast.expressions.aggregation.AggregatorNodes; +import raw.runtime.truffle.ast.expressions.aggregation.AggregatorNodesFactory; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; + +public class OSRSingleAggregationBodyNode extends ExpressionNode { + + @Child + private GeneratorNodes.GeneratorNextNode nextNode = + GeneratorNodesFactory.GeneratorNextNodeGen.create(); + + @Child AggregatorNodes.Merge mergeNode = AggregatorNodesFactory.MergeNodeGen.create(); + + private final byte aggregationType; + private final int resultSlot; + private final int generatorSlot; + + public OSRSingleAggregationBodyNode(byte aggregationType, int generatorSlot, int resultSlot) { + this.resultSlot = resultSlot; + this.generatorSlot = generatorSlot; + this.aggregationType = aggregationType; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object generator = frame.getObject(generatorSlot); + Object next = nextNode.execute(this, generator); + Object currentResult = frame.getObject(resultSlot); + Object newResult = mergeNode.execute(this, aggregationType, currentResult, next); + frame.setObject(resultSlot, newResult); + return null; + } + + @Override + public void executeVoid(VirtualFrame virtualFrame) { + executeGeneric(virtualFrame); + } + + @Override + public String toString() { + return "OSRSingleAggregationBodyNode-Type" + aggregationType; + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRToArrayBodyNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRToArrayBodyNode.java new file mode 100644 index 000000000..b20f81438 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/bodies/OSRToArrayBodyNode.java @@ -0,0 +1,72 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.bodies; + +import com.oracle.truffle.api.frame.VirtualFrame; +import java.util.ArrayList; +import raw.compiler.rql2.source.Rql2Type; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.ast.TypeGuards; + +public class OSRToArrayBodyNode extends ExpressionNode { + + private final Rql2Type resultType; + + private final int listSlot; + + private final int currentIdxSlot; + + private final int resultSlot; + + public OSRToArrayBodyNode(Rql2Type resultType, int listSlot, int currentIdxSlot, int resultSlot) { + this.resultType = resultType; + this.currentIdxSlot = currentIdxSlot; + this.resultSlot = resultSlot; + this.listSlot = listSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + int currentIdx = frame.getInt(currentIdxSlot); + Object result = frame.getObject(resultSlot); + @SuppressWarnings("unchecked") + ArrayList llist = (ArrayList) frame.getObject(listSlot); + + if (TypeGuards.isByteKind(resultType)) { + ((byte[]) result)[currentIdx] = (byte) llist.get(currentIdx); + } else if (TypeGuards.isShortKind(resultType)) { + ((short[]) result)[currentIdx] = (short) llist.get(currentIdx); + } else if (TypeGuards.isIntKind(resultType)) { + ((int[]) result)[currentIdx] = (int) llist.get(currentIdx); + } else if (TypeGuards.isLongKind(resultType)) { + ((long[]) result)[currentIdx] = (long) llist.get(currentIdx); + } else if (TypeGuards.isFloatKind(resultType)) { + ((float[]) result)[currentIdx] = (float) llist.get(currentIdx); + } else if (TypeGuards.isDoubleKind(resultType)) { + ((double[]) result)[currentIdx] = (double) llist.get(currentIdx); + } else if (TypeGuards.isBooleanKind(resultType)) { + ((boolean[]) result)[currentIdx] = (boolean) llist.get(currentIdx); + } else if (TypeGuards.isStringKind(resultType)) { + ((String[]) result)[currentIdx] = (String) llist.get(currentIdx); + } else { + ((Object[]) result)[currentIdx] = llist.get(currentIdx); + } + frame.setInt(currentIdxSlot, currentIdx + 1); + return null; + } + + @Override + public void executeVoid(VirtualFrame virtualFrame) { + executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRCollectionFilterConditionNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRCollectionFilterConditionNode.java new file mode 100644 index 000000000..2cb0ad5b5 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRCollectionFilterConditionNode.java @@ -0,0 +1,47 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.conditions; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; + +public class OSRCollectionFilterConditionNode extends ExpressionNode { + + @Child + private GeneratorNodes.GeneratorHasNextNode hasNextNode = + GeneratorNodesFactory.GeneratorHasNextNodeGen.create(); + + private final int generatorSlot; + + private final int resultSlot; + + public OSRCollectionFilterConditionNode(int generatorSlot, int resultSlot) { + this.generatorSlot = generatorSlot; + this.resultSlot = resultSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object generator = frame.getObject(generatorSlot); + Object result = frame.getObject(resultSlot); + return result == null && hasNextNode.execute(this, generator); + } + + @Override + public boolean executeBoolean(VirtualFrame virtualFrame) throws UnexpectedResultException { + return (boolean) executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRExistsConditionNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRExistsConditionNode.java new file mode 100644 index 000000000..733e21813 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRExistsConditionNode.java @@ -0,0 +1,46 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.conditions; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; + +public class OSRExistsConditionNode extends ExpressionNode { + + @Child + private GeneratorNodes.GeneratorHasNextNode hasNextNode = + GeneratorNodesFactory.GeneratorHasNextNodeGen.create(); + + private final int generatorSlot; + + private final int predicateResultSlot; + + public OSRExistsConditionNode(int generatorSlot, int predicateResultSlot) { + this.generatorSlot = generatorSlot; + this.predicateResultSlot = predicateResultSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + return !frame.getBoolean(predicateResultSlot) + && hasNextNode.execute(this, frame.getObject(generatorSlot)); + } + + @Override + public boolean executeBoolean(VirtualFrame virtualFrame) throws UnexpectedResultException { + return (boolean) executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRFromBodyConditionNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRFromBodyConditionNode.java new file mode 100644 index 000000000..b97609c54 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRFromBodyConditionNode.java @@ -0,0 +1,36 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.conditions; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import raw.runtime.truffle.ExpressionNode; + +public class OSRFromBodyConditionNode extends ExpressionNode { + + private final int shouldContinueSlot; + + public OSRFromBodyConditionNode(int shouldContinueSlot) { + this.shouldContinueSlot = shouldContinueSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + return frame.getBoolean(shouldContinueSlot); + } + + @Override + public boolean executeBoolean(VirtualFrame virtualFrame) throws UnexpectedResultException { + return (boolean) executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRHasNextConditionNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRHasNextConditionNode.java new file mode 100644 index 000000000..f4fb2d1e5 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRHasNextConditionNode.java @@ -0,0 +1,43 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.conditions; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.GeneratorNodesFactory; + +public class OSRHasNextConditionNode extends ExpressionNode { + + @Child + private GeneratorNodes.GeneratorHasNextNode hasNextNode = + GeneratorNodesFactory.GeneratorHasNextNodeGen.create(); + + private final int generatorSlot; + + public OSRHasNextConditionNode(int generatorSlot) { + this.generatorSlot = generatorSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object generator = frame.getObject(generatorSlot); + return hasNextNode.execute(this, generator); + } + + @Override + public boolean executeBoolean(VirtualFrame virtualFrame) throws UnexpectedResultException { + return (boolean) executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRIsLessThanSizeConditionNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRIsLessThanSizeConditionNode.java new file mode 100644 index 000000000..ba84f5465 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRIsLessThanSizeConditionNode.java @@ -0,0 +1,40 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.conditions; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import raw.runtime.truffle.ExpressionNode; + +public class OSRIsLessThanSizeConditionNode extends ExpressionNode { + + private final int currentIdxSlot; + private final int sizeSlot; + + public OSRIsLessThanSizeConditionNode(int currentIdxSlot, int listSizeSlot) { + this.currentIdxSlot = currentIdxSlot; + this.sizeSlot = listSizeSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + int currentIdx = frame.getInt(currentIdxSlot); + int listSize = frame.getInt(sizeSlot); + return currentIdx < listSize; + } + + @Override + public boolean executeBoolean(VirtualFrame virtualFrame) throws UnexpectedResultException { + return (boolean) executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRListParseJsonConditionNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRListParseJsonConditionNode.java new file mode 100644 index 000000000..9152c4296 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/ast/osr/conditions/OSRListParseJsonConditionNode.java @@ -0,0 +1,45 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.ast.osr.conditions; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import raw.runtime.truffle.ExpressionNode; +import raw.runtime.truffle.ast.io.json.reader.JsonParserNodes; +import raw.runtime.truffle.ast.io.json.reader.JsonParserNodesFactory; + +public class OSRListParseJsonConditionNode extends ExpressionNode { + + @Child + JsonParserNodes.CurrentTokenJsonParserNode currentToken = + JsonParserNodesFactory.CurrentTokenJsonParserNodeGen.create(); + + private final int parserSlot; + + public OSRListParseJsonConditionNode(int parserSlot) { + this.parserSlot = parserSlot; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + JsonParser parser = (JsonParser) frame.getObject(parserSlot); + return currentToken.execute(this, parser) != JsonToken.END_ARRAY; + } + + @Override + public boolean executeBoolean(VirtualFrame virtualFrame) throws UnexpectedResultException { + return (boolean) executeGeneric(virtualFrame); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/aggregation/AggregationNodes.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/aggregation/AggregationNodes.java deleted file mode 100644 index c2bf17c41..000000000 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/aggregation/AggregationNodes.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2023 RAW Labs S.A. - * - * Use of this software is governed by the Business Source License - * included in the file licenses/BSL.txt. - * - * As of the Change Date specified in that file, in accordance with - * the Business Source License, use of this software will be governed - * by the Apache License, Version 2.0, included in the file - * licenses/APL.txt. - */ - -package raw.runtime.truffle.runtime.aggregation; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.NodeInfo; -import raw.runtime.truffle.runtime.aggregation.aggregator.AggregatorNodes; -import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; -import raw.runtime.truffle.runtime.iterable.IterableNodes; - -public class AggregationNodes { - @NodeInfo(shortName = "Aggregation.Aggregate") - @GenerateUncached - @GenerateInline - public abstract static class Aggregate extends Node { - - public abstract Object execute(Node node, Object aggregation, Object iterable); - - @Specialization - static Object aggregate( - Node node, - SingleAggregation aggregation, - Object iterable, - @Bind("$node") Node thisNode, - @Cached @Cached.Shared("getGenerator") IterableNodes.GetGeneratorNode getGenerator, - @Cached @Cached.Shared("init") GeneratorNodes.GeneratorInitNode generatorInitNode, - @Cached @Cached.Shared("hasNext") GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached @Cached.Shared("next") GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached @Cached.Shared("close") GeneratorNodes.GeneratorCloseNode generatorCloseNode, - @Cached @Cached.Shared("merge") AggregatorNodes.Merge mergeNode, - @Cached @Cached.Shared("zero") AggregatorNodes.Zero zeroNode) { - Object generator = getGenerator.execute(thisNode, iterable); - try { - generatorInitNode.execute(thisNode, generator); - if (!generatorHasNextNode.execute(thisNode, generator)) { - return zeroNode.execute(thisNode, aggregation.getAggregationType()); - } - Object result = zeroNode.execute(thisNode, aggregation.getAggregationType()); - while (generatorHasNextNode.execute(thisNode, generator)) { - Object next = generatorNextNode.execute(thisNode, generator); - result = mergeNode.execute(thisNode, aggregation.getAggregationType(), result, next); - } - return result; - } finally { - generatorCloseNode.execute(thisNode, generator); - } - } - - @Specialization - static Object aggregate( - Node node, - MultiAggregation aggregation, - Object iterable, - @Bind("$node") Node thisNode, - @Cached @Cached.Shared("getGenerator") IterableNodes.GetGeneratorNode getGenerator, - @Cached @Cached.Shared("init") GeneratorNodes.GeneratorInitNode generatorInitNode, - @Cached @Cached.Shared("hasNext") GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, - @Cached @Cached.Shared("next") GeneratorNodes.GeneratorNextNode generatorNextNode, - @Cached @Cached.Shared("close") GeneratorNodes.GeneratorCloseNode generatorCloseNode, - @Cached @Cached.Shared("merge") AggregatorNodes.Merge mergeNode, - @Cached @Cached.Shared("zero") AggregatorNodes.Zero zeroNode) { - Object generator = getGenerator.execute(thisNode, iterable); - try { - generatorInitNode.execute(thisNode, generator); - Object[] results = new Object[aggregation.getAggregationTypes().length]; - for (int i = 0; i < aggregation.getAggregationTypes().length; i++) { - results[i] = zeroNode.execute(thisNode, aggregation.getAggregationTypes()[i]); - } - if (!generatorHasNextNode.execute(thisNode, generator)) { - return results; - } - while (generatorHasNextNode.execute(thisNode, generator)) { - Object next = generatorNextNode.execute(thisNode, generator); - for (int i = 0; i < aggregation.getAggregationTypes().length; i++) { - results[i] = - mergeNode.execute(thisNode, aggregation.getAggregationTypes()[i], results[i], next); - } - } - return results; - } finally { - generatorCloseNode.execute(thisNode, generator); - } - } - } -} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/aggregation/MultiAggregation.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/aggregation/MultiAggregation.java deleted file mode 100644 index 3544e702f..000000000 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/aggregation/MultiAggregation.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2023 RAW Labs S.A. - * - * Use of this software is governed by the Business Source License - * included in the file licenses/BSL.txt. - * - * As of the Change Date specified in that file, in accordance with - * the Business Source License, use of this software will be governed - * by the Apache License, Version 2.0, included in the file - * licenses/APL.txt. - */ - -package raw.runtime.truffle.runtime.aggregation; - -public class MultiAggregation { - private final byte[] aggregationTypes; - - public MultiAggregation(byte[] aggregationTypes) { - this.aggregationTypes = aggregationTypes; - } - - public byte[] getAggregationTypes() { - return aggregationTypes; - } -} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/aggregation/SingleAggregation.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/aggregation/SingleAggregation.java deleted file mode 100644 index 82c64fa08..000000000 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/aggregation/SingleAggregation.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2023 RAW Labs S.A. - * - * Use of this software is governed by the Business Source License - * included in the file licenses/BSL.txt. - * - * As of the Change Date specified in that file, in accordance with - * the Business Source License, use of this software will be governed - * by the Apache License, Version 2.0, included in the file - * licenses/APL.txt. - */ - -package raw.runtime.truffle.runtime.aggregation; - -public class SingleAggregation { - private final byte aggregationType; - - public SingleAggregation(byte aggregationType) { - this.aggregationType = aggregationType; - } - - public byte getAggregationType() { - return aggregationType; - } -} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapIterator.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapIterator.java new file mode 100644 index 000000000..f6188b0b7 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapIterator.java @@ -0,0 +1,74 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.runtime.data_structures.treemap; + +import static raw.runtime.truffle.runtime.data_structures.treemap.TreeMapStatic.predecessor; +import static raw.runtime.truffle.runtime.data_structures.treemap.TreeMapStatic.successor; + +import java.util.ConcurrentModificationException; +import java.util.NoSuchElementException; + +public class TreeMapIterator { + private final TreeMapObject tree; + TreeMapNode next; + TreeMapNode lastReturned; + int expectedModCount; + + TreeMapIterator(TreeMapObject tree) { + expectedModCount = tree.getModCount(); + lastReturned = null; + next = tree.getFirstEntry(); + this.tree = tree; + } + + public final boolean hasNext() { + return next != null; + } + + public final TreeMapNode nextNode() { + TreeMapNode e = next; + if (e == null) throw new NoSuchElementException(); + if (tree.getModCount() != expectedModCount) throw new ConcurrentModificationException(); + next = successor(e); + lastReturned = e; + return e; + } + + public final Object nextKey() { + TreeMapNode e = next; + if (e == null) throw new NoSuchElementException(); + if (tree.getModCount() != expectedModCount) throw new ConcurrentModificationException(); + next = successor(e); + lastReturned = e; + return e.key; + } + + final TreeMapNode prevNode() { + TreeMapNode e = next; + if (e == null) throw new NoSuchElementException(); + if (tree.getModCount() != expectedModCount) throw new ConcurrentModificationException(); + next = predecessor(e); + lastReturned = e; + return e; + } + + public void remove() { + if (lastReturned == null) throw new IllegalStateException(); + if (tree.getModCount() != expectedModCount) throw new ConcurrentModificationException(); + // deleted entries are replaced by their successors + if (lastReturned.left != null && lastReturned.right != null) next = lastReturned; + tree.deleteEntry(lastReturned); + expectedModCount = tree.getModCount(); + lastReturned = null; + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapNode.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapNode.java new file mode 100644 index 000000000..259778672 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapNode.java @@ -0,0 +1,44 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.runtime.data_structures.treemap; + +import static raw.runtime.truffle.runtime.data_structures.treemap.TreeMapStatic.BLACK; + +public class TreeMapNode { + Object key; + Object value; + TreeMapNode left; + TreeMapNode right; + TreeMapNode parent; + boolean color = BLACK; + + TreeMapNode(Object key, Object value, TreeMapNode parent) { + this.key = key; + this.value = value; + this.parent = parent; + } + + public Object getKey() { + return key; + } + + public Object getValue() { + return value; + } + + public Object setValue(Object value) { + Object oldValue = this.value; + this.value = value; + return oldValue; + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapNodes.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapNodes.java new file mode 100644 index 000000000..2b36f1f41 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapNodes.java @@ -0,0 +1,140 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.runtime.data_structures.treemap; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.NodeInfo; +import java.util.ArrayList; +import raw.runtime.truffle.PropertyType; +import raw.runtime.truffle.runtime.operators.OperatorNodes; + +public class TreeMapNodes { + + @NodeInfo(shortName = "TreeMap.GetOrCreate") + @GenerateUncached + @GenerateInline + @ImportStatic(raw.runtime.truffle.PropertyType.class) + public abstract static class TreeMapGetOrCreate extends Node { + + public abstract Object execute(Node node, TreeMapObject mapObject, Object key); + + @Specialization + static Object exec( + Node node, + TreeMapObject treeMapObject, + Object key, + @Bind("$node") Node thisNode, + @Cached OperatorNodes.CompareNode compareNode) { + int cmp = 0; + TreeMapNode parent = null; + TreeMapNode t = treeMapObject.getRoot(); + while (t != null) { // if `t` is null, we don't enter the loop, `parent` remains null. + parent = t; + cmp = compareNode.execute(thisNode, key, t.key); + if (cmp < 0) t = t.left; + else if (cmp > 0) t = t.right; + else { + return t.value; + } + } + ArrayList result = new ArrayList<>(); + if (parent != null) { + // we entered the loop and exited because `t` is null + treeMapObject.addEntry(key, result, parent, cmp < 0); + } else { + // we didn't enter the loop, we insert in the root + treeMapObject.addEntryToEmptyMap(key, result); + } + return result; + } + } + + @NodeInfo(shortName = "TreeMap.GetOrCreateDistinct") + @GenerateUncached + @GenerateInline + @ImportStatic(raw.runtime.truffle.PropertyType.class) + public abstract static class TreeMapGetOrCreateDistinct extends Node { + + public abstract boolean execute(Node node, TreeMapObject mapObject, Object key); + + @Specialization + static boolean exec( + Node node, + TreeMapObject treeMapObject, + Object key, + @Bind("$node") Node thisNode, + @Cached OperatorNodes.CompareNode compareNode) { + int cmp = 0; + TreeMapNode parent = null; + TreeMapNode t = treeMapObject.getRoot(); + while (t != null) { // if `t` is null, we don't enter the loop, `parent` remains null. + parent = t; + cmp = compareNode.execute(thisNode, key, t.key); + if (cmp < 0) t = t.left; + else if (cmp > 0) t = t.right; + else { + return false; + } + } + if (parent != null) { + // we entered the loop and exited because `t` is null + treeMapObject.addEntry(key, null, parent, cmp < 0); + } else { + // we didn't enter the loop, we insert in the root + treeMapObject.addEntryToEmptyMap(key, null); + } + return true; + } + } + + @NodeInfo(shortName = "TreeMap.GetOrCreateArrayKeys") + @GenerateUncached + @GenerateInline + @ImportStatic(PropertyType.class) + public abstract static class TreeMapGetOrCreateArrayKeysNode extends Node { + + public abstract Object execute(Node node, TreeMapObject mapObject, Object key, int[] orderings); + + @Specialization + static Object exec( + Node node, + TreeMapObject treeMapObject, + Object key, + int[] orderings, + @Bind("$node") Node thisNode, + @Cached OperatorNodes.CompareKeys compareNode) { + int cmp = 0; + TreeMapNode parent = null; + TreeMapNode t = treeMapObject.getRoot(); + while (t != null) { // if `t` is null, we don't enter the loop, `parent` remains null. + parent = t; + cmp = compareNode.execute(thisNode, (Object[]) key, (Object[]) t.key, orderings); + if (cmp < 0) t = t.left; + else if (cmp > 0) t = t.right; + else { + return t.value; + } + } + ArrayList result = new ArrayList<>(); + if (parent != null) { + // we entered the loop and exited because `t` is null + treeMapObject.addEntry(key, result, parent, cmp < 0); + } else { + // we didn't enter the loop, we insert in the root + treeMapObject.addEntryToEmptyMap(key, result); + } + return result; + } + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapObject.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapObject.java new file mode 100644 index 000000000..db10f3211 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapObject.java @@ -0,0 +1,245 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.runtime.data_structures.treemap; + +import static raw.runtime.truffle.runtime.data_structures.treemap.TreeMapStatic.*; + +import com.oracle.truffle.api.interop.TruffleObject; + +public class TreeMapObject implements TruffleObject { + + private TreeMapNode root; + private int size = 0; + private int modCount = 0; + + public TreeMapObject() {} + + public TreeMapNode getRoot() { + return root; + } + + public int getSize() { + return size; + } + + public int getModCount() { + return modCount; + } + + public void setSize(int size) { + this.size = size; + } + + public void addEntryToEmptyMap(Object key, Object value) { + root = new TreeMapNode(key, value, null); + size = 1; + modCount++; + } + + public void addEntry(Object key, Object value, TreeMapNode parent, boolean addToLeft) { + TreeMapNode e = new TreeMapNode(key, value, parent); + if (addToLeft) parent.left = e; + else parent.right = e; + fixAfterInsertion(e); + size++; + modCount++; + } + + private void rotateLeft(TreeMapNode p) { + if (p != null) { + TreeMapNode r = p.right; + p.right = r.left; + if (r.left != null) r.left.parent = p; + r.parent = p.parent; + if (p.parent == null) root = r; + else if (p.parent.left == p) p.parent.left = r; + else p.parent.right = r; + r.left = p; + p.parent = r; + } + } + + /** From CLR */ + private void rotateRight(TreeMapNode p) { + if (p != null) { + TreeMapNode l = p.left; + p.left = l.right; + if (l.right != null) l.right.parent = p; + l.parent = p.parent; + if (p.parent == null) root = l; + else if (p.parent.right == p) p.parent.right = l; + else p.parent.left = l; + l.right = p; + p.parent = l; + } + } + + private void fixAfterInsertion(TreeMapNode x) { + x.color = RED; + + while (x != null && x != root && x.parent.color == RED) { + if (parentOf(x) == leftOf(parentOf(parentOf(x)))) { + TreeMapNode y = rightOf(parentOf(parentOf(x))); + if (colorOf(y) == RED) { + setColor(parentOf(x), BLACK); + setColor(y, BLACK); + setColor(parentOf(parentOf(x)), RED); + x = parentOf(parentOf(x)); + } else { + if (x == rightOf(parentOf(x))) { + x = parentOf(x); + rotateLeft(x); + } + setColor(parentOf(x), BLACK); + setColor(parentOf(parentOf(x)), RED); + rotateRight(parentOf(parentOf(x))); + } + } else { + TreeMapNode y = leftOf(parentOf(parentOf(x))); + if (colorOf(y) == RED) { + setColor(parentOf(x), BLACK); + setColor(y, BLACK); + setColor(parentOf(parentOf(x)), RED); + x = parentOf(parentOf(x)); + } else { + if (x == leftOf(parentOf(x))) { + x = parentOf(x); + rotateRight(x); + } + setColor(parentOf(x), BLACK); + setColor(parentOf(parentOf(x)), RED); + rotateLeft(parentOf(parentOf(x))); + } + } + } + root.color = BLACK; + } + + public void clear() { + modCount++; + size = 0; + root = null; + } + + final TreeMapNode getFirstEntry() { + TreeMapNode p = root; + if (p != null) while (p.left != null) p = p.left; + return p; + } + + public void deleteEntry(TreeMapNode p) { + modCount++; + size--; + + // If strictly internal, copy successor's element to p and then make p + // point to successor. + if (p.left != null && p.right != null) { + TreeMapNode s = successor(p); + p.key = s.key; + p.value = s.value; + p = s; + } // p has 2 children + + // Start fixup at replacement node, if it exists. + TreeMapNode replacement = (p.left != null ? p.left : p.right); + + if (replacement != null) { + // Link replacement to parent + replacement.parent = p.parent; + if (p.parent == null) root = replacement; + else if (p == p.parent.left) p.parent.left = replacement; + else p.parent.right = replacement; + + // Null out links so they are OK to use by fixAfterDeletion. + p.left = p.right = p.parent = null; + + // Fix replacement + if (p.color == BLACK) fixAfterDeletion(replacement); + } else if (p.parent == null) { // return if we are the only node. + root = null; + } else { // No children. Use self as phantom replacement and unlink. + if (p.color == BLACK) fixAfterDeletion(p); + + if (p.parent != null) { + if (p == p.parent.left) p.parent.left = null; + else if (p == p.parent.right) p.parent.right = null; + p.parent = null; + } + } + } + + /** From CLR */ + private void fixAfterDeletion(TreeMapNode x) { + while (x != root && colorOf(x) == BLACK) { + if (x == leftOf(parentOf(x))) { + TreeMapNode sib = rightOf(parentOf(x)); + + if (colorOf(sib) == RED) { + setColor(sib, BLACK); + setColor(parentOf(x), RED); + rotateLeft(parentOf(x)); + sib = rightOf(parentOf(x)); + } + + if (colorOf(leftOf(sib)) == BLACK && colorOf(rightOf(sib)) == BLACK) { + setColor(sib, RED); + x = parentOf(x); + } else { + if (colorOf(rightOf(sib)) == BLACK) { + setColor(leftOf(sib), BLACK); + setColor(sib, RED); + rotateRight(sib); + sib = rightOf(parentOf(x)); + } + setColor(sib, colorOf(parentOf(x))); + setColor(parentOf(x), BLACK); + setColor(rightOf(sib), BLACK); + rotateLeft(parentOf(x)); + x = root; + } + } else { // symmetric + TreeMapNode sib = leftOf(parentOf(x)); + + if (colorOf(sib) == RED) { + setColor(sib, BLACK); + setColor(parentOf(x), RED); + rotateRight(parentOf(x)); + sib = leftOf(parentOf(x)); + } + + if (colorOf(rightOf(sib)) == BLACK && colorOf(leftOf(sib)) == BLACK) { + setColor(sib, RED); + x = parentOf(x); + } else { + if (colorOf(leftOf(sib)) == BLACK) { + setColor(rightOf(sib), BLACK); + setColor(sib, RED); + rotateLeft(sib); + sib = leftOf(parentOf(x)); + } + setColor(sib, colorOf(parentOf(x))); + setColor(parentOf(x), BLACK); + setColor(leftOf(sib), BLACK); + rotateRight(parentOf(x)); + x = root; + } + } + } + + setColor(x, BLACK); + } + + public TreeMapIterator iterator() { + return new TreeMapIterator(this); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapStatic.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapStatic.java new file mode 100644 index 000000000..dfb39f4e4 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/data_structures/treemap/TreeMapStatic.java @@ -0,0 +1,72 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.runtime.data_structures.treemap; + +public class TreeMapStatic { + public static final boolean RED = false; + public static final boolean BLACK = true; + + public static boolean colorOf(TreeMapNode p) { + return (p == null ? BLACK : p.color); + } + + public static TreeMapNode parentOf(TreeMapNode p) { + return (p == null ? null : p.parent); + } + + public static void setColor(TreeMapNode p, boolean c) { + if (p != null) p.color = c; + } + + public static TreeMapNode leftOf(TreeMapNode p) { + return (p == null) ? null : p.left; + } + + public static TreeMapNode rightOf(TreeMapNode p) { + return (p == null) ? null : p.right; + } + + static TreeMapNode predecessor(TreeMapNode t) { + if (t == null) return null; + else if (t.left != null) { + TreeMapNode p = t.left; + while (p.right != null) p = p.right; + return p; + } else { + TreeMapNode p = t.parent; + TreeMapNode ch = t; + while (p != null && ch == p.left) { + ch = p; + p = p.parent; + } + return p; + } + } + + static TreeMapNode successor(TreeMapNode t) { + if (t == null) return null; + else if (t.right != null) { + TreeMapNode p = t.right; + while (p.left != null) p = p.left; + return p; + } else { + TreeMapNode p = t.parent; + TreeMapNode ch = t; + while (p != null && ch == p.right) { + ch = p; + p = p.parent; + } + return p; + } + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/GeneratorNodes.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/GeneratorNodes.java index a5bcdb36b..eda9122c9 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/GeneratorNodes.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/GeneratorNodes.java @@ -15,6 +15,7 @@ import com.esotericsoftware.kryo.KryoException; import com.esotericsoftware.kryo.io.Input; import com.esotericsoftware.kryo.unsafe.UnsafeInput; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; @@ -22,6 +23,7 @@ import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Arrays; +import raw.runtime.truffle.runtime.data_structures.treemap.TreeMapNode; import raw.runtime.truffle.runtime.exceptions.BreakException; import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; import raw.runtime.truffle.runtime.generator.collection.abstract_generator.AbstractGenerator; @@ -81,11 +83,20 @@ static Object next( Node node, GroupByMemoryGenerator generator, @Bind("$node") Node thisNode, - @Cached @Cached.Shared("reshape") RecordShaperNodes.MakeRowNode reshape) { - Object key = generator.getKeys().next(); - ArrayList values = generator.getOffHeapGroupByKey().getMemMap().get(key); + @Cached @Cached.Exclusive RecordShaperNodes.MakeRowNode reshape) { + TreeMapNode treeNode = generator.getTreeNodesIterator().nextNode(); + @SuppressWarnings("unchecked") + ArrayList values = (ArrayList) treeNode.getValue(); return reshape.execute( - thisNode, generator.getOffHeapGroupByKey().getReshape(), key, values.toArray()); + thisNode, + generator.getOffHeapGroupByKey().getReshape(), + treeNode.getKey(), + values.toArray()); + } + + @CompilerDirectives.TruffleBoundary + static void closeInput(Input input) { + input.close(); } @Specialization @@ -93,11 +104,10 @@ static Object next( Node node, GroupBySpilledFilesGenerator generator, @Bind("$node") Node thisNode, - @Cached @Cached.Shared("headKey") InputBufferNodes.InputBufferHeadKeyNode headKeyNode, + @Cached @Cached.Exclusive InputBufferNodes.InputBufferHeadKeyNode headKeyNode, @Cached @Cached.Shared("keyCompare") OperatorNodes.CompareNode keyCompare, - @Cached @Cached.Shared("inputClose") InputBufferNodes.InputBufferCloseNode closeNode, - @Cached @Cached.Shared("read") InputBufferNodes.InputBufferReadNode readNode, - @Cached @Cached.Shared("reshape") RecordShaperNodes.MakeRowNode reshape) { + @Cached @Cached.Exclusive InputBufferNodes.InputBufferReadNode readNode, + @Cached @Cached.Exclusive RecordShaperNodes.MakeRowNode reshape) { Object key = null; // read missing keys and compute the smallest for (int idx = 0; idx < generator.getInputBuffers().size(); idx++) { @@ -110,7 +120,7 @@ static Object next( } catch (KryoException e) { // we reached the end of that buffer final GroupByInputBuffer removed = generator.getInputBuffers().remove(idx); - closeNode.execute(thisNode, removed); + closeInput(removed.getInput()); idx--; } } @@ -148,10 +158,10 @@ static Object next(Node node, OrderByMemoryGenerator generator) { Object n; if (generator.getValues() == null) { // no iterator over the values, create one from the next key. - Object[] keys = generator.getKeysIterator().next(); - generator.setValues( - Arrays.stream(generator.getOffHeapGroupByKeys().getMemMap().get(keys).toArray()) - .iterator()); + TreeMapNode treeNode = generator.getNodeIterator().nextNode(); + @SuppressWarnings("unchecked") + ArrayList value = (ArrayList) treeNode.getValue(); + generator.setValues(Arrays.stream(value.toArray()).iterator()); } n = generator.getValues().next(); if (!generator.getValues().hasNext()) { @@ -166,9 +176,8 @@ static Object next( Node node, OrderBySpilledFilesGenerator generator, @Bind("$node") Node thisNode, - @Cached @Cached.Shared("headKey") InputBufferNodes.InputBufferHeadKeyNode headKeyNode, - @Cached @Cached.Shared("inputClose") InputBufferNodes.InputBufferCloseNode closeNode, - @Cached @Cached.Shared("read") InputBufferNodes.InputBufferReadNode readNode, + @Cached @Cached.Exclusive InputBufferNodes.InputBufferHeadKeyNode headKeyNode, + @Cached @Cached.Exclusive InputBufferNodes.InputBufferReadNode readNode, @Cached OperatorNodes.CompareKeys keysCompare) { if (generator.getCurrentKryoBuffer() == null) { // we need to read the next keys and prepare the new buffer to read from. @@ -190,7 +199,7 @@ static Object next( } catch (KryoException e) { // we reached the end of that buffer OrderByInputBuffer removed = generator.getInputBuffers().remove(idx); - closeNode.execute(thisNode, removed); + closeInput(removed.getInput()); idx--; } } @@ -218,7 +227,7 @@ static Object next( @Specialization static Object next(Node node, DistinctMemoryGenerator generator) { - return generator.getItems().next(); + return generator.getItems().nextKey(); } @Specialization @@ -237,16 +246,12 @@ static Object next( Input buffer = generator.getKryoBuffers().get(idx); try { bufferKey = - reader.execute( - thisNode, - generator.getOffHeapDistinct().getLanguage(), - buffer, - generator.getOffHeapDistinct().getItemType()); + reader.execute(thisNode, buffer, generator.getOffHeapDistinct().getItemType()); } catch (KryoException e) { // we reached the end of that buffer // remove both the buffer and its key from the lists final Input removed = generator.getKryoBuffers().remove(idx); - removed.close(); + closeInput(removed); generator.getHeadKeys().remove(idx); idx--; continue; @@ -311,7 +316,12 @@ static boolean hasNext( @Specialization static boolean hasNext(Node node, GroupByMemoryGenerator generator) { - return generator.getKeys().hasNext(); + return generator.getTreeNodesIterator().hasNext(); + } + + @CompilerDirectives.TruffleBoundary + static void closeInput(Input input) { + input.close(); } @Specialization @@ -319,9 +329,8 @@ static boolean hasNext( Node node, GroupBySpilledFilesGenerator generator, @Bind("$node") Node thisNode, - @Cached @Cached.Shared("headKey") InputBufferNodes.InputBufferHeadKeyNode headKeyNode, - @Cached @Cached.Shared("keyCompare") OperatorNodes.CompareNode keyCompare, - @Cached @Cached.Shared("inputClose") InputBufferNodes.InputBufferCloseNode closeNode) { + @Cached @Cached.Exclusive InputBufferNodes.InputBufferHeadKeyNode headKeyNode, + @Cached @Cached.Shared("keyCompare") OperatorNodes.CompareNode keyCompare) { Object key = null; // read missing keys and compute the smallest for (int idx = 0; idx < generator.getInputBuffers().size(); idx++) { @@ -334,7 +343,7 @@ static boolean hasNext( } catch (KryoException e) { // we reached the end of that buffer final GroupByInputBuffer removed = generator.getInputBuffers().remove(idx); - closeNode.execute(thisNode, removed); + closeInput(removed.getInput()); idx--; } } @@ -343,7 +352,7 @@ static boolean hasNext( @Specialization static boolean hasNext(Node node, OrderByMemoryGenerator generator) { - return generator.getKeysIterator().hasNext() || generator.getValues() != null; + return generator.getNodeIterator().hasNext() || generator.getValues() != null; } @Specialization @@ -351,8 +360,7 @@ static boolean hasNext( Node node, OrderBySpilledFilesGenerator generator, @Bind("$node") Node thisNode, - @Cached @Cached.Shared("headKey") InputBufferNodes.InputBufferHeadKeyNode headKeyNode, - @Cached @Cached.Shared("inputClose") InputBufferNodes.InputBufferCloseNode closeNode, + @Cached @Cached.Exclusive InputBufferNodes.InputBufferHeadKeyNode headKeyNode, @Cached OperatorNodes.CompareKeys keysCompare) { // we need to read the next keys and prepare the new buffer to read from. Object[] keys = null; @@ -373,7 +381,7 @@ static boolean hasNext( } catch (KryoException e) { // we reached the end of that buffer OrderByInputBuffer removed = generator.getInputBuffers().remove(idx); - closeNode.execute(thisNode, removed); + closeInput(removed.getInput()); idx--; } } @@ -401,16 +409,12 @@ static boolean hasNext( Input buffer = generator.getKryoBuffers().get(idx); try { bufferKey = - reader.execute( - thisNode, - generator.getOffHeapDistinct().getLanguage(), - buffer, - generator.getOffHeapDistinct().getItemType()); + reader.execute(thisNode, buffer, generator.getOffHeapDistinct().getItemType()); } catch (KryoException e) { // we reached the end of that buffer // remove both the buffer and its key from the lists final Input removed = generator.getKryoBuffers().remove(idx); - removed.close(); + closeInput(removed); generator.getHeadKeys().remove(idx); idx--; continue; @@ -546,6 +550,11 @@ public abstract static class GeneratorCloseNode extends Node { public abstract void execute(Node node, Object generator); + @CompilerDirectives.TruffleBoundary + static void closeInput(Input input) { + input.close(); + } + @Specialization static void close( Node node, @@ -560,7 +569,7 @@ static void close(Node node, GroupByMemoryGenerator generator) {} @Specialization static void close(Node node, GroupBySpilledFilesGenerator generator) { - generator.getInputBuffers().forEach(buffer -> buffer.getInput().close()); + generator.getInputBuffers().forEach(buffer -> closeInput(buffer.getInput())); } @Specialization @@ -568,7 +577,7 @@ static void close(Node node, OrderByMemoryGenerator generator) {} @Specialization static void close(Node node, OrderBySpilledFilesGenerator generator) { - generator.getInputBuffers().forEach(buffer -> buffer.getInput().close()); + generator.getInputBuffers().forEach(buffer -> closeInput(buffer.getInput())); } @Specialization @@ -576,7 +585,7 @@ static void close(Node node, DistinctMemoryGenerator generator) {} @Specialization static void close(Node node, DistinctSpilledFilesGenerator generator) { - generator.getKryoBuffers().forEach(Input::close); + generator.getKryoBuffers().forEach(GeneratorCloseNode::closeInput); } @Specialization diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/StaticInitializers.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/StaticInitializers.java new file mode 100644 index 000000000..4167b964f --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/StaticInitializers.java @@ -0,0 +1,122 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.runtime.generator.collection; + +import com.esotericsoftware.kryo.io.Output; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.nodes.Node; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.OutputStream; +import raw.runtime.truffle.RawContext; +import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; +import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.distinct.OffHeapDistinct; +import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.group_by.OffHeapGroupByKey; +import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.order_by.OffHeapGroupByKeys; +import raw.runtime.truffle.utils.IOUtils; +import raw.sources.api.SourceContext; + +public class StaticInitializers { + + @CompilerDirectives.TruffleBoundary + public static void kryoWriteInt(Output kryoOutput, int size) { + kryoOutput.writeInt(size); + } + + @CompilerDirectives.TruffleBoundary + public static FileOutputStream getGroupByKeyNewDiskBuffer( + OffHeapGroupByKey offHeapGroupByKey, Node node) { + SourceContext sourceContext = RawContext.get(node).getSourceContext(); + File file; + file = IOUtils.getScratchFile("groupby.", ".kryo", sourceContext).toFile(); + offHeapGroupByKey.getSpilledBuffers().add(file); + try { + return new FileOutputStream(file); + } catch (FileNotFoundException e) { + throw new RawTruffleRuntimeException(e, node); + } + } + + @CompilerDirectives.TruffleBoundary + public static FileOutputStream groupByKeysNextFile( + OffHeapGroupByKeys offHeapGroupByKeys, Node node) { + File file; + SourceContext sourceContext = RawContext.get(node).getSourceContext(); + file = IOUtils.getScratchFile("orderby.", ".kryo", sourceContext).toFile(); + offHeapGroupByKeys.getSpilledBuffers().add(file); + try { + return new FileOutputStream(file); + } catch (FileNotFoundException e) { + throw new RawTruffleRuntimeException(e, node); + } + } + + @CompilerDirectives.TruffleBoundary + public static FileOutputStream distinctNextFile(OffHeapDistinct offHeapDistinct, Node node) { + File file; + SourceContext sourceContext = RawContext.get(node).getSourceContext(); + file = IOUtils.getScratchFile("distinct.", ".kryo", sourceContext).toFile(); + offHeapDistinct.getSpilledBuffers().add(file); + try { + return new FileOutputStream(file); + } catch (FileNotFoundException e) { + throw new RawTruffleRuntimeException(e, node); + } + } + + @CompilerDirectives.TruffleBoundary + public static void kryoOutputClose(Output kryoOutput) { + kryoOutput.close(); + } + + public static int getKryoOutputBufferSize(Node node) { + return (int) + RawContext.get(node) + .getSourceContext() + .settings() + .getMemorySize("raw.runtime.kryo.output-buffer-size"); + } + + @CompilerDirectives.TruffleBoundary + public static long[] getContextValues(Node node) { + SourceContext sourceContext = RawContext.get(node).getSourceContext(); + long[] contextValues = new long[3]; + contextValues[0] = + sourceContext.settings().getMemorySize("raw.runtime.external.disk-block-max-size"); + contextValues[1] = getKryoOutputBufferSize(node); + contextValues[2] = + (int) sourceContext.settings().getMemorySize("raw.runtime.kryo.input-buffer-size"); + return contextValues; + } + + @CompilerDirectives.TruffleBoundary + public static SourceContext getSourceContext(Node node) { + return RawContext.get(node).getSourceContext(); + } + + @CompilerDirectives.TruffleBoundary + public static RawContext getRawContext(Node node) { + return RawContext.get(node); + } + + @CompilerDirectives.TruffleBoundary + public static OutputStream getOutputStream(Node node) { + return RawContext.get(node).getOutput(); + } + + @CompilerDirectives.TruffleBoundary + public static String[] getScopes(Node node) { + return RawContext.get(node).getScopes(); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/ComputeNextNodes.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/ComputeNextNodes.java index b0f9260a7..dd3a7466e 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/ComputeNextNodes.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/ComputeNextNodes.java @@ -17,21 +17,27 @@ import com.fasterxml.jackson.core.JsonToken; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.RootCallTarget; +import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.interop.*; -import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.nodes.DirectCallNode; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.ast.io.csv.reader.CsvParserNodes; import raw.runtime.truffle.ast.io.json.reader.JsonParserNodes; import raw.runtime.truffle.ast.io.xml.parser.RawTruffleXmlParser; +import raw.runtime.truffle.ast.osr.OSRGeneratorNode; +import raw.runtime.truffle.ast.osr.bodies.*; +import raw.runtime.truffle.ast.osr.conditions.OSRCollectionFilterConditionNode; +import raw.runtime.truffle.ast.osr.conditions.OSRFromBodyConditionNode; +import raw.runtime.truffle.ast.osr.conditions.OSRHasNextConditionNode; import raw.runtime.truffle.runtime.exceptions.BreakException; -import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; import raw.runtime.truffle.runtime.exceptions.csv.CsvParserRawTruffleException; import raw.runtime.truffle.runtime.exceptions.csv.CsvReaderRawTruffleException; @@ -40,19 +46,20 @@ import raw.runtime.truffle.runtime.exceptions.xml.XmlReaderRawTruffleException; import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.StaticInitializers; import raw.runtime.truffle.runtime.generator.collection.abstract_generator.compute_next.operations.*; import raw.runtime.truffle.runtime.generator.collection.abstract_generator.compute_next.sources.*; import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.OffHeapNodes; import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.group_by.OffHeapGroupByKey; import raw.runtime.truffle.runtime.iterable.IterableNodes; import raw.runtime.truffle.runtime.iterable.sources.EmptyCollection; -import raw.runtime.truffle.runtime.kryo.KryoNodes; -import raw.runtime.truffle.runtime.operators.OperatorNodes; -import raw.runtime.truffle.runtime.record.RecordObject; -import raw.runtime.truffle.tryable_nullable.TryableNullable; +import raw.runtime.truffle.runtime.record.RecordNodes; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; +import raw.runtime.truffle.utils.IOUtils; import raw.runtime.truffle.utils.RawTruffleStringCharStream; import raw.runtime.truffle.utils.TruffleCharInputStream; import raw.runtime.truffle.utils.TruffleInputStream; +import raw.sources.api.SourceContext; public class ComputeNextNodes { @@ -176,8 +183,8 @@ static Object next( UnionComputeNext computeNext, @Bind("$node") Node thisNode, @Cached @Cached.Shared("getGenerator") IterableNodes.GetGeneratorNode getGeneratorNode, - @Cached(inline = false) @Cached.Shared("next2") GeneratorNodes.GeneratorNextNode nextNode, - @Cached @Cached.Shared("hasNext2") GeneratorNodes.GeneratorHasNextNode hasNextNode, + @Cached(inline = false) @Cached.Exclusive GeneratorNodes.GeneratorNextNode nextNode, + @Cached @Cached.Exclusive GeneratorNodes.GeneratorHasNextNode hasNextNode, @Cached @Cached.Shared("init") GeneratorNodes.GeneratorInitNode initNode, @Cached @Cached.Shared("close") GeneratorNodes.GeneratorCloseNode closeNode) { Object currentGenerator; @@ -243,26 +250,36 @@ static Object next(Node node, EmptyComputeNext computeNext) { throw new BreakException(); } - @Specialization + public static LoopNode getFilterLoopNode(FilterComputeNext computeNext) { + return Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRCollectionFilterConditionNode( + computeNext.getGeneratorSlot(), computeNext.getResultSlot()), + new OSRCollectionFilterBodyNode( + computeNext.getGeneratorSlot(), + computeNext.getFunctionSlot(), + computeNext.getResultSlot()))); + } + + @Specialization(guards = "cachedComputeNext.hasSameSlots(computeNext)", limit = "8", unroll = 8) static Object next( Node node, FilterComputeNext computeNext, - @Bind("$node") Node thisNode, - @Cached @Cached.Shared("hasNext1") GeneratorNodes.GeneratorHasNextNode hasNextNode, - @Cached(inline = false) @Cached.Shared("next1") GeneratorNodes.GeneratorNextNode nextNode, - @Cached @Cached.Shared("executeOne") - FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { - while (hasNextNode.execute(thisNode, computeNext.getParent())) { - Object v = nextNode.execute(thisNode, computeNext.getParent()); - Boolean isPredicateTrue = null; - isPredicateTrue = - TryableNullable.handlePredicate( - functionExecuteOneNode.execute(thisNode, computeNext.getPredicate(), v), false); - if (isPredicateTrue) { - return v; - } + @Cached("computeNext") FilterComputeNext cachedComputeNext, + @Cached( + value = "getFilterLoopNode(cachedComputeNext)", + inline = false, + allowUncached = true) + LoopNode loopNode) { + Frame frame = computeNext.getFrame(); + frame.setObject(computeNext.getResultSlot(), null); + loopNode.execute(computeNext.getFrame()); + Object result = frame.getObject(computeNext.getResultSlot()); + if (result == null) { + throw new BreakException(); } - throw new BreakException(); + return result; } @Specialization @@ -270,8 +287,8 @@ static Object next( Node node, TakeComputeNext computeNext, @Bind("$node") Node thisNode, - @Cached @Cached.Shared("hasNext1") GeneratorNodes.GeneratorHasNextNode hasNextNode, - @Cached(inline = false) @Cached.Shared("next1") GeneratorNodes.GeneratorNextNode nextNode) { + @Cached @Cached.Exclusive GeneratorNodes.GeneratorHasNextNode hasNextNode, + @Cached(inline = false) @Cached.Exclusive GeneratorNodes.GeneratorNextNode nextNode) { if (computeNext.getCurrentCount() < computeNext.getTakeCount() && hasNextNode.execute(thisNode, computeNext.getParent())) { computeNext.incrementCurrentCount(); @@ -285,7 +302,7 @@ static Object next( Node node, TransformComputeNext computeNext, @Bind("$node") Node thisNode, - @Cached @Cached.Shared("hasNext1") GeneratorNodes.GeneratorHasNextNode hasNextNode, + @Cached @Cached.Exclusive GeneratorNodes.GeneratorHasNextNode hasNextNode, @Cached(inline = false) @Cached.Shared("next1") GeneratorNodes.GeneratorNextNode nextNode, @Cached @Cached.Shared("executeOne") FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { @@ -304,12 +321,13 @@ static Object next( UnnestComputeNext computeNext, @Bind("$node") Node thisNode, @Cached(inline = false) @Cached.Shared("next1") GeneratorNodes.GeneratorNextNode nextNode, - @Cached @Cached.Shared("hasNext1") GeneratorNodes.GeneratorHasNextNode hasNextNode, + @Cached @Cached.Exclusive GeneratorNodes.GeneratorHasNextNode hasNextNode, @Cached @Cached.Shared("getGenerator") IterableNodes.GetGeneratorNode getGeneratorNode, @Cached @Cached.Shared("init") GeneratorNodes.GeneratorInitNode initNode, @Cached @Cached.Shared("close") GeneratorNodes.GeneratorCloseNode closeNode, @Cached @Cached.Shared("executeOne") - FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { + FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode, + @Cached TryableNullableNodes.GetOrElseNode getOrElseNode) { Object next = null; while (next == null) { @@ -325,7 +343,8 @@ static Object next( nextNode.execute(thisNode, computeNext.getParent())); // the function result could be tryable/nullable. If error/null, // we replace it by an empty collection. - Object iterable = TryableNullable.getOrElse(functionResult, EmptyCollection.INSTANCE); + Object iterable = + getOrElseNode.execute(thisNode, functionResult, EmptyCollection.INSTANCE); computeNext.setCurrentGenerator(getGeneratorNode.execute(thisNode, iterable)); initNode.execute(thisNode, computeNext.getCurrentGenerator()); } @@ -339,88 +358,66 @@ static Object next( return next; } + public static RawLanguage getRawLanguage(Node node) { + return RawLanguage.get(node); + } + @Specialization static Object next( Node node, ZipComputeNext computeNext, @Bind("$node") Node thisNode, - @Cached @Cached.Shared("hasNext1") GeneratorNodes.GeneratorHasNextNode hasNextNode1, - @Cached @Cached.Shared("hasNext2") GeneratorNodes.GeneratorHasNextNode hasNextNode2, - @Cached(inline = false) @Cached.Shared("next1") GeneratorNodes.GeneratorNextNode nextNode1, - @Cached(inline = false) @Cached.Shared("next2") GeneratorNodes.GeneratorNextNode nextNode2, - @CachedLibrary(limit = "5") InteropLibrary records) { - try { - if (hasNextNode1.execute(thisNode, computeNext.getParent1()) - && hasNextNode2.execute(thisNode, computeNext.getParent2())) { - RecordObject record = computeNext.getLanguage().createRecord(); - records.writeMember(record, "_1", nextNode1.execute(thisNode, computeNext.getParent1())); - records.writeMember(record, "_2", nextNode2.execute(thisNode, computeNext.getParent2())); - return record; - } - throw new BreakException(); - } catch (UnsupportedMessageException - | UnknownIdentifierException - | UnsupportedTypeException e) { - throw new RawTruffleInternalErrorException(e); + @Cached(value = "getRawLanguage(thisNode)", allowUncached = true) RawLanguage language, + @Cached @Cached.Exclusive GeneratorNodes.GeneratorHasNextNode hasNextNode1, + @Cached @Cached.Exclusive GeneratorNodes.GeneratorHasNextNode hasNextNode2, + @Cached(inline = false) @Cached.Exclusive GeneratorNodes.GeneratorNextNode nextNode1, + @Cached(inline = false) @Cached.Exclusive GeneratorNodes.GeneratorNextNode nextNode2, + @Cached RecordNodes.AddPropNode addPropNode1, + @Cached RecordNodes.AddPropNode addPropNode2) { + if (hasNextNode1.execute(thisNode, computeNext.getParent1()) + && hasNextNode2.execute(thisNode, computeNext.getParent2())) { + Object record = language.createPureRecord(); + addPropNode1.execute( + thisNode, record, "_1", nextNode1.execute(thisNode, computeNext.getParent1()), false); + + addPropNode2.execute( + thisNode, record, "_2", nextNode2.execute(thisNode, computeNext.getParent2()), false); + return record; } + throw new BreakException(); } - @Specialization + public static LoopNode getEquiJoinNextLoopNode(EquiJoinComputeNext computeNext) { + return Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRFromBodyConditionNode(computeNext.getShouldContinueSlot()), + new OSREquiJoinNextBodyNode( + computeNext.getComputeNextSlot(), computeNext.getShouldContinueSlot()))); + } + + @Specialization(guards = "cachedComputeNext.hasSameSlots(computeNext)", limit = "8", unroll = 8) static Object next( Node node, EquiJoinComputeNext computeNext, @Bind("$node") Node thisNode, - @Cached @Cached.Shared("hasNext2") GeneratorNodes.GeneratorHasNextNode hasNextNode, - @Cached(inline = false) @Cached.Shared("next2") GeneratorNodes.GeneratorNextNode nextNode, - @Cached OperatorNodes.CompareNode compareKey, - @Cached @Cached.Shared("executeTwo") - FunctionExecuteNodes.FunctionExecuteTwo functionExecuteTwoNode) { + @Cached("computeNext") EquiJoinComputeNext cachedComputeNext, + @Cached( + value = "getEquiJoinNextLoopNode(cachedComputeNext)", + inline = false, + allowUncached = true) + LoopNode loopNode, + @Cached FunctionExecuteNodes.FunctionExecuteTwo functionExecuteTwoNode) { assert (computeNext.getLeftMapGenerator() != null); assert (computeNext.getRightMapGenerator() != null); - // keep iterating until we find matching keys - while (computeNext.getLeftKey() == null || computeNext.getRightKey() == null) { - if (computeNext.getLeftKey() == null) { - if (hasNextNode.execute(thisNode, computeNext.getLeftMapGenerator())) { - computeNext.setLeftEntry( - (Object[]) nextNode.execute(thisNode, computeNext.getLeftMapGenerator())); - computeNext.setLeftKey(computeNext.getLeftEntry()[0]); - } else { - throw new BreakException(); - } - } + Frame frame = computeNext.getFrame(); - if (computeNext.getRightKey() == null) { - if (hasNextNode.execute(thisNode, computeNext.getRightMapGenerator())) { - computeNext.setRightEntry( - (Object[]) nextNode.execute(thisNode, computeNext.getRightMapGenerator())); - computeNext.setRightKey(computeNext.getRightEntry()[0]); - } else { - throw new BreakException(); - } - } + frame.setObject(computeNext.getComputeNextSlot(), computeNext); + frame.setBoolean(computeNext.getShouldContinueSlot(), true); - int compare = - compareKey.execute(thisNode, computeNext.getLeftKey(), computeNext.getRightKey()); - // if keys aren't equal, reset the smallest of both (it will be read in the next - // iteration and - // will be larger) - if (compare < 0) { - computeNext.setLeftKey(null); - } else if (compare > 0) { - computeNext.setRightKey(null); - } else { - // keys are equal, prepare to do the cartesian product between both. - // leftRows and rightRows are the arrays of rows with the same key. - // We'll iterate over them to produce the cartesian product. - computeNext.setLeftRows((Object[]) computeNext.getLeftEntry()[1]); - computeNext.setRightRows((Object[]) computeNext.getRightEntry()[1]); - computeNext.setLeftIndex(0); - computeNext.setRightIndex(0); - break; - } - } + loopNode.execute(computeNext.getFrame()); // record to return Object joinedRow = null; @@ -460,84 +457,31 @@ private static Input createInput(File file, Node node) { } } - @Specialization + public static LoopNode getJoinNextLoopNode(JoinComputeNext computeNext) { + return Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRFromBodyConditionNode(computeNext.getShouldContinueSlot()), + new OSRJoinNextBodyNode( + computeNext.getComputeNextSlot(), + computeNext.getShouldContinueSlot(), + computeNext.getResultSlot()))); + } + + @Specialization(guards = "cachedComputeNext.hasSameSlots(computeNext)", limit = "8", unroll = 8) static Object next( Node node, JoinComputeNext computeNext, - @Bind("$node") Node thisNode, - @Cached @Cached.Shared("hasNext2") GeneratorNodes.GeneratorHasNextNode hasNextNode, - @Cached(inline = false) @Cached.Shared("next2") GeneratorNodes.GeneratorNextNode nextNode, - @Cached KryoNodes.KryoReadNode kryoReadNode, - @Cached @Cached.Shared("executeOne") FunctionExecuteNodes.FunctionExecuteOne executeOneNode, - @Cached @Cached.Shared("executeTwo") - FunctionExecuteNodes.FunctionExecuteTwo executeTwoNode) { - Object row = null; - - while (row == null) { - if (computeNext.getLeftRow() == null || computeNext.getRightRow() == null) { - if (computeNext.getLeftRow() == null) { - if (hasNextNode.execute(thisNode, computeNext.getLeftGen())) { - computeNext.setLeftRow(nextNode.execute(thisNode, computeNext.getLeftGen())); - } else { - // end of left, nothing else to read - throw new BreakException(); - } - } - if (computeNext.getKryoRight() == null) { - computeNext.setKryoRight(createInput(computeNext.getDiskRight(), thisNode)); - computeNext.setReadRight(0); - } - if (computeNext.getRightRow() == null) { - if (computeNext.getReadRight() < computeNext.getSpilledRight()) { - computeNext.setRightRow( - kryoReadNode.execute( - thisNode, - computeNext.getLanguage(), - computeNext.getKryoRight(), - computeNext.getRightRowType())); - boolean pass; - if (computeNext.getReshapeBeforePredicate()) { - row = - executeTwoNode.execute( - thisNode, - computeNext.getRemap(), - computeNext.getLeftRow(), - computeNext.getRightRow()); - pass = - TryableNullable.handlePredicate( - executeOneNode.execute(thisNode, computeNext.getPredicate(), row), false); - if (!pass) row = null; - } else { - pass = - TryableNullable.handlePredicate( - executeTwoNode.execute( - thisNode, - computeNext.getPredicate(), - computeNext.getLeftRow(), - computeNext.getRightRow()), - false); - if (pass) - row = - executeTwoNode.execute( - thisNode, - computeNext.getRemap(), - computeNext.getLeftRow(), - computeNext.getRightRow()); - } - - computeNext.setReadRight(computeNext.getReadRight() + 1); - computeNext.setRightRow(null); - } else { - // end of right, reset currentLeft to make sure we try another round - computeNext.setLeftRow(null); - computeNext.getKryoRight().close(); - computeNext.setRightRow(null); - computeNext.setKryoRight(null); - } - } - } - } - return row; + @Cached("computeNext") JoinComputeNext cachedComputeNext, + @Cached( + value = "getJoinNextLoopNode(cachedComputeNext)", + inline = false, + allowUncached = true) + LoopNode loopNode) { + computeNext.getFrame().setObject(computeNext.getComputeNextSlot(), computeNext); + computeNext.getFrame().setBoolean(computeNext.getShouldContinueSlot(), true); + loopNode.execute(computeNext.getFrame()); + return computeNext.getFrame().getObject(computeNext.getResultSlot()); } } @@ -548,6 +492,7 @@ static Object next( @NodeInfo(shortName = "Generator.Init") @GenerateUncached @GenerateInline + @ImportStatic(StaticInitializers.class) public abstract static class InitNode extends Node { public abstract void execute(Node node, Object computeNext); @@ -561,10 +506,12 @@ static void init( CsvReadComputeNext computeNext, @Bind("$node") Node thisNode, @Cached @Cached.Shared("initCsv") CsvParserNodes.InitCsvParserNode initParser, - @Cached @Cached.Shared("closeCsv") CsvParserNodes.CloseCsvParserNode closeParser) { + @Cached @Cached.Shared("closeCsv") CsvParserNodes.CloseCsvParserNode closeParser, + @Cached(value = "getSourceContext(thisNode)", allowUncached = true, neverDefault = true) + SourceContext sourceContext) { try { TruffleInputStream truffleInputStream = - new TruffleInputStream(computeNext.getLocation(), computeNext.getContext()); + new TruffleInputStream(computeNext.getLocation(), sourceContext); computeNext.setStream( new TruffleCharInputStream(truffleInputStream, computeNext.getEncoding())); computeNext.setParser( @@ -614,10 +561,12 @@ static void init( @Bind("$node") Node thisNode, @Cached JsonParserNodes.InitJsonParserNode initParser, @Cached JsonParserNodes.CloseJsonParserNode closeParser, - @Cached JsonParserNodes.NextTokenJsonParserNode nextToken) { + @Cached JsonParserNodes.NextTokenJsonParserNode nextToken, + @Cached(value = "getSourceContext(thisNode)", allowUncached = true, neverDefault = true) + SourceContext sourceContext) { try { TruffleInputStream truffleInputStream = - new TruffleInputStream(computeNext.getLocationObject(), computeNext.getContext()); + new TruffleInputStream(computeNext.getLocationObject(), sourceContext); computeNext.setStream( new TruffleCharInputStream(truffleInputStream, computeNext.getEncoding())); computeNext.setParser(initParser.execute(thisNode, computeNext.getStream())); @@ -667,10 +616,15 @@ static void init(Node node, XmlParseComputeNext computeNext) { } @Specialization - static void init(Node node, XmlReadComputeNext computeNext) { + static void init( + Node node, + XmlReadComputeNext computeNext, + @Bind("$node") Node thisNode, + @Cached(value = "getSourceContext(thisNode)", allowUncached = true, neverDefault = true) + SourceContext sourceContext) { try { TruffleInputStream truffleInputStream = - new TruffleInputStream(computeNext.getLocationObject(), computeNext.getContext()); + new TruffleInputStream(computeNext.getLocationObject(), sourceContext); computeNext.setStream( new TruffleCharInputStream(truffleInputStream, computeNext.getEncoding())); computeNext.setParser( @@ -694,6 +648,9 @@ static void init( @Bind("$node") Node thisNode, @Cached(inline = false) @Cached.Shared("init") GeneratorNodes.GeneratorInitNode initNode) { initNode.execute(thisNode, computeNext.getParent()); + Frame frame = computeNext.getFrame(); + frame.setObject(computeNext.getGeneratorSlot(), computeNext.getParent()); + frame.setObject(computeNext.getFunctionSlot(), computeNext.getPredicate()); } @Specialization @@ -734,71 +691,85 @@ static void init( initNode2.execute(thisNode, computeNext.getParent2()); } - @Specialization + public static LoopNode getEquiJoinInitLoopNode(EquiJoinComputeNext computeNext) { + return Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRHasNextConditionNode(computeNext.getGeneratorSlot()), + new OSRCollectionEquiJoinInitBodyNode( + computeNext.getGeneratorSlot(), + computeNext.getKeyFunctionSlot(), + computeNext.getMapSlot()))); + } + + @Specialization(guards = "cachedComputeNext.hasSameSlots(computeNext)", limit = "8", unroll = 8) static void init( Node node, EquiJoinComputeNext computeNext, @Bind("$node") Node thisNode, + @Cached("computeNext") EquiJoinComputeNext cachedComputeNext, + @Cached( + value = "getEquiJoinInitLoopNode(cachedComputeNext)", + inline = false, + allowUncached = true) + LoopNode loopNode1, + @Cached( + value = "getEquiJoinInitLoopNode(cachedComputeNext)", + inline = false, + allowUncached = true) + LoopNode loopNode2, @Cached @Cached.Shared("getGenerator") IterableNodes.GetGeneratorNode getGenerator, @Cached(inline = false) @Cached.Shared("init1") GeneratorNodes.GeneratorInitNode initLeftNode, @Cached(inline = false) @Cached.Shared("init2") GeneratorNodes.GeneratorInitNode initRightNode, - @Cached @Cached.Shared("hasNext1") GeneratorNodes.GeneratorHasNextNode hasNextLeftNode, - @SuppressWarnings("truffle-sharing") @Cached - GeneratorNodes.GeneratorHasNextNode hasNextRightNode, - @Cached(inline = false) @Cached.Shared("next1") - GeneratorNodes.GeneratorNextNode nextLeftNode, - @SuppressWarnings("truffle-sharing") @Cached(inline = false) - GeneratorNodes.GeneratorNextNode nextRightNode, @Cached @Cached.Shared("close1") GeneratorNodes.GeneratorCloseNode closeLeftNode, @SuppressWarnings("truffle-sharing") @Cached GeneratorNodes.GeneratorCloseNode closeRightNode, - @Cached OffHeapNodes.OffHeapGroupByPutNode putLeftNode, - @Cached OffHeapNodes.OffHeapGroupByPutNode putRightNode, @Cached OffHeapNodes.OffHeapGeneratorNode offHeapGeneratorLeft, @Cached OffHeapNodes.OffHeapGeneratorNode offHeapGeneratorRight, - @Cached FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { + @Cached(value = "getContextValues(thisNode)", dimensions = 1, allowUncached = true) + long[] contextValues) { + Frame frame = computeNext.getFrame(); // left side (get a generator, then fill a map, set leftMapGenerator to the map generator) OffHeapGroupByKey leftMap = new OffHeapGroupByKey( computeNext.getKeyType(), computeNext.getLeftRowType(), - computeNext.getLanguage(), - computeNext.getContext(), - null); + null, + contextValues[0], + (int) contextValues[1], + (int) contextValues[2]); + Object leftGenerator = getGenerator.execute(thisNode, computeNext.getLeftIterable()); try { initLeftNode.execute(thisNode, leftGenerator); - while (hasNextLeftNode.execute(thisNode, leftGenerator)) { - Object leftItem = nextLeftNode.execute(thisNode, leftGenerator); - Object leftKey = - functionExecuteOneNode.execute(thisNode, computeNext.getLeftKeyF(), leftItem); - putLeftNode.execute(thisNode, leftMap, leftKey, leftItem); - } + frame.setObject(computeNext.getMapSlot(), leftMap); + frame.setObject(computeNext.getGeneratorSlot(), leftGenerator); + frame.setObject(computeNext.getKeyFunctionSlot(), computeNext.getLeftKeyF()); + loopNode1.execute(computeNext.getFrame()); } finally { closeLeftNode.execute(thisNode, leftGenerator); } computeNext.setLeftMapGenerator(offHeapGeneratorLeft.execute(thisNode, leftMap)); - initRightNode.execute(thisNode, computeNext.getLeftMapGenerator()); + initLeftNode.execute(thisNode, computeNext.getLeftMapGenerator()); // same with right side OffHeapGroupByKey rightMap = new OffHeapGroupByKey( computeNext.getKeyType(), computeNext.getRightRowType(), - computeNext.getLanguage(), - computeNext.getContext(), - null); + null, + contextValues[0], + (int) contextValues[1], + (int) contextValues[2]); Object rightGenerator = getGenerator.execute(thisNode, computeNext.getRightIterable()); try { initRightNode.execute(thisNode, rightGenerator); - while (hasNextRightNode.execute(thisNode, rightGenerator)) { - Object rightItem = nextRightNode.execute(thisNode, rightGenerator); - Object rightKey = - functionExecuteOneNode.execute(thisNode, computeNext.getRightKeyF(), rightItem); - putRightNode.execute(thisNode, rightMap, rightKey, rightItem); - } + frame.setObject(computeNext.getMapSlot(), rightMap); + frame.setObject(computeNext.getGeneratorSlot(), rightGenerator); + frame.setObject(computeNext.getKeyFunctionSlot(), computeNext.getRightKeyF()); + loopNode2.execute(computeNext.getFrame()); } finally { closeRightNode.execute(thisNode, rightGenerator); } @@ -817,33 +788,52 @@ private static Output createOutput(JoinComputeNext computeNext, Node node) { } } - @Specialization + public static LoopNode getJoinInitLoopNode(JoinComputeNext computeNext) { + return Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRHasNextConditionNode(computeNext.getGeneratorSlot()), + new OSRCollectionJoinInitBodyNode( + computeNext.getGeneratorSlot(), + computeNext.getComputeNextSlot(), + computeNext.getOutputBufferSlot()))); + } + + @Specialization(guards = "cachedComputeNext.hasSameSlots(computeNext)", limit = "8", unroll = 8) static void init( Node node, JoinComputeNext computeNext, @Bind("$node") Node thisNode, + @Cached("computeNext") JoinComputeNext cachedComputeNext, + @Cached( + value = "getJoinInitLoopNode(cachedComputeNext)", + inline = false, + allowUncached = true) + LoopNode loopNode, @Cached @Cached.Shared("getGenerator") IterableNodes.GetGeneratorNode getGeneratorNode, @Cached(inline = false) @Cached.Shared("init") GeneratorNodes.GeneratorInitNode initNode, - @Cached @Cached.Shared("hasNext1") GeneratorNodes.GeneratorHasNextNode hasNextNode, - @Cached(inline = false) @Cached.Shared("next1") GeneratorNodes.GeneratorNextNode nextNode, @Cached @Cached.Shared("close1") GeneratorNodes.GeneratorCloseNode closeNode, - @Cached KryoNodes.KryoWriteNode kryoWrite) { - // initialize left - computeNext.setLeftGen(getGeneratorNode.execute(thisNode, computeNext.getLeftIterable())); - initNode.execute(thisNode, computeNext.getLeftGen()); + @Cached(value = "getSourceContext(thisNode)", allowUncached = true) + SourceContext sourceContext) { + + computeNext.setDiskRight( + IOUtils.getScratchFile("cartesian.", ".kryo", sourceContext).toFile()); // save right to disk Object rightGen = getGeneratorNode.execute(thisNode, computeNext.getRightIterable()); try (Output buffer = createOutput(computeNext, thisNode)) { initNode.execute(thisNode, rightGen); - while (hasNextNode.execute(thisNode, rightGen)) { - Object row = nextNode.execute(thisNode, rightGen); - kryoWrite.execute(thisNode, buffer, computeNext.getRightRowType(), row); - computeNext.setSpilledRight(computeNext.getSpilledRight() + 1); - } + Frame frame = computeNext.getFrame(); + frame.setObject(computeNext.getGeneratorSlot(), rightGen); + frame.setObject(computeNext.getOutputBufferSlot(), buffer); + frame.setObject(computeNext.getComputeNextSlot(), computeNext); + loopNode.execute(computeNext.getFrame()); } finally { closeNode.execute(thisNode, rightGen); } + // initialize left + computeNext.setLeftGen(getGeneratorNode.execute(thisNode, computeNext.getLeftIterable())); + initNode.execute(thisNode, computeNext.getLeftGen()); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/operations/EquiJoinComputeNext.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/operations/EquiJoinComputeNext.java index 9a1f74e18..7515eef9a 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/operations/EquiJoinComputeNext.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/operations/EquiJoinComputeNext.java @@ -12,24 +12,26 @@ package raw.runtime.truffle.runtime.generator.collection.abstract_generator.compute_next.operations; +import com.oracle.truffle.api.frame.MaterializedFrame; import raw.compiler.rql2.source.Rql2TypeWithProperties; -import raw.runtime.truffle.RawLanguage; -import raw.sources.api.SourceContext; public class EquiJoinComputeNext { private final Object leftIterable, rightIterable; private final Object leftKeyF, rightKeyF, mkJoinedRecord; private final Rql2TypeWithProperties leftRowType, rightRowType, keyType; - private final RawLanguage language; - private final SourceContext context; - private Object leftMapGenerator = null, rightMapGenerator = null; // generators from group-by key maps private Object[] leftEntry = null, rightEntry = null; private int leftIndex = -1, rightIndex = -1; private Object leftKey = null, rightKey = null; private Object[] leftRows = null, rightRows = null; + private final MaterializedFrame frame; + private final int computeNextSlot; + private final int shouldContinueSlot; + private final int generatorSlot; + private final int keyFunctionSlot; + private final int mapSlot; public EquiJoinComputeNext( Object leftIterable, @@ -40,8 +42,12 @@ public EquiJoinComputeNext( Rql2TypeWithProperties rightRowType, Rql2TypeWithProperties keyType, Object mkJoinedRecord, - RawLanguage language, - SourceContext context) { + MaterializedFrame frame, + int computeNextSlot, + int shouldContinueSlot, + int generatorSlot, + int keyFunctionSlot, + int mapSlot) { this.leftIterable = leftIterable; this.leftKeyF = leftKeyF; this.leftRowType = leftRowType; @@ -50,8 +56,12 @@ public EquiJoinComputeNext( this.rightRowType = rightRowType; this.keyType = keyType; this.mkJoinedRecord = mkJoinedRecord; - this.language = language; - this.context = context; + this.frame = frame; + this.computeNextSlot = computeNextSlot; + this.shouldContinueSlot = shouldContinueSlot; + this.generatorSlot = generatorSlot; + this.keyFunctionSlot = keyFunctionSlot; + this.mapSlot = mapSlot; } public Object getLeftIterable() { @@ -86,14 +96,6 @@ public Rql2TypeWithProperties getKeyType() { return keyType; } - public RawLanguage getLanguage() { - return language; - } - - public SourceContext getContext() { - return context; - } - public Object getLeftMapGenerator() { return leftMapGenerator; } @@ -173,4 +175,36 @@ public Object[] getRightRows() { public void setRightRows(Object[] rightRows) { this.rightRows = rightRows; } + + public MaterializedFrame getFrame() { + return frame; + } + + public int getComputeNextSlot() { + return computeNextSlot; + } + + public int getShouldContinueSlot() { + return shouldContinueSlot; + } + + public int getGeneratorSlot() { + return generatorSlot; + } + + public int getKeyFunctionSlot() { + return keyFunctionSlot; + } + + public int getMapSlot() { + return mapSlot; + } + + public boolean hasSameSlots(EquiJoinComputeNext other) { + return this.computeNextSlot == other.computeNextSlot + && this.shouldContinueSlot == other.shouldContinueSlot + && this.generatorSlot == other.generatorSlot + && this.keyFunctionSlot == other.keyFunctionSlot + && this.mapSlot == other.mapSlot; + } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/operations/FilterComputeNext.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/operations/FilterComputeNext.java index 86c253e45..144e052d2 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/operations/FilterComputeNext.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/operations/FilterComputeNext.java @@ -12,13 +12,31 @@ package raw.runtime.truffle.runtime.generator.collection.abstract_generator.compute_next.operations; +import com.oracle.truffle.api.frame.MaterializedFrame; + public class FilterComputeNext { private final Object parent; private final Object predicate; + private final MaterializedFrame frame; + private final int generatorSlot; + + private final int functionSlot; - public FilterComputeNext(Object parent, Object predicate) { + private final int resultSlot; + + public FilterComputeNext( + Object parent, + Object predicate, + MaterializedFrame frame, + int generatorSlot, + int functionSlot, + int resultSlot) { this.parent = parent; this.predicate = predicate; + this.frame = frame; + this.generatorSlot = generatorSlot; + this.functionSlot = functionSlot; + this.resultSlot = resultSlot; } public Object getParent() { @@ -28,4 +46,26 @@ public Object getParent() { public Object getPredicate() { return predicate; } + + public MaterializedFrame getFrame() { + return frame; + } + + public int getGeneratorSlot() { + return generatorSlot; + } + + public int getFunctionSlot() { + return functionSlot; + } + + public int getResultSlot() { + return resultSlot; + } + + public boolean hasSameSlots(FilterComputeNext other) { + return this.generatorSlot == other.generatorSlot + && this.functionSlot == other.functionSlot + && this.resultSlot == other.resultSlot; + } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/operations/JoinComputeNext.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/operations/JoinComputeNext.java index 45bac583b..9e19d596d 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/operations/JoinComputeNext.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/operations/JoinComputeNext.java @@ -13,33 +13,33 @@ package raw.runtime.truffle.runtime.generator.collection.abstract_generator.compute_next.operations; import com.esotericsoftware.kryo.io.Input; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.frame.MaterializedFrame; import java.io.File; import raw.compiler.rql2.source.Rql2TypeWithProperties; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.utils.IOUtils; -import raw.sources.api.SourceContext; public class JoinComputeNext { + @CompilationFinal private File diskRight; + private final int kryoOutputBufferSize; protected final Object leftIterable; protected final Object rightIterable; private Object leftGen = null; private final Object remap; private final Object predicate; - private Object leftRow = null; private Object rightRow = null; Input kryoRight = null; - private final int kryoOutputBufferSize; private final Rql2TypeWithProperties rightRowType; // grouped key and value types. private int spilledRight = 0; private int readRight = 0; - private final File diskRight; private final Boolean reshapeBeforePredicate; + private final MaterializedFrame frame; + private final int computeNextSlot; + private final int shouldContinueSlot; + private final int resultSlot; + private final int generatorSlot; + private final int outputBufferSlot; - private final RawLanguage language; - - @TruffleBoundary // Needed because of SourceContext public JoinComputeNext( Object leftIterable, Object rightIterable, @@ -47,18 +47,26 @@ public JoinComputeNext( Object predicate, Boolean reshapeBeforePredicate, Rql2TypeWithProperties rightRowType, - SourceContext context, - RawLanguage language) { + int kryoOutputBufferSize, + MaterializedFrame frame, + int computeNextSlot, + int shouldContinueSlot, + int resultSlot, + int generatorSlot, + int outputBufferSlot) { this.leftIterable = leftIterable; this.rightIterable = rightIterable; this.remap = remap; this.predicate = predicate; - this.kryoOutputBufferSize = - (int) context.settings().getMemorySize("raw.runtime.kryo.output-buffer-size"); - this.language = language; this.rightRowType = rightRowType; this.reshapeBeforePredicate = reshapeBeforePredicate; - this.diskRight = IOUtils.getScratchFile("cartesian.", ".kryo", context).toFile(); + this.frame = frame; + this.computeNextSlot = computeNextSlot; + this.shouldContinueSlot = shouldContinueSlot; + this.resultSlot = resultSlot; + this.generatorSlot = generatorSlot; + this.outputBufferSlot = outputBufferSlot; + this.kryoOutputBufferSize = kryoOutputBufferSize; } public Object getLeftIterable() { @@ -137,11 +145,43 @@ public File getDiskRight() { return diskRight; } + public void setDiskRight(File diskRight) { + this.diskRight = diskRight; + } + public Boolean getReshapeBeforePredicate() { return reshapeBeforePredicate; } - public RawLanguage getLanguage() { - return language; + public MaterializedFrame getFrame() { + return frame; + } + + public int getComputeNextSlot() { + return computeNextSlot; + } + + public int getShouldContinueSlot() { + return shouldContinueSlot; + } + + public int getResultSlot() { + return resultSlot; + } + + public int getGeneratorSlot() { + return generatorSlot; + } + + public int getOutputBufferSlot() { + return outputBufferSlot; + } + + public boolean hasSameSlots(JoinComputeNext other) { + return this.computeNextSlot == other.computeNextSlot + && this.shouldContinueSlot == other.shouldContinueSlot + && this.resultSlot == other.resultSlot + && this.generatorSlot == other.generatorSlot + && this.outputBufferSlot == other.outputBufferSlot; } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/operations/ZipComputeNext.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/operations/ZipComputeNext.java index a7ef18e7f..b4f448aa0 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/operations/ZipComputeNext.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/operations/ZipComputeNext.java @@ -12,19 +12,14 @@ package raw.runtime.truffle.runtime.generator.collection.abstract_generator.compute_next.operations; -import raw.runtime.truffle.RawLanguage; - public class ZipComputeNext { private final Object parent1; private final Object parent2; - private final RawLanguage language; - - public ZipComputeNext(Object parent1, Object parent2, RawLanguage language) { + public ZipComputeNext(Object parent1, Object parent2) { this.parent1 = parent1; this.parent2 = parent2; - this.language = language; } public Object getParent1() { @@ -34,8 +29,4 @@ public Object getParent1() { public Object getParent2() { return parent2; } - - public RawLanguage getLanguage() { - return language; - } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/sources/CsvReadComputeNext.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/sources/CsvReadComputeNext.java index fc15354a2..a21ed81f4 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/sources/CsvReadComputeNext.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/sources/CsvReadComputeNext.java @@ -17,12 +17,10 @@ import raw.runtime.truffle.ast.io.csv.reader.parser.RawTruffleCsvParserSettings; import raw.runtime.truffle.runtime.primitives.LocationObject; import raw.runtime.truffle.utils.TruffleCharInputStream; -import raw.sources.api.SourceContext; public class CsvReadComputeNext { private final LocationObject location; private final RootCallTarget rowParserCallTarget; - private final SourceContext context; private final String encoding; private final RawTruffleCsvParserSettings settings; private TruffleCharInputStream stream; @@ -30,11 +28,9 @@ public class CsvReadComputeNext { public CsvReadComputeNext( LocationObject location, - SourceContext context, RootCallTarget rowParserCallTarget, String encoding, RawTruffleCsvParserSettings settings) { - this.context = context; this.location = location; this.rowParserCallTarget = rowParserCallTarget; this.encoding = encoding; @@ -57,10 +53,6 @@ public RootCallTarget getRowParserCallTarget() { return rowParserCallTarget; } - public SourceContext getContext() { - return context; - } - public String getEncoding() { return encoding; } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/sources/JsonReadComputeNext.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/sources/JsonReadComputeNext.java index 72787d82e..2dd627bf9 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/sources/JsonReadComputeNext.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/sources/JsonReadComputeNext.java @@ -16,25 +16,17 @@ import com.oracle.truffle.api.RootCallTarget; import raw.runtime.truffle.runtime.primitives.LocationObject; import raw.runtime.truffle.utils.TruffleCharInputStream; -import raw.sources.api.SourceContext; public class JsonReadComputeNext { private final LocationObject locationObject; private final RootCallTarget parseNextCallTarget; - private final SourceContext context; private final String encoding; - private TruffleCharInputStream stream; - private JsonParser parser; public JsonReadComputeNext( - LocationObject locationObject, - String encoding, - SourceContext context, - RootCallTarget parseNextRootCallTarget) { + LocationObject locationObject, String encoding, RootCallTarget parseNextRootCallTarget) { this.encoding = encoding; - this.context = context; this.locationObject = locationObject; this.parseNextCallTarget = parseNextRootCallTarget; } @@ -63,10 +55,6 @@ public LocationObject getLocationObject() { return locationObject; } - public SourceContext getContext() { - return context; - } - public String getEncoding() { return encoding; } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/sources/ReadLinesComputeNext.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/sources/ReadLinesComputeNext.java index b116fcb2c..e36ea5943 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/sources/ReadLinesComputeNext.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/sources/ReadLinesComputeNext.java @@ -29,10 +29,12 @@ public ReadLinesComputeNext(TruffleCharInputStream stream) { this.stream = stream; } + @TruffleBoundary public void init() { this.reader = new BufferedReader(stream.getReader()); } + @TruffleBoundary public void close() { IOUtils.closeQuietly(reader); } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/sources/XmlReadComputeNext.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/sources/XmlReadComputeNext.java index 9df2cc766..ba7e05e59 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/sources/XmlReadComputeNext.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/abstract_generator/compute_next/sources/XmlReadComputeNext.java @@ -17,12 +17,10 @@ import raw.runtime.truffle.ast.io.xml.parser.RawTruffleXmlParserSettings; import raw.runtime.truffle.runtime.primitives.LocationObject; import raw.runtime.truffle.utils.TruffleCharInputStream; -import raw.sources.api.SourceContext; public class XmlReadComputeNext { private final LocationObject locationObject; protected final RootCallTarget parseNextRootCallTarget; - private final SourceContext context; private final String encoding; private RawTruffleXmlParser parser; private final RawTruffleXmlParserSettings settings; @@ -32,11 +30,9 @@ public class XmlReadComputeNext { public XmlReadComputeNext( LocationObject locationObject, String encoding, - SourceContext context, RootCallTarget parseNextRootCallTarget, RawTruffleXmlParserSettings settings) { this.encoding = encoding; - this.context = context; this.settings = settings; this.locationObject = locationObject; this.parseNextRootCallTarget = parseNextRootCallTarget; @@ -58,10 +54,6 @@ public RootCallTarget getParseNextRootCallTarget() { return parseNextRootCallTarget; } - public SourceContext getContext() { - return context; - } - public String getEncoding() { return encoding; } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/input_buffer/GroupByInputBuffer.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/input_buffer/GroupByInputBuffer.java index 899b73eae..103f9940b 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/input_buffer/GroupByInputBuffer.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/input_buffer/GroupByInputBuffer.java @@ -13,6 +13,7 @@ package raw.runtime.truffle.runtime.generator.collection.off_heap_generator.input_buffer; import com.esotericsoftware.kryo.io.Input; +import com.oracle.truffle.api.CompilerDirectives; import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.group_by.OffHeapGroupByKey; public class GroupByInputBuffer { @@ -32,6 +33,7 @@ public void setKey(Object key) { this.key = key; } + @CompilerDirectives.TruffleBoundary public void setItemsLeftFromInput() { itemsLeft = input.readInt(); } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/input_buffer/InputBufferNodes.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/input_buffer/InputBufferNodes.java index 95dcb83b1..161004608 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/input_buffer/InputBufferNodes.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/input_buffer/InputBufferNodes.java @@ -16,33 +16,9 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import raw.compiler.rql2.source.Rql2TypeWithProperties; -import raw.runtime.truffle.runtime.generator.collection.abstract_generator.compute_next.ComputeNextNodes; import raw.runtime.truffle.runtime.kryo.KryoNodes; public class InputBufferNodes { - @NodeInfo(shortName = "InputBuffer.Close") - @GenerateUncached - @GenerateInline - public abstract static class InputBufferCloseNode extends Node { - - public abstract void execute(Node node, Object generator); - - @Specialization - static void close( - Node node, - GroupByInputBuffer buffer, - @Cached @Cached.Shared("close") ComputeNextNodes.CloseNode closeNode) { - buffer.getInput().close(); - } - - @Specialization - static void close( - Node node, - OrderByInputBuffer buffer, - @Cached @Cached.Shared("close") ComputeNextNodes.CloseNode closeNode) { - buffer.getInput().close(); - } - } @NodeInfo(shortName = "InputBuffer.HeadKey") @GenerateUncached @@ -56,15 +32,12 @@ static Object headKey( Node node, GroupByInputBuffer buffer, @Bind("$node") Node thisNode, - @Cached @Cached.Shared("kryoRead") KryoNodes.KryoReadNode kryoRead) { + @Cached @Cached.Exclusive KryoNodes.KryoReadNode kryoRead) { // read the next key (if it is null, otherwise keep the current one). if (buffer.getKey() == null) { buffer.setKey( kryoRead.execute( - thisNode, - buffer.getOffHeapGroupByKey().getLanguage(), - buffer.getInput(), - buffer.getOffHeapGroupByKey().getKeyType())); + thisNode, buffer.getInput(), buffer.getOffHeapGroupByKey().getKeyType())); buffer.setItemsLeftFromInput(); } return buffer.getKey(); @@ -75,18 +48,13 @@ static Object[] headKey( Node node, OrderByInputBuffer buffer, @Bind("$node") Node thisNode, - @Cached @Cached.Shared("kryoRead") KryoNodes.KryoReadNode kryoRead) { + @Cached @Cached.Exclusive KryoNodes.KryoReadNode kryoRead) { // read the next key (if it is null, otherwise keep the current one). if (buffer.getKeys() == null) { Rql2TypeWithProperties[] keyTypes = buffer.getOffHeapGroupByKey().getKeyTypes(); Object[] keys = new Object[keyTypes.length]; for (int i = 0; i < keyTypes.length; i++) { - keys[i] = - kryoRead.execute( - thisNode, - buffer.getOffHeapGroupByKey().getLanguage(), - buffer.getInput(), - keyTypes[i]); + keys[i] = kryoRead.execute(thisNode, buffer.getInput(), keyTypes[i]); } buffer.setKeys(keys); buffer.setItemsLeftFromInput(); @@ -107,16 +75,13 @@ static Object read( Node node, GroupByInputBuffer buffer, @Bind("$node") Node thisNode, - @Cached @Cached.Shared("kryoRead") KryoNodes.KryoReadNode kryoRead) { + @Cached @Cached.Exclusive KryoNodes.KryoReadNode kryoRead) { buffer.decreaseItemsLeft(); if (buffer.getItemsLeft() == 0) { buffer.setKey(null); } return kryoRead.execute( - thisNode, - buffer.getOffHeapGroupByKey().getLanguage(), - buffer.getInput(), - buffer.getOffHeapGroupByKey().getRowType()); + thisNode, buffer.getInput(), buffer.getOffHeapGroupByKey().getRowType()); } @Specialization @@ -124,16 +89,13 @@ static Object read( Node node, OrderByInputBuffer buffer, @Bind("$node") Node thisNode, - @Cached @Cached.Shared("kryoRead") KryoNodes.KryoReadNode kryoRead) { + @Cached @Cached.Exclusive KryoNodes.KryoReadNode kryoRead) { buffer.decreaseItemsLeft(); if (buffer.getItemsLeft() == 0) { buffer.setKeys(null); } return kryoRead.execute( - thisNode, - buffer.getOffHeapGroupByKey().getLanguage(), - buffer.getInput(), - buffer.getOffHeapGroupByKey().getRowType()); + thisNode, buffer.getInput(), buffer.getOffHeapGroupByKey().getRowType()); } } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/input_buffer/OrderByInputBuffer.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/input_buffer/OrderByInputBuffer.java index 5d715248c..4b671ae3f 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/input_buffer/OrderByInputBuffer.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/input_buffer/OrderByInputBuffer.java @@ -13,6 +13,7 @@ package raw.runtime.truffle.runtime.generator.collection.off_heap_generator.input_buffer; import com.esotericsoftware.kryo.io.Input; +import com.oracle.truffle.api.CompilerDirectives; import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.order_by.OffHeapGroupByKeys; public class OrderByInputBuffer { @@ -32,6 +33,7 @@ public void setKeys(Object[] keys) { this.keys = keys; } + @CompilerDirectives.TruffleBoundary public void setItemsLeftFromInput() { itemsLeft = input.readInt(); } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/OffHeapNodes.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/OffHeapNodes.java index 097741d7e..de7a285d0 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/OffHeapNodes.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/OffHeapNodes.java @@ -12,16 +12,17 @@ package raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap; +import static raw.runtime.truffle.runtime.generator.collection.StaticInitializers.*; + import com.esotericsoftware.kryo.io.Output; import com.esotericsoftware.kryo.unsafe.UnsafeOutput; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.util.ArrayList; -import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; +import raw.runtime.truffle.runtime.data_structures.treemap.TreeMapIterator; +import raw.runtime.truffle.runtime.data_structures.treemap.TreeMapNode; +import raw.runtime.truffle.runtime.data_structures.treemap.TreeMapNodes; import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.distinct.DistinctMemoryGenerator; import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.distinct.DistinctSpilledFilesGenerator; import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.distinct.OffHeapDistinct; @@ -32,7 +33,6 @@ import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.order_by.OrderByMemoryGenerator; import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.order_by.OrderBySpilledFilesGenerator; import raw.runtime.truffle.runtime.kryo.KryoNodes; -import raw.runtime.truffle.utils.IOUtils; public class OffHeapNodes { @NodeInfo(shortName = "OffHeap.Put") @@ -49,19 +49,47 @@ static void put( Object key, Object value, @Bind("$node") Node thisNode, - @Cached @Cached.Shared("flushNode") OffHeapFlushNode flushNode) { - ArrayList list = offHeapGroupByKey.getMemMap().get(key); - if (list == null) { - list = new ArrayList<>(); - offHeapGroupByKey.getMemMap().put(key, list); - // add the size of the key to the memory footprint. (Row size added below in main path.) + @Cached @Cached.Exclusive KryoNodes.KryoWriteNode writer1, + @Cached @Cached.Exclusive KryoNodes.KryoWriteNode writer2, + @Cached TreeMapNodes.TreeMapGetOrCreate putIfNotExistNode) { + @SuppressWarnings("unchecked") + ArrayList list = + (ArrayList) + putIfNotExistNode.execute(thisNode, offHeapGroupByKey.getMemMap(), key); + // add the size of the key to the memory footprint. (Row size added below in main path.) + if (list.isEmpty()) { offHeapGroupByKey.setSize(offHeapGroupByKey.getSize() + offHeapGroupByKey.getKeySize()); } + list.add(value); // add the size of the row to the memory footprint. offHeapGroupByKey.setSize(offHeapGroupByKey.getSize() + offHeapGroupByKey.getRowSize()); + if (offHeapGroupByKey.getSize() >= offHeapGroupByKey.getMaxSize()) { - flushNode.execute(thisNode, offHeapGroupByKey); + // flush + Output kryoOutput = + new UnsafeOutput( + getGroupByKeyNewDiskBuffer(offHeapGroupByKey, thisNode), + offHeapGroupByKey.getKryoOutputBufferSize()); + TreeMapIterator iterator = offHeapGroupByKey.getMemMap().iterator(); + + while (iterator.hasNext()) { + TreeMapNode treeNode = iterator.nextNode(); + @SuppressWarnings("unchecked") + ArrayList values = (ArrayList) treeNode.getValue(); + // write key, then n, then values. + writer1.execute(thisNode, kryoOutput, offHeapGroupByKey.getKeyType(), treeNode.getKey()); + kryoWriteInt(kryoOutput, values.size()); + for (Object v : values) { + writer2.execute(thisNode, kryoOutput, offHeapGroupByKey.getRowType(), v); + } + } + + kryoOutputClose(kryoOutput); + // reset both the memory map and memory footprint. + + offHeapGroupByKey.getMemMap().clear(); + offHeapGroupByKey.setSize(0); } } @@ -72,19 +100,52 @@ static void put( Object[] keys, Object value, @Bind("$node") Node thisNode, - @Cached @Cached.Shared("flushNode") OffHeapFlushNode flushNode) { - ArrayList list = offHeapGroupByKeys.getMemMap().get(keys); - if (list == null) { - list = new ArrayList<>(); - offHeapGroupByKeys.getMemMap().put(keys, list); - // add the size of the key to the memory footprint. (Row size added below in main path.) + @Cached @Cached.Exclusive KryoNodes.KryoWriteNode writer1, + @Cached @Cached.Exclusive KryoNodes.KryoWriteNode writer2, + @Cached TreeMapNodes.TreeMapGetOrCreateArrayKeysNode getOrCreateArrayKeysNode) { + @SuppressWarnings("unchecked") + ArrayList list = + (ArrayList) + getOrCreateArrayKeysNode.execute( + thisNode, + offHeapGroupByKeys.getMemMap(), + keys, + offHeapGroupByKeys.getKeyOrderings()); + + if (list.isEmpty()) { offHeapGroupByKeys.setSize(offHeapGroupByKeys.getSize() + offHeapGroupByKeys.getKeysSize()); } + list.add(value); // add the size of the row to the memory footprint. offHeapGroupByKeys.setSize(offHeapGroupByKeys.getSize() + offHeapGroupByKeys.getRowSize()); if (offHeapGroupByKeys.getSize() >= offHeapGroupByKeys.getMaxSize()) { - flushNode.execute(thisNode, offHeapGroupByKeys); + // flush + Output kryoOutput = + new UnsafeOutput( + groupByKeysNextFile(offHeapGroupByKeys, thisNode), + offHeapGroupByKeys.getKryoOutputBufferSize()); + TreeMapIterator iterator = offHeapGroupByKeys.getMemMap().iterator(); + + while (iterator.hasNext()) { + TreeMapNode treeNode = iterator.nextNode(); + // write keys, then n, then values. + for (int i = 0; i < offHeapGroupByKeys.getKeyTypes().length; i++) { + Object[] k = (Object[]) treeNode.getKey(); + writer1.execute(thisNode, kryoOutput, offHeapGroupByKeys.getKeyTypes()[i], k[i]); + } + @SuppressWarnings("unchecked") + ArrayList values = (ArrayList) treeNode.getValue(); + kryoWriteInt(kryoOutput, values.size()); + for (Object v : values) { + writer2.execute(thisNode, kryoOutput, offHeapGroupByKeys.getRowType(), v); + } + } + + kryoOutputClose(kryoOutput); + // reset the memory map and footprint + offHeapGroupByKeys.getMemMap().clear(); + offHeapGroupByKeys.setSize(0); } } @@ -95,135 +156,121 @@ static void put( Object item, Object value, @Bind("$node") Node thisNode, - @Cached @Cached.Shared("flushNode") OffHeapFlushNode flushNode) { + @Cached @Cached.Exclusive KryoNodes.KryoWriteNode writer, + @Cached @Cached.Exclusive TreeMapNodes.TreeMapGetOrCreateDistinct addDistinct) { // append the value to the list of values for the key. - boolean added = offHeapDistinct.getIndex().add(item); + boolean added = addDistinct.execute(thisNode, offHeapDistinct.getIndex(), item); if (added) { offHeapDistinct.setBinarySize( offHeapDistinct.getBinarySize() + offHeapDistinct.getItemSize()); if (offHeapDistinct.getBinarySize() >= offHeapDistinct.getBlockSize()) { - flushNode.execute(thisNode, offHeapDistinct); + // flush + Output kryoOutput = + new UnsafeOutput( + distinctNextFile(offHeapDistinct, node), + offHeapDistinct.getKryoInputBufferSize()); + TreeMapIterator iterator = offHeapDistinct.getIndex().iterator(); + + while (iterator.hasNext()) { + Object key = iterator.nextKey(); + writer.execute(thisNode, kryoOutput, offHeapDistinct.getItemType(), key); + } + + kryoOutputClose(kryoOutput); + // reset the memory map and footprint + offHeapDistinct.getIndex().clear(); + offHeapDistinct.setBinarySize(0); } } } } - @NodeInfo(shortName = "OffHeap.Flush") + @NodeInfo(shortName = "OffHeap.Generator") @GenerateUncached @GenerateInline - public abstract static class OffHeapFlushNode extends Node { + public abstract static class OffHeapGeneratorNode extends Node { - public abstract void execute(Node node, Object offHeap); + public abstract Object execute(Node node, Object offHeap); - @Specialization - static void flush( + @Specialization(guards = "offHeapGroupByKey.getSpilledBuffers().isEmpty()") + static GroupByMemoryGenerator generator(Node node, OffHeapGroupByKey offHeapGroupByKey) { + return new GroupByMemoryGenerator(offHeapGroupByKey); + } + + @Specialization(guards = "!offHeapGroupByKey.getSpilledBuffers().isEmpty()") + static GroupBySpilledFilesGenerator generator( Node node, OffHeapGroupByKey offHeapGroupByKey, - @Cached OffHeapNewDiskBufferNode newDiskBufferNode, @Bind("$node") Node thisNode, - @Cached @Cached.Shared("kryoWriter") KryoNodes.KryoWriteNode writer) { + @Cached @Cached.Exclusive KryoNodes.KryoWriteNode writer1, + @Cached @Cached.Exclusive KryoNodes.KryoWriteNode writer2) { + // flush Output kryoOutput = new UnsafeOutput( - newDiskBufferNode.execute(thisNode, offHeapGroupByKey), + getGroupByKeyNewDiskBuffer(offHeapGroupByKey, thisNode), offHeapGroupByKey.getKryoOutputBufferSize()); - for (Object key : offHeapGroupByKey.getMemMap().keySet()) { - ArrayList values = offHeapGroupByKey.getMemMap().get(key); + TreeMapIterator iterator = offHeapGroupByKey.getMemMap().iterator(); + + while (iterator.hasNext()) { + TreeMapNode treeNode = iterator.nextNode(); + @SuppressWarnings("unchecked") + ArrayList values = (ArrayList) treeNode.getValue(); // write key, then n, then values. - writer.execute(thisNode, kryoOutput, offHeapGroupByKey.getKeyType(), key); - kryoOutput.writeInt(values.size()); + writer1.execute(thisNode, kryoOutput, offHeapGroupByKey.getKeyType(), treeNode.getKey()); + kryoWriteInt(kryoOutput, values.size()); for (Object value : values) { - writer.execute(thisNode, kryoOutput, offHeapGroupByKey.getRowType(), value); + writer2.execute(thisNode, kryoOutput, offHeapGroupByKey.getRowType(), value); } } - kryoOutput.close(); + + kryoOutputClose(kryoOutput); // reset both the memory map and memory footprint. + offHeapGroupByKey.getMemMap().clear(); offHeapGroupByKey.setSize(0); + + return new GroupBySpilledFilesGenerator(offHeapGroupByKey); } - @Specialization - static void flush( + @Specialization(guards = "offHeapGroupByKeys.getSpilledBuffers().isEmpty()") + static OrderByMemoryGenerator generator(Node node, OffHeapGroupByKeys offHeapGroupByKeys) { + return new OrderByMemoryGenerator(offHeapGroupByKeys); + } + + @Specialization(guards = "!offHeapGroupByKeys.getSpilledBuffers().isEmpty()") + static OrderBySpilledFilesGenerator generator( Node node, OffHeapGroupByKeys offHeapGroupByKeys, @Bind("$node") Node thisNode, - @Cached @Cached.Shared("nextFile") OffHeapNextFileNode nextFileNode, - @Cached @Cached.Shared("kryoWriter") KryoNodes.KryoWriteNode writer) { + @Cached @Cached.Exclusive KryoNodes.KryoWriteNode writer1, + @Cached @Cached.Exclusive KryoNodes.KryoWriteNode writer2) { + // flush Output kryoOutput = new UnsafeOutput( - nextFileNode.execute(thisNode, offHeapGroupByKeys), + groupByKeysNextFile(offHeapGroupByKeys, thisNode), offHeapGroupByKeys.getKryoOutputBufferSize()); - for (Object[] keys : offHeapGroupByKeys.getMemMap().keySet()) { + TreeMapIterator iterator = offHeapGroupByKeys.getMemMap().iterator(); + + while (iterator.hasNext()) { + TreeMapNode treeNode = iterator.nextNode(); // write keys, then n, then values. - for (int i = 0; i < keys.length; i++) { - writer.execute(thisNode, kryoOutput, offHeapGroupByKeys.getKeyTypes()[i], keys[i]); + for (int i = 0; i < offHeapGroupByKeys.getKeyTypes().length; i++) { + Object[] k = (Object[]) treeNode.getKey(); + writer1.execute(thisNode, kryoOutput, offHeapGroupByKeys.getKeyTypes()[i], k[i]); } - ArrayList values = offHeapGroupByKeys.getMemMap().get(keys); - kryoOutput.writeInt(values.size()); - for (Object value : values) { - writer.execute(thisNode, kryoOutput, offHeapGroupByKeys.getRowType(), value); + @SuppressWarnings("unchecked") + ArrayList values = (ArrayList) treeNode.getValue(); + kryoWriteInt(kryoOutput, values.size()); + for (Object v : values) { + writer2.execute(thisNode, kryoOutput, offHeapGroupByKeys.getRowType(), v); } } - kryoOutput.close(); + + kryoOutputClose(kryoOutput); // reset the memory map and footprint offHeapGroupByKeys.getMemMap().clear(); offHeapGroupByKeys.setSize(0); - } - - @Specialization - static void flush( - Node node, - OffHeapDistinct offHeapDistinct, - @Bind("$node") Node thisNode, - @Cached @Cached.Shared("nextFile") OffHeapNextFileNode nextFileNode, - @Cached @Cached.Shared("kryoWriter") KryoNodes.KryoWriteNode writer) { - Output kryoOutput = - new UnsafeOutput( - nextFileNode.execute(thisNode, offHeapDistinct), - offHeapDistinct.getKryoInputBufferSize()); - for (Object item : offHeapDistinct.getIndex()) { - writer.execute(thisNode, kryoOutput, offHeapDistinct.getItemType(), item); - } - kryoOutput.close(); - // reset the memory map and footprint - offHeapDistinct.getIndex().clear(); - offHeapDistinct.setBinarySize(0); - } - } - @NodeInfo(shortName = "OffHeap.Generator") - @GenerateUncached - @GenerateInline - public abstract static class OffHeapGeneratorNode extends Node { - - public abstract Object execute(Node node, Object offHeap); - - @Specialization(guards = "offHeapGroupByKey.getSpilledBuffers().isEmpty()") - static GroupByMemoryGenerator generator(Node node, OffHeapGroupByKey offHeapGroupByKey) { - return new GroupByMemoryGenerator(offHeapGroupByKey); - } - - @Specialization(guards = "!offHeapGroupByKey.getSpilledBuffers().isEmpty()") - static GroupBySpilledFilesGenerator generator( - Node node, - OffHeapGroupByKey offHeapGroupByKey, - @Bind("$node") Node thisNode, - @Cached @Cached.Shared("flush") OffHeapFlushNode flushNode) { - flushNode.execute(thisNode, offHeapGroupByKey); - return new GroupBySpilledFilesGenerator(offHeapGroupByKey); - } - - @Specialization(guards = "offHeapGroupByKeys.getSpilledBuffers().isEmpty()") - static OrderByMemoryGenerator generator(Node node, OffHeapGroupByKeys offHeapGroupByKeys) { - return new OrderByMemoryGenerator(offHeapGroupByKeys); - } - - @Specialization(guards = "!offHeapGroupByKeys.getSpilledBuffers().isEmpty()") - static OrderBySpilledFilesGenerator generator( - Node node, - OffHeapGroupByKeys offHeapGroupByKeys, - @Bind("$node") Node thisNode, - @Cached @Cached.Shared("flush") OffHeapFlushNode flushNode) { - flushNode.execute(thisNode, offHeapGroupByKeys); return new OrderBySpilledFilesGenerator(offHeapGroupByKeys); } @@ -237,64 +284,25 @@ static DistinctSpilledFilesGenerator generator( Node node, OffHeapDistinct offHeapDistinct, @Bind("$node") Node thisNode, - @Cached @Cached.Shared("flush") OffHeapFlushNode flushNode) { - flushNode.execute(thisNode, offHeapDistinct); - return new DistinctSpilledFilesGenerator(offHeapDistinct); - } - } - - @NodeInfo(shortName = "OffHeap.NewDiskBuffer") - @GenerateUncached - @GenerateInline - public abstract static class OffHeapNewDiskBufferNode extends Node { + @Cached @Cached.Exclusive KryoNodes.KryoWriteNode writer) { - public abstract FileOutputStream execute(Node node, Object offHeapGroupByKey); + // flush + Output kryoOutput = + new UnsafeOutput( + distinctNextFile(offHeapDistinct, node), offHeapDistinct.getKryoInputBufferSize()); + TreeMapIterator iterator = offHeapDistinct.getIndex().iterator(); - @Specialization - static FileOutputStream newDiskBuffer( - Node node, OffHeapGroupByKey offHeapGroupByKey, @Bind("$node") Node thisNode) { - File file; - file = IOUtils.getScratchFile("groupby.", ".kryo", offHeapGroupByKey.getContext()).toFile(); - offHeapGroupByKey.getSpilledBuffers().add(file); - try { - return new FileOutputStream(file); - } catch (FileNotFoundException e) { - throw new RawTruffleRuntimeException(e, thisNode); + while (iterator.hasNext()) { + Object key = iterator.nextKey(); + writer.execute(thisNode, kryoOutput, offHeapDistinct.getItemType(), key); } - } - } - @NodeInfo(shortName = "OffHeap.nextFile") - @GenerateUncached - @GenerateInline - public abstract static class OffHeapNextFileNode extends Node { - - public abstract FileOutputStream execute(Node node, Object offHeapGroupByKeys); - - @Specialization - static FileOutputStream nextFile( - Node node, OffHeapGroupByKeys offHeapGroupByKeys, @Bind("$node") Node thisNode) { - File file; - file = IOUtils.getScratchFile("orderby.", ".kryo", offHeapGroupByKeys.getContext()).toFile(); - offHeapGroupByKeys.getSpilledBuffers().add(file); - try { - return new FileOutputStream(file); - } catch (FileNotFoundException e) { - throw new RawTruffleRuntimeException(e, thisNode); - } - } + kryoOutputClose(kryoOutput); + // reset the memory map and footprint + offHeapDistinct.getIndex().clear(); + offHeapDistinct.setBinarySize(0); - @Specialization - static FileOutputStream nextFile( - Node node, OffHeapDistinct offHeapDistinct, @Bind("$node") Node thisNode) { - File file; - file = IOUtils.getScratchFile("distinct.", ".kryo", offHeapDistinct.getContext()).toFile(); - offHeapDistinct.getSpilledBuffers().add(file); - try { - return new FileOutputStream(file); - } catch (FileNotFoundException e) { - throw new RawTruffleRuntimeException(e, thisNode); - } + return new DistinctSpilledFilesGenerator(offHeapDistinct); } } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/distinct/DistinctMemoryGenerator.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/distinct/DistinctMemoryGenerator.java index 8beac4c4a..83f4c7e36 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/distinct/DistinctMemoryGenerator.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/distinct/DistinctMemoryGenerator.java @@ -21,20 +21,20 @@ import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; -import java.util.Iterator; import java.util.Objects; +import raw.runtime.truffle.runtime.data_structures.treemap.TreeMapIterator; import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; import raw.runtime.truffle.runtime.list.StringList; @ExportLibrary(InteropLibrary.class) public class DistinctMemoryGenerator implements TruffleObject { - private final Iterator items; + private final TreeMapIterator items; public DistinctMemoryGenerator(OffHeapDistinct offHeapDistinct) { this.items = offHeapDistinct.getIndex().iterator(); } - public Iterator getItems() { + public TreeMapIterator getItems() { return items; } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/distinct/OffHeapDistinct.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/distinct/OffHeapDistinct.java index 85c1703f0..b0ef56247 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/distinct/OffHeapDistinct.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/distinct/OffHeapDistinct.java @@ -12,18 +12,15 @@ package raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.distinct; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.frame.MaterializedFrame; import java.io.File; import java.util.ArrayList; -import java.util.TreeSet; import raw.compiler.rql2.source.Rql2TypeWithProperties; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.runtime.operators.OperatorNodesFactory; +import raw.runtime.truffle.runtime.data_structures.treemap.TreeMapObject; import raw.runtime.truffle.utils.KryoFootPrint; -import raw.sources.api.SourceContext; public class OffHeapDistinct { - private final TreeSet + private final TreeMapObject index; // in-memory map that's used as long as the data fits in memory. private final ArrayList spilledBuffers = new ArrayList<>(); // list of files that contain the spilled data. @@ -38,30 +35,29 @@ public class OffHeapDistinct { private final int kryoOutputBufferSize, kryoInputBufferSize; // size of the kryo buffers used to write and read the data. - private final SourceContext context; + private final MaterializedFrame frame; - private final RawLanguage language; - - @TruffleBoundary // Needed because of SourceContext - public OffHeapDistinct(Rql2TypeWithProperties vType, RawLanguage rl, SourceContext context) { - this.index = new TreeSet<>(OperatorNodesFactory.CompareUninlinedNodeGen.getUncached()::execute); + public OffHeapDistinct( + Rql2TypeWithProperties vType, + MaterializedFrame frame, + long blockSize, + int kryoOutputBufferSize, + int kryoInputBufferSize) { + this.index = new TreeMapObject(); this.itemType = vType; this.itemSize = KryoFootPrint.of(vType); this.binarySize = 0; - this.blockSize = context.settings().getMemorySize("raw.runtime.external.disk-block-max-size"); - this.language = rl; - this.kryoOutputBufferSize = - (int) context.settings().getMemorySize("raw.runtime.kryo.output-buffer-size"); - this.kryoInputBufferSize = - (int) context.settings().getMemorySize("raw.runtime.kryo.input-buffer-size"); - this.context = context; + this.blockSize = blockSize; + this.kryoOutputBufferSize = kryoOutputBufferSize; + this.kryoInputBufferSize = kryoInputBufferSize; + this.frame = frame; } public void setBinarySize(int binarySize) { this.binarySize = binarySize; } - public TreeSet getIndex() { + public TreeMapObject getIndex() { return index; } @@ -93,11 +89,7 @@ public int getKryoInputBufferSize() { return kryoInputBufferSize; } - public SourceContext getContext() { - return context; - } - - public RawLanguage getLanguage() { - return language; + public MaterializedFrame getFrame() { + return frame; } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/group_by/GroupByMemoryGenerator.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/group_by/GroupByMemoryGenerator.java index 2227c751b..729b4f81b 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/group_by/GroupByMemoryGenerator.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/group_by/GroupByMemoryGenerator.java @@ -21,24 +21,24 @@ import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; -import java.util.Iterator; import java.util.Objects; +import raw.runtime.truffle.runtime.data_structures.treemap.TreeMapIterator; import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; import raw.runtime.truffle.runtime.list.StringList; @ExportLibrary(InteropLibrary.class) public class GroupByMemoryGenerator implements TruffleObject { - private final Iterator keys; + private final TreeMapIterator iterator; private final OffHeapGroupByKey offHeapGroupByKey; public GroupByMemoryGenerator(OffHeapGroupByKey offHeapGroupByKey) { - keys = offHeapGroupByKey.getMemMap().keySet().iterator(); + iterator = offHeapGroupByKey.getMemMap().iterator(); this.offHeapGroupByKey = offHeapGroupByKey; } - public Iterator getKeys() { - return keys; + public TreeMapIterator getTreeNodesIterator() { + return iterator; } public OffHeapGroupByKey getOffHeapGroupByKey() { diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/group_by/OffHeapGroupByKey.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/group_by/OffHeapGroupByKey.java index 3d7b096c1..6f62adae9 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/group_by/OffHeapGroupByKey.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/group_by/OffHeapGroupByKey.java @@ -12,23 +12,15 @@ package raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.group_by; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.util.ArrayList; -import java.util.TreeMap; import raw.compiler.rql2.source.Rql2TypeWithProperties; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; +import raw.runtime.truffle.runtime.data_structures.treemap.TreeMapObject; import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.record_shaper.RecordShaper; -import raw.runtime.truffle.runtime.operators.OperatorNodesFactory; -import raw.runtime.truffle.utils.IOUtils; import raw.runtime.truffle.utils.KryoFootPrint; -import raw.sources.api.SourceContext; public class OffHeapGroupByKey { - private final TreeMap> + private final TreeMapObject memMap; // in-memory map that's used as long as the data fits in memory. private final ArrayList spilledBuffers = new ArrayList<>(); // list of files that contain the spilled data. @@ -37,8 +29,6 @@ public class OffHeapGroupByKey { size; // estimated size of currently memory held objects (when reaching blockSize, spill // to // disk). - - private final SourceContext context; private final Rql2TypeWithProperties keyType, rowType; // grouping key and row types. private final int kryoOutputBufferSize, kryoInputBufferSize; // size of the kryo buffers used to write and read the data. @@ -46,29 +36,22 @@ public class OffHeapGroupByKey { private final RecordShaper reshape; - private final RawLanguage language; - - @TruffleBoundary // Needed because of SourceContext public OffHeapGroupByKey( Rql2TypeWithProperties kType, Rql2TypeWithProperties rowType, - RawLanguage language, - SourceContext context, - RecordShaper reshape) { - this.language = language; - this.memMap = - new TreeMap<>(OperatorNodesFactory.CompareUninlinedNodeGen.getUncached()::execute); + RecordShaper reshape, + long maxSize, + int kryoOutputBufferSize, + int kryoInputBufferSize) { + this.memMap = new TreeMapObject(); this.keyType = kType; this.rowType = rowType; this.rowSize = KryoFootPrint.of(rowType); this.keySize = KryoFootPrint.of(kType); this.size = 0; - this.maxSize = context.settings().getMemorySize("raw.runtime.external.disk-block-max-size"); - this.kryoOutputBufferSize = - (int) context.settings().getMemorySize("raw.runtime.kryo.output-buffer-size"); - this.kryoInputBufferSize = - (int) context.settings().getMemorySize("raw.runtime.kryo.input-buffer-size"); - this.context = context; + this.maxSize = maxSize; + this.kryoOutputBufferSize = kryoOutputBufferSize; + this.kryoInputBufferSize = kryoInputBufferSize; this.reshape = reshape; } @@ -76,7 +59,7 @@ public void setSize(int size) { this.size = size; } - public TreeMap> getMemMap() { + public TreeMapObject getMemMap() { return memMap; } @@ -92,10 +75,6 @@ public int getSize() { return size; } - public SourceContext getContext() { - return context; - } - public Rql2TypeWithProperties getKeyType() { return keyType; } @@ -123,19 +102,4 @@ public int getRowSize() { public RecordShaper getReshape() { return reshape; } - - public RawLanguage getLanguage() { - return language; - } - - public FileOutputStream newDiskBuffer() throws RawTruffleRuntimeException { - File file; - file = IOUtils.getScratchFile("groupby.", ".kryo", this.context).toFile(); - spilledBuffers.add(file); - try { - return new FileOutputStream(file); - } catch (FileNotFoundException e) { - throw new RawTruffleRuntimeException(e.getMessage(), e, null); - } - } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/order_by/OffHeapGroupByKeys.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/order_by/OffHeapGroupByKeys.java index 9c64b7b98..ced7ab204 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/order_by/OffHeapGroupByKeys.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/order_by/OffHeapGroupByKeys.java @@ -12,24 +12,15 @@ package raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.order_by; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import java.io.File; import java.util.ArrayList; -import java.util.TreeMap; import raw.compiler.rql2.source.Rql2TypeWithProperties; -import raw.runtime.truffle.RawLanguage; -import raw.runtime.truffle.runtime.operators.OperatorNodes; -import raw.runtime.truffle.runtime.operators.OperatorNodesFactory; +import raw.runtime.truffle.runtime.data_structures.treemap.TreeMapObject; import raw.runtime.truffle.utils.KryoFootPrint; -import raw.sources.api.SourceContext; public class OffHeapGroupByKeys { - - private final RawLanguage language; - private final int[] keyOrderings; - private final TreeMap> - memMap; // in-memory map from arrays of keys to array of rows. + private final TreeMapObject memMap; // in-memory map from arrays of keys to array of rows. private final ArrayList spilledBuffers = new ArrayList<>(); // list of files that contain the spilled data. private final long maxSize; // maximum size of a spilled file. @@ -44,11 +35,6 @@ public class OffHeapGroupByKeys { private final int kryoOutputBufferSize, kryoInputBufferSize; // size of the kryo buffers used to write and read the data. - private final SourceContext context; - - private final OperatorNodes.CompareUninlinedNode compare = - OperatorNodesFactory.CompareUninlinedNodeGen.getUncached(); - private static int keysFootPrint(Rql2TypeWithProperties[] keyType) { int size = 0; for (Rql2TypeWithProperties t : keyType) { @@ -57,48 +43,28 @@ private static int keysFootPrint(Rql2TypeWithProperties[] keyType) { return size; } - private int compareKeys(Object[] keys1, Object[] keys2) { - // Keys are compared in order, until a difference is found. - // If all keys are equal, then the rows are equal. - // If keys are different, the comparison result is multiplied by the 'order' of the key to - // reflect the "ASC/DESC". - for (int i = 0; i < keys1.length; i++) { - int cmp = compare.execute(keys1[i], keys2[i]); - if (cmp != 0) { - return keyOrderings[i] * cmp; - } - } - return 0; - } - - @TruffleBoundary // Needed because of SourceContext public OffHeapGroupByKeys( Rql2TypeWithProperties[] kTypes, Rql2TypeWithProperties rowType, int[] keyOrderings, - RawLanguage language, - SourceContext context) { - this.memMap = new TreeMap<>(this::compareKeys); + long maxSize, + int kryoOutputBufferSize, + int kryoInputBufferSize) { + this.memMap = new TreeMapObject(); this.keyTypes = kTypes; this.rowType = rowType; this.rowSize = KryoFootPrint.of(rowType); this.keysSize = keysFootPrint(kTypes); this.size = 0; - this.maxSize = context.settings().getMemorySize("raw.runtime.external.disk-block-max-size"); - this.kryoOutputBufferSize = - (int) context.settings().getMemorySize("raw.runtime.kryo.output-buffer-size"); - this.kryoInputBufferSize = - (int) context.settings().getMemorySize("raw.runtime.kryo.input-buffer-size"); - this.context = context; - this.language = language; - this.keyOrderings = keyOrderings; - } - public RawLanguage getLanguage() { - return language; + this.maxSize = maxSize; + this.kryoOutputBufferSize = kryoOutputBufferSize; + this.kryoInputBufferSize = kryoInputBufferSize; + + this.keyOrderings = keyOrderings; } - public TreeMap> getMemMap() { + public TreeMapObject getMemMap() { return memMap; } @@ -138,10 +104,6 @@ public int getKryoInputBufferSize() { return kryoInputBufferSize; } - public SourceContext getContext() { - return context; - } - public void setSize(int size) { this.size = size; } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/order_by/OrderByMemoryGenerator.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/order_by/OrderByMemoryGenerator.java index 4c3293676..d9c47a34c 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/order_by/OrderByMemoryGenerator.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/off_heap/order_by/OrderByMemoryGenerator.java @@ -23,6 +23,7 @@ import com.oracle.truffle.api.nodes.Node; import java.util.Iterator; import java.util.Objects; +import raw.runtime.truffle.runtime.data_structures.treemap.TreeMapIterator; import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; import raw.runtime.truffle.runtime.list.StringList; @@ -31,13 +32,12 @@ @ExportLibrary(InteropLibrary.class) public class OrderByMemoryGenerator implements TruffleObject { private final OffHeapGroupByKeys offHeapGroupByKeys; - - private final Iterator keysIterator; // the iterator from the in-memory map keys. + private final TreeMapIterator nodeIterator; // the iterator from the in-memory map keys. private Iterator values = null; // the current iterator over the grouped rows public OrderByMemoryGenerator(OffHeapGroupByKeys offHeapGroupByKeys) { this.offHeapGroupByKeys = offHeapGroupByKeys; - this.keysIterator = offHeapGroupByKeys.getMemMap().keySet().iterator(); + this.nodeIterator = offHeapGroupByKeys.getMemMap().iterator(); } public void setValues(Iterator values) { @@ -48,8 +48,8 @@ public OffHeapGroupByKeys getOffHeapGroupByKeys() { return offHeapGroupByKeys; } - public Iterator getKeysIterator() { - return keysIterator; + public TreeMapIterator getNodeIterator() { + return nodeIterator; } public Iterator getValues() { diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/record_shaper/RecordShaper.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/record_shaper/RecordShaper.java index e6e6d6c7c..6c95f0384 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/record_shaper/RecordShaper.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/record_shaper/RecordShaper.java @@ -12,22 +12,13 @@ package raw.runtime.truffle.runtime.generator.collection.off_heap_generator.record_shaper; -import raw.runtime.truffle.RawLanguage; - public class RecordShaper { - private final RawLanguage language; - private final boolean forList; - public RecordShaper(RawLanguage language, boolean forList) { - this.language = language; + public RecordShaper(boolean forList) { this.forList = forList; } - public RawLanguage getLanguage() { - return language; - } - public boolean forList() { return forList; } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/record_shaper/RecordShaperNodes.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/record_shaper/RecordShaperNodes.java index 6ac52eff7..f15359080 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/record_shaper/RecordShaperNodes.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/generator/collection/off_heap_generator/record_shaper/RecordShaperNodes.java @@ -12,20 +12,12 @@ package raw.runtime.truffle.runtime.generator.collection.off_heap_generator.record_shaper; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.GenerateInline; -import com.oracle.truffle.api.dsl.GenerateUncached; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.UnknownIdentifierException; -import com.oracle.truffle.api.interop.UnsupportedMessageException; -import com.oracle.truffle.api.interop.UnsupportedTypeException; -import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; -import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; +import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.runtime.list.ObjectList; -import raw.runtime.truffle.runtime.record.RecordObject; +import raw.runtime.truffle.runtime.record.RecordNodes; public class RecordShaperNodes { @NodeInfo(shortName = "RecordShaper.MakeRow") @@ -35,22 +27,24 @@ public abstract static class MakeRowNode extends Node { public abstract Object execute(Node node, Object shaper, Object key, Object[] values); + public static RawLanguage getRawLanguage(Node node) { + return RawLanguage.get(node); + } + @Specialization(guards = {"shaper != null", "!shaper.forList()"}) static Object makeRowCollection( Node node, RecordShaper shaper, Object key, Object[] values, - @CachedLibrary(limit = "3") @Cached.Shared("records") InteropLibrary records) { - RecordObject record = shaper.getLanguage().createRecord(); - try { - records.writeMember(record, "key", key); - records.writeMember(record, "group", new ObjectList(values).toIterable()); - } catch (UnsupportedMessageException - | UnknownIdentifierException - | UnsupportedTypeException e) { - throw new RawTruffleInternalErrorException(e); - } + @Bind("$node") Node thisNode, + @Cached(value = "getRawLanguage(thisNode)", allowUncached = true) RawLanguage language, + @Cached @Cached.Exclusive RecordNodes.AddPropNode addPropNode1, + @Cached @Cached.Exclusive RecordNodes.AddPropNode addPropNode2) { + Object record = language.createPureRecord(); + addPropNode1.execute(thisNode, record, "key", key, false); + addPropNode2.execute(thisNode, record, "group", new ObjectList(values).toIterable(), false); + return record; } @@ -60,16 +54,13 @@ static Object makeRowList( RecordShaper shaper, Object key, Object[] values, - @CachedLibrary(limit = "3") @Cached.Shared("records") InteropLibrary records) { - RecordObject record = shaper.getLanguage().createRecord(); - try { - records.writeMember(record, "key", key); - records.writeMember(record, "group", new ObjectList(values)); - } catch (UnsupportedMessageException - | UnknownIdentifierException - | UnsupportedTypeException e) { - throw new RawTruffleInternalErrorException(e); - } + @Bind("$node") Node thisNode, + @Cached(value = "getRawLanguage(thisNode)", allowUncached = true) RawLanguage language, + @Cached @Cached.Exclusive RecordNodes.AddPropNode addPropNode1, + @Cached @Cached.Exclusive RecordNodes.AddPropNode addPropNode2) { + Object record = language.createPureRecord(); + addPropNode1.execute(node, record, "key", key, false); + addPropNode2.execute(node, record, "group", new ObjectList(values), false); return record; } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/IterableNodes.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/IterableNodes.java index d4d6826ed..a250abf57 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/IterableNodes.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/IterableNodes.java @@ -12,11 +12,20 @@ package raw.runtime.truffle.runtime.iterable; +import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.Frame; +import com.oracle.truffle.api.frame.MaterializedFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; -import raw.runtime.truffle.runtime.function.FunctionExecuteNodes; +import raw.runtime.truffle.ast.osr.OSRGeneratorNode; +import raw.runtime.truffle.ast.osr.bodies.OSRCollectionEquiJoinInitBodyNode; +import raw.runtime.truffle.ast.osr.bodies.OSRDistinctGetGeneratorNode; +import raw.runtime.truffle.ast.osr.bodies.OSROrderByGetGeneratorNode; +import raw.runtime.truffle.ast.osr.conditions.OSRHasNextConditionNode; import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; +import raw.runtime.truffle.runtime.generator.collection.StaticInitializers; import raw.runtime.truffle.runtime.generator.collection.abstract_generator.AbstractGenerator; import raw.runtime.truffle.runtime.generator.collection.abstract_generator.compute_next.operations.*; import raw.runtime.truffle.runtime.generator.collection.off_heap_generator.off_heap.OffHeapNodes; @@ -32,6 +41,7 @@ public class IterableNodes { @NodeInfo(shortName = "Iterable.GetGenerator") @GenerateUncached @GenerateInline + @ImportStatic(StaticInitializers.class) public abstract static class GetGeneratorNode extends Node { public abstract Object execute(Node node, Object generator); @@ -110,7 +120,13 @@ static Object getGenerator( IterableNodes.GetGeneratorNode getGeneratorNode) { Object parentGenerator = getGeneratorNode.execute(thisNode, collection.getParentIterable()); return new AbstractGenerator( - new FilterComputeNext(parentGenerator, collection.getPredicate())); + new FilterComputeNext( + parentGenerator, + collection.getPredicate(), + collection.getFrame(), + collection.getGeneratorSlot(), + collection.getFunctionSlot(), + collection.getResultSlot())); } @Specialization @@ -162,33 +178,52 @@ static Object getGenerator( getGeneratorNode1.execute(thisNode, collection.getParentIterable1()); Object parentGenerator2 = getGeneratorNode2.execute(thisNode, collection.getParentIterable2()); - return new AbstractGenerator( - new ZipComputeNext(parentGenerator1, parentGenerator2, collection.getLang())); + return new AbstractGenerator(new ZipComputeNext(parentGenerator1, parentGenerator2)); } - @Specialization + public static LoopNode getDistinctGenLoopNode(DistinctCollection collection) { + return Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRHasNextConditionNode(collection.getGeneratorSlot()), + new OSRDistinctGetGeneratorNode( + collection.getGeneratorSlot(), collection.getOffHeapDistinctSlot()))); + } + + @Specialization(guards = "cachedCollection.hasSameSlots(collection)", limit = "8", unroll = 8) static Object getGenerator( Node node, DistinctCollection collection, @Bind("$node") Node thisNode, + @Cached("collection") DistinctCollection cachedCollection, + @Cached( + value = "getDistinctGenLoopNode(cachedCollection)", + inline = false, + allowUncached = true) + LoopNode loopNode, @Cached(inline = false) @Cached.Shared("getGenerator1") IterableNodes.GetGeneratorNode getGeneratorNode, @Cached GeneratorNodes.GeneratorInitNode initNode, - @Cached @Cached.Shared("hasNext") GeneratorNodes.GeneratorHasNextNode hasNextNode, - @Cached @Cached.Shared("next") GeneratorNodes.GeneratorNextNode nextNode, @Cached @Cached.Shared("close") GeneratorNodes.GeneratorCloseNode closeNode, - @Cached @Cached.Shared("put") OffHeapNodes.OffHeapGroupByPutNode putNode, - @Cached @Cached.Shared("generator") OffHeapNodes.OffHeapGeneratorNode generatorNode) { + @Cached @Cached.Shared("generator") OffHeapNodes.OffHeapGeneratorNode generatorNode, + @Cached(value = "getContextValues(thisNode)", dimensions = 1, allowUncached = true) + long[] contextValues) { OffHeapDistinct index = new OffHeapDistinct( - collection.getRowType(), collection.getLang(), collection.getContext()); + collection.getRowType(), + collection.getFrame(), + contextValues[0], + (int) contextValues[1], + (int) contextValues[2]); Object generator = getGeneratorNode.execute(thisNode, collection.getIterable()); try { initNode.execute(thisNode, generator); - while (hasNextNode.execute(thisNode, generator)) { - Object next = nextNode.execute(thisNode, generator); - putNode.execute(thisNode, index, next, null); - } + + MaterializedFrame frame = collection.getFrame(); + frame.setObject(collection.getGeneratorSlot(), generator); + frame.setObject(collection.getOffHeapDistinctSlot(), index); + + loopNode.execute(frame); } finally { closeNode.execute(thisNode, generator); } @@ -200,36 +235,51 @@ static Object getGenerator(Node node, EquiJoinCollection collection) { return collection.getGenerator(); } - @Specialization + public static LoopNode getEquiJoinInitLoopNode(GroupByCollection collection) { + return Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRHasNextConditionNode(collection.getGeneratorSlot()), + new OSRCollectionEquiJoinInitBodyNode( + collection.getGeneratorSlot(), + collection.getKeyFunctionSlot(), + collection.getMapSlot()))); + } + + @Specialization(guards = "cachedCollection.hasSameSlots(collection)", limit = "8", unroll = 8) static Object getGenerator( Node node, GroupByCollection collection, @Bind("$node") Node thisNode, + @Cached("collection") GroupByCollection cachedCollection, + @Cached( + value = "getEquiJoinInitLoopNode(cachedCollection)", + inline = false, + allowUncached = true) + LoopNode loopNode, @Cached(inline = false) @Cached.Shared("getGenerator1") IterableNodes.GetGeneratorNode getGeneratorNode, @Cached(inline = false) @Cached.Shared("init") GeneratorNodes.GeneratorInitNode initNode, - @Cached @Cached.Shared("hasNext") GeneratorNodes.GeneratorHasNextNode hasNextNode, - @Cached @Cached.Shared("next") GeneratorNodes.GeneratorNextNode nextNode, @Cached @Cached.Shared("close") GeneratorNodes.GeneratorCloseNode closeNode, - @Cached @Cached.Shared("put") OffHeapNodes.OffHeapGroupByPutNode putNode, @Cached @Cached.Shared("generator") OffHeapNodes.OffHeapGeneratorNode generatorNode, - @Cached @Cached.Shared("functionOne") - FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { + @Cached(value = "getContextValues(thisNode)", dimensions = 1, allowUncached = true) + long[] contextValues) { + MaterializedFrame frame = collection.getFrame(); OffHeapGroupByKey map = new OffHeapGroupByKey( collection.getKeyType(), collection.getRowType(), - collection.getLang(), - collection.getContext(), - new RecordShaper(collection.getLang(), false)); + new RecordShaper(false), + contextValues[0], + (int) contextValues[1], + (int) contextValues[2]); Object inputGenerator = getGeneratorNode.execute(thisNode, collection.getIterable()); try { initNode.execute(thisNode, inputGenerator); - while (hasNextNode.execute(thisNode, inputGenerator)) { - Object v = nextNode.execute(thisNode, inputGenerator); - Object key = functionExecuteOneNode.execute(thisNode, collection.getKeyFun(), v); - putNode.execute(thisNode, map, key, v); - } + frame.setObject(collection.getGeneratorSlot(), inputGenerator); + frame.setObject(collection.getMapSlot(), map); + frame.setObject(collection.getKeyFunctionSlot(), collection.getKeyFun()); + loopNode.execute(collection.getFrame()); } finally { closeNode.execute(thisNode, inputGenerator); } @@ -241,40 +291,50 @@ static Object getGenerator(Node node, JoinCollection collection) { return collection.getGenerator(); } - @Specialization + public static LoopNode getOrderByGenNode(OrderByCollection collection) { + return Truffle.getRuntime() + .createLoopNode( + new OSRGeneratorNode( + new OSRHasNextConditionNode(collection.getGeneratorSlot()), + new OSROrderByGetGeneratorNode( + collection.getGeneratorSlot(), + collection.getCollectionSlot(), + collection.getOffHeapGroupByKeysSlot()))); + } + + @Specialization(guards = "cachedCollection.hasSameSlots(collection)", limit = "8", unroll = 8) static Object getGenerator( Node node, OrderByCollection collection, @Bind("$node") Node thisNode, + @Cached("collection") OrderByCollection cachedCollection, + @Cached(value = "getOrderByGenNode(cachedCollection)", inline = false, allowUncached = true) + LoopNode loopNode, @Cached(inline = false) @Cached.Shared("getGenerator1") IterableNodes.GetGeneratorNode getGeneratorNode, @Cached(inline = false) @Cached.Shared("init") GeneratorNodes.GeneratorInitNode initNode, - @Cached @Cached.Shared("hasNext") GeneratorNodes.GeneratorHasNextNode hasNextNode, - @Cached @Cached.Shared("next") GeneratorNodes.GeneratorNextNode nextNode, @Cached @Cached.Shared("close") GeneratorNodes.GeneratorCloseNode closeNode, - @Cached @Cached.Shared("put") OffHeapNodes.OffHeapGroupByPutNode putNode, @Cached @Cached.Shared("generator") OffHeapNodes.OffHeapGeneratorNode generatorNode, - @Cached @Cached.Shared("functionOne") - FunctionExecuteNodes.FunctionExecuteOne functionExecuteOneNode) { + @Cached(value = "getContextValues(thisNode)", dimensions = 1, allowUncached = true) + long[] contextValues) { Object generator = getGeneratorNode.execute(thisNode, collection.getParentIterable()); OffHeapGroupByKeys groupByKeys = new OffHeapGroupByKeys( collection.getKeyTypes(), collection.getRowType(), collection.getKeyOrderings(), - collection.getLang(), - collection.getContext()); + contextValues[0], + (int) contextValues[1], + (int) contextValues[2]); try { initNode.execute(thisNode, generator); - while (hasNextNode.execute(thisNode, generator)) { - Object v = nextNode.execute(thisNode, generator); - int len = collection.getKeyFunctions().length; - Object[] key = new Object[len]; - for (int i = 0; i < len; i++) { - key[i] = functionExecuteOneNode.execute(thisNode, collection.getKeyFunctions()[i], v); - } - putNode.execute(thisNode, groupByKeys, key, v); - } + + Frame frame = collection.getFrame(); + frame.setObject(collection.getGeneratorSlot(), generator); + frame.setObject(collection.getOffHeapGroupByKeysSlot(), groupByKeys); + frame.setObject(collection.getCollectionSlot(), collection); + + loopNode.execute(collection.getFrame()); } finally { closeNode.execute(thisNode, generator); } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/DistinctCollection.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/DistinctCollection.java index f828befe4..7dd6a7047 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/DistinctCollection.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/DistinctCollection.java @@ -14,32 +14,35 @@ import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; import raw.compiler.rql2.source.Rql2TypeWithProperties; -import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; import raw.runtime.truffle.runtime.iterable.IterableNodes; -import raw.sources.api.SourceContext; @ExportLibrary(InteropLibrary.class) public class DistinctCollection implements TruffleObject { final Object iterable; - - final RawLanguage language; - final Rql2TypeWithProperties rowType; - private final SourceContext context; + private final MaterializedFrame frame; + private final int generatorSlot; + private final int offHeapDistinctSlot; public DistinctCollection( - Object iterable, Rql2TypeWithProperties vType, RawLanguage language, SourceContext context) { + Object iterable, + Rql2TypeWithProperties vType, + MaterializedFrame frame, + int generatorSlot, + int offHeapDistinctSlot) { this.iterable = iterable; - this.language = language; this.rowType = vType; - this.context = context; + this.frame = frame; + this.generatorSlot = generatorSlot; + this.offHeapDistinctSlot = offHeapDistinctSlot; } public Object getIterable() { @@ -50,12 +53,21 @@ public Rql2TypeWithProperties getRowType() { return rowType; } - public SourceContext getContext() { - return context; + public MaterializedFrame getFrame() { + return frame; + } + + public int getGeneratorSlot() { + return generatorSlot; + } + + public int getOffHeapDistinctSlot() { + return offHeapDistinctSlot; } - public RawLanguage getLang() { - return language; + public boolean hasSameSlots(DistinctCollection other) { + return this.generatorSlot == other.generatorSlot + && this.offHeapDistinctSlot == other.offHeapDistinctSlot; } // InteropLibrary: Iterable diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/EquiJoinCollection.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/EquiJoinCollection.java index de871281b..4490d40c2 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/EquiJoinCollection.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/EquiJoinCollection.java @@ -14,18 +14,17 @@ import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; import raw.compiler.rql2.source.Rql2TypeWithProperties; -import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; import raw.runtime.truffle.runtime.generator.collection.abstract_generator.AbstractGenerator; import raw.runtime.truffle.runtime.generator.collection.abstract_generator.compute_next.operations.EquiJoinComputeNext; import raw.runtime.truffle.runtime.iterable.IterableNodes; -import raw.sources.api.SourceContext; @ExportLibrary(InteropLibrary.class) public class EquiJoinCollection implements TruffleObject { @@ -33,8 +32,12 @@ public class EquiJoinCollection implements TruffleObject { final Object leftKeyF, rightKeyF, reshapeFun; final Rql2TypeWithProperties leftRowType, rightRowType; final Rql2TypeWithProperties keyType; - private final RawLanguage language; - private final SourceContext context; + private final MaterializedFrame frame; + private final int computeNextSlot; + private final int shouldContinueSlot; + private final int generatorSlot; + private final int keyFunctionSlot; + private final int mapSlot; public EquiJoinCollection( Object leftIterable, @@ -45,8 +48,12 @@ public EquiJoinCollection( Rql2TypeWithProperties rightRowType, Rql2TypeWithProperties keyType, Object reshapeFun, - RawLanguage language, - SourceContext context) { + MaterializedFrame frame, + int computeNextSlot, + int shouldContinueSlot, + int generatorSlot, + int keyFunctionSlot, + int mapSlot) { this.leftIterable = leftIterable; this.leftKeyF = leftKeyF; this.leftRowType = leftRowType; @@ -55,8 +62,12 @@ public EquiJoinCollection( this.rightRowType = rightRowType; this.keyType = keyType; this.reshapeFun = reshapeFun; - this.language = language; - this.context = context; + this.frame = frame; + this.computeNextSlot = computeNextSlot; + this.shouldContinueSlot = shouldContinueSlot; + this.generatorSlot = generatorSlot; + this.keyFunctionSlot = keyFunctionSlot; + this.mapSlot = mapSlot; } public Object getGenerator() { @@ -70,8 +81,12 @@ public Object getGenerator() { rightRowType, keyType, reshapeFun, - language, - context)); + frame, + computeNextSlot, + shouldContinueSlot, + generatorSlot, + keyFunctionSlot, + mapSlot)); } @ExportMessage diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/FilterCollection.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/FilterCollection.java index c98bf55cf..8de52370c 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/FilterCollection.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/FilterCollection.java @@ -14,6 +14,7 @@ import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.library.ExportLibrary; @@ -26,10 +27,27 @@ public class FilterCollection implements TruffleObject { private final Object parentIterable; private final Object predicate; + private final MaterializedFrame frame; - public FilterCollection(Object iterable, Object predicate) { + private final int generatorSlot; + + private final int functionSlot; + + private final int resultSlot; + + public FilterCollection( + Object iterable, + Object predicate, + MaterializedFrame frame, + int generatorSlot, + int functionSlot, + int resultSlot) { this.parentIterable = iterable; this.predicate = predicate; + this.frame = frame; + this.generatorSlot = generatorSlot; + this.functionSlot = functionSlot; + this.resultSlot = resultSlot; } public Object getParentIterable() { @@ -40,6 +58,22 @@ public Object getPredicate() { return predicate; } + public MaterializedFrame getFrame() { + return frame; + } + + public int getGeneratorSlot() { + return generatorSlot; + } + + public int getFunctionSlot() { + return functionSlot; + } + + public int getResultSlot() { + return resultSlot; + } + // InteropLibrary: Iterable @ExportMessage boolean hasIterator() { diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/GroupByCollection.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/GroupByCollection.java index 8e210c504..102699671 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/GroupByCollection.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/GroupByCollection.java @@ -14,41 +14,44 @@ import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; import raw.compiler.rql2.source.Rql2TypeWithProperties; -import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; import raw.runtime.truffle.runtime.iterable.IterableNodes; -import raw.sources.api.SourceContext; @ExportLibrary(InteropLibrary.class) public class GroupByCollection implements TruffleObject { final Object iterable; final Object keyFun; - - final RawLanguage language; - final Rql2TypeWithProperties keyType; final Rql2TypeWithProperties rowType; - private final SourceContext context; + private final MaterializedFrame frame; + private final int generatorSlot; + private final int keyFunctionSlot; + private final int mapSlot; public GroupByCollection( Object iterable, Object keyFun, Rql2TypeWithProperties kType, Rql2TypeWithProperties rowType, - RawLanguage language, - SourceContext context) { + MaterializedFrame frame, + int generatorSlot, + int keyFunctionSlot, + int mapSlot) { this.iterable = iterable; this.keyFun = keyFun; - this.language = language; this.keyType = kType; this.rowType = rowType; - this.context = context; + this.frame = frame; + this.generatorSlot = generatorSlot; + this.keyFunctionSlot = keyFunctionSlot; + this.mapSlot = mapSlot; } public Object getIterable() { @@ -67,12 +70,26 @@ public Rql2TypeWithProperties getRowType() { return rowType; } - public SourceContext getContext() { - return context; + public MaterializedFrame getFrame() { + return frame; + } + + public int getGeneratorSlot() { + return generatorSlot; + } + + public int getKeyFunctionSlot() { + return keyFunctionSlot; + } + + public int getMapSlot() { + return mapSlot; } - public RawLanguage getLang() { - return language; + public boolean hasSameSlots(GroupByCollection other) { + return this.generatorSlot == other.generatorSlot + && this.keyFunctionSlot == other.keyFunctionSlot + && this.mapSlot == other.mapSlot; } // InteropLibrary: Iterable diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/JoinCollection.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/JoinCollection.java index 121c2d167..bf3d57cba 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/JoinCollection.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/JoinCollection.java @@ -14,18 +14,17 @@ import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; import raw.compiler.rql2.source.Rql2TypeWithProperties; -import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; import raw.runtime.truffle.runtime.generator.collection.abstract_generator.AbstractGenerator; import raw.runtime.truffle.runtime.generator.collection.abstract_generator.compute_next.operations.JoinComputeNext; import raw.runtime.truffle.runtime.iterable.IterableNodes; -import raw.sources.api.SourceContext; @ExportLibrary(InteropLibrary.class) public class JoinCollection implements TruffleObject { @@ -33,10 +32,16 @@ public class JoinCollection implements TruffleObject { final Object rightIterable; final Object predicate, remap; final Rql2TypeWithProperties rightType; - final SourceContext context; - final RawLanguage language; private final Boolean reshapeBeforePredicate; + private final int kryoOutputBufferSize; + private final MaterializedFrame frame; + private final int computeNextSlot; + private final int shouldContinueSlot; + private final int resultSlot; + private final int generatorSlot; + private final int outputBufferSlot; + public JoinCollection( Object leftIterable, Object rightIterable, @@ -44,16 +49,26 @@ public JoinCollection( Object predicate, Rql2TypeWithProperties rightType, Boolean reshapeBeforePredicate, - SourceContext context, - RawLanguage language) { + int kryoOutputBufferSize, + MaterializedFrame frame, + int computeNextSlot, + int shouldContinueSlot, + int resultSlot, + int generatorSlot, + int outputBufferSlot) { this.leftIterable = leftIterable; this.rightIterable = rightIterable; this.remap = remap; this.predicate = predicate; this.rightType = rightType; - this.context = context; - this.language = language; this.reshapeBeforePredicate = reshapeBeforePredicate; + this.frame = frame; + this.computeNextSlot = computeNextSlot; + this.shouldContinueSlot = shouldContinueSlot; + this.resultSlot = resultSlot; + this.generatorSlot = generatorSlot; + this.outputBufferSlot = outputBufferSlot; + this.kryoOutputBufferSize = kryoOutputBufferSize; } public Object getGenerator() { @@ -65,8 +80,13 @@ public Object getGenerator() { predicate, reshapeBeforePredicate, rightType, - context, - language)); + kryoOutputBufferSize, + frame, + computeNextSlot, + shouldContinueSlot, + resultSlot, + generatorSlot, + outputBufferSlot)); } // InteropLibrary: Iterable diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/OrderByCollection.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/OrderByCollection.java index 55f8d1aaf..73ae219cd 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/OrderByCollection.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/OrderByCollection.java @@ -14,27 +14,27 @@ import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; import raw.compiler.rql2.source.Rql2TypeWithProperties; -import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; import raw.runtime.truffle.runtime.iterable.IterableNodes; -import raw.sources.api.SourceContext; @ExportLibrary(InteropLibrary.class) public class OrderByCollection implements TruffleObject { final Object parentIterable; final Object[] keyFunctions; - final int[] keyOrderings; final Rql2TypeWithProperties[] keyTypes; final Rql2TypeWithProperties rowType; - private final RawLanguage language; - private final SourceContext context; + private final MaterializedFrame frame; + private final int generatorSlot; + private final int collectionSlot; + private final int offHeapGroupByKeysSlot; public OrderByCollection( Object iterable, @@ -42,15 +42,19 @@ public OrderByCollection( int[] keyOrderings, Rql2TypeWithProperties[] keyTypes, Rql2TypeWithProperties rowType, - RawLanguage language, - SourceContext context) { + MaterializedFrame frame, + int generatorSlot, + int collectionSlot, + int offHeapGroupByKeysSlot) { this.parentIterable = iterable; this.keyFunctions = keyFunctions; this.keyOrderings = keyOrderings; this.keyTypes = keyTypes; this.rowType = rowType; - this.language = language; - this.context = context; + this.frame = frame; + this.generatorSlot = generatorSlot; + this.collectionSlot = collectionSlot; + this.offHeapGroupByKeysSlot = offHeapGroupByKeysSlot; } public Object getParentIterable() { @@ -73,12 +77,26 @@ public Rql2TypeWithProperties getRowType() { return rowType; } - public SourceContext getContext() { - return context; + public MaterializedFrame getFrame() { + return frame; + } + + public int getGeneratorSlot() { + return generatorSlot; + } + + public int getCollectionSlot() { + return collectionSlot; + } + + public int getOffHeapGroupByKeysSlot() { + return offHeapGroupByKeysSlot; } - public RawLanguage getLang() { - return language; + public boolean hasSameSlots(OrderByCollection other) { + return this.generatorSlot == other.generatorSlot + && this.collectionSlot == other.collectionSlot + && this.offHeapGroupByKeysSlot == other.offHeapGroupByKeysSlot; } // InteropLibrary: Iterable diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/ZipCollection.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/ZipCollection.java index 31db8aaf1..710c51205 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/ZipCollection.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/operations/ZipCollection.java @@ -28,12 +28,9 @@ public class ZipCollection implements TruffleObject { final Object parentIterable1; final Object parentIterable2; - final RawLanguage language; - public ZipCollection(Object iterable1, Object iterable2, RawLanguage language) { this.parentIterable1 = iterable1; this.parentIterable2 = iterable2; - this.language = language; } public Object getParentIterable1() { @@ -44,10 +41,6 @@ public Object getParentIterable2() { return parentIterable2; } - public RawLanguage getLang() { - return language; - } - @ExportMessage boolean hasIterator() { return true; diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/sources/CsvCollection.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/sources/CsvCollection.java index a00ff434c..5c06f8108 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/sources/CsvCollection.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/sources/CsvCollection.java @@ -25,34 +25,28 @@ import raw.runtime.truffle.runtime.generator.collection.abstract_generator.AbstractGenerator; import raw.runtime.truffle.runtime.generator.collection.abstract_generator.compute_next.sources.CsvReadComputeNext; import raw.runtime.truffle.runtime.primitives.LocationObject; -import raw.sources.api.SourceContext; @ExportLibrary(InteropLibrary.class) public class CsvCollection implements TruffleObject { private final LocationObject location; private final RootCallTarget rowParserCallTarget; - - private final SourceContext context; - private final String encoding; private final RawTruffleCsvParserSettings settings; public CsvCollection( LocationObject location, - SourceContext context, RootCallTarget rowParserCallTarget, String encoding, RawTruffleCsvParserSettings settings) { this.location = location; this.rowParserCallTarget = rowParserCallTarget; - this.context = context; this.encoding = encoding; this.settings = settings; } public AbstractGenerator getGenerator() { return new AbstractGenerator( - new CsvReadComputeNext(location, context, rowParserCallTarget, encoding, settings)); + new CsvReadComputeNext(location, rowParserCallTarget, encoding, settings)); } // InteropLibrary: Iterable diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/sources/JsonReadCollection.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/sources/JsonReadCollection.java index aeb7ca097..8411dc678 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/sources/JsonReadCollection.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/sources/JsonReadCollection.java @@ -24,31 +24,24 @@ import raw.runtime.truffle.runtime.generator.collection.abstract_generator.AbstractGenerator; import raw.runtime.truffle.runtime.generator.collection.abstract_generator.compute_next.sources.JsonReadComputeNext; import raw.runtime.truffle.runtime.primitives.LocationObject; -import raw.sources.api.SourceContext; @ExportLibrary(InteropLibrary.class) public class JsonReadCollection implements TruffleObject { private final LocationObject locationObject; private final RootCallTarget parseNextRootCallTarget; - private final SourceContext context; - private final String encoding; public JsonReadCollection( - LocationObject locationObject, - String encoding, - SourceContext context, - RootCallTarget parseNextRootCallTarget) { + LocationObject locationObject, String encoding, RootCallTarget parseNextRootCallTarget) { this.locationObject = locationObject; this.parseNextRootCallTarget = parseNextRootCallTarget; - this.context = context; this.encoding = encoding; } public AbstractGenerator getGenerator() { return new AbstractGenerator( - new JsonReadComputeNext(locationObject, encoding, context, parseNextRootCallTarget)); + new JsonReadComputeNext(locationObject, encoding, parseNextRootCallTarget)); } // InteropLibrary: Iterable diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/sources/XmlParseCollection.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/sources/XmlParseCollection.java index 6edb11a07..2cce0c733 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/sources/XmlParseCollection.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/sources/XmlParseCollection.java @@ -24,7 +24,6 @@ import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; import raw.runtime.truffle.runtime.generator.collection.abstract_generator.AbstractGenerator; import raw.runtime.truffle.runtime.generator.collection.abstract_generator.compute_next.sources.XmlParseComputeNext; -import raw.sources.api.SourceContext; @ExportLibrary(InteropLibrary.class) public class XmlParseCollection implements TruffleObject { @@ -33,10 +32,7 @@ public class XmlParseCollection implements TruffleObject { private final RawTruffleXmlParserSettings settings; public XmlParseCollection( - String text, - SourceContext context, - RootCallTarget parseNextRootCallTarget, - RawTruffleXmlParserSettings settings) { + String text, RootCallTarget parseNextRootCallTarget, RawTruffleXmlParserSettings settings) { this.text = text; this.parseNextRootCallTarget = parseNextRootCallTarget; this.settings = settings; diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/sources/XmlReadCollection.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/sources/XmlReadCollection.java index f34e1efbc..c047a3469 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/sources/XmlReadCollection.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/iterable/sources/XmlReadCollection.java @@ -25,34 +25,28 @@ import raw.runtime.truffle.runtime.generator.collection.abstract_generator.AbstractGenerator; import raw.runtime.truffle.runtime.generator.collection.abstract_generator.compute_next.sources.XmlReadComputeNext; import raw.runtime.truffle.runtime.primitives.LocationObject; -import raw.sources.api.SourceContext; @ExportLibrary(InteropLibrary.class) public class XmlReadCollection implements TruffleObject { private final LocationObject locationObject; private final RootCallTarget parseNextRootCallTarget; private RawTruffleXmlParserSettings settings; - private final SourceContext context; - private final String encoding; public XmlReadCollection( LocationObject locationObject, String encoding, - SourceContext context, RootCallTarget parseNextRootCallTarget, RawTruffleXmlParserSettings settings) { this.locationObject = locationObject; this.parseNextRootCallTarget = parseNextRootCallTarget; this.settings = settings; - this.context = context; this.encoding = encoding; } public AbstractGenerator getGenerator() { return new AbstractGenerator( - new XmlReadComputeNext( - locationObject, encoding, context, parseNextRootCallTarget, settings)); + new XmlReadComputeNext(locationObject, encoding, parseNextRootCallTarget, settings)); } // InteropLibrary: Iterable diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/kryo/KryoNodes.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/kryo/KryoNodes.java index 888ceef9c..791f7dedc 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/kryo/KryoNodes.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/kryo/KryoNodes.java @@ -17,7 +17,7 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.interop.*; -import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import java.math.BigDecimal; @@ -25,19 +25,19 @@ import java.time.LocalDateTime; import java.time.LocalTime; import java.util.ArrayList; +import java.util.List; import java.util.concurrent.TimeUnit; import raw.compiler.rql2.source.*; import raw.runtime.truffle.RawLanguage; import raw.runtime.truffle.ast.TypeGuards; -import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; import raw.runtime.truffle.runtime.iterable.IterableNodes; import raw.runtime.truffle.runtime.list.ListNodes; import raw.runtime.truffle.runtime.list.ObjectList; import raw.runtime.truffle.runtime.primitives.*; -import raw.runtime.truffle.runtime.record.RecordObject; -import raw.runtime.truffle.tryable_nullable.Nullable; -import raw.runtime.truffle.tryable_nullable.Tryable; +import raw.runtime.truffle.runtime.record.RecordNodes; +import raw.runtime.truffle.runtime.record.RecordNodesFactory; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; import scala.collection.immutable.Vector; public class KryoNodes { @@ -47,14 +47,12 @@ public class KryoNodes { @ImportStatic(TypeGuards.class) public abstract static class KryoReadNode extends Node { - public abstract Object execute( - Node node, RawLanguage language, Input input, Rql2TypeWithProperties t); + public abstract Object execute(Node node, Input input, Rql2TypeWithProperties t); @Specialization(guards = {"isTryable(t)"}) @CompilerDirectives.TruffleBoundary static Object doTryable( Node node, - RawLanguage language, Input input, Rql2TypeWithProperties t, @Bind("$node") Node thisNode, @@ -63,7 +61,7 @@ static Object doTryable( if (isSuccess) { Rql2TypeWithProperties successType = (Rql2TypeWithProperties) t.cloneAndRemoveProp(new Rql2IsTryableTypeProperty()); - return kryo.execute(thisNode, language, input, successType); + return kryo.execute(thisNode, input, successType); } else { String error = input.readString(); return new ErrorObject(error); @@ -74,7 +72,6 @@ static Object doTryable( @CompilerDirectives.TruffleBoundary static Object doNullable( Node node, - RawLanguage language, Input input, Rql2TypeWithProperties t, @Bind("$node") Node thisNode, @@ -83,7 +80,7 @@ static Object doNullable( if (isDefined) { Rql2TypeWithProperties innerType = (Rql2TypeWithProperties) t.cloneAndRemoveProp(new Rql2IsNullableTypeProperty()); - return kryo.execute(thisNode, language, input, innerType); + return kryo.execute(thisNode, input, innerType); } else { return NullObject.INSTANCE; } @@ -93,17 +90,16 @@ static Object doNullable( @CompilerDirectives.TruffleBoundary static ObjectList doList( Node node, - RawLanguage language, Input input, Rql2TypeWithProperties t, @Bind("$node") Node thisNode, - @Cached(inline = false) @Cached.Shared("kryoRead") KryoReadNode kryo) { + @Cached(inline = false) @Cached.Exclusive KryoReadNode kryo) { Rql2ListType listType = (Rql2ListType) t; Rql2TypeWithProperties innerType = (Rql2TypeWithProperties) listType.innerType(); int size = input.readInt(); Object[] values = new Object[size]; for (int i = 0; i < size; i++) { - values[i] = kryo.execute(thisNode, language, input, innerType); + values[i] = kryo.execute(thisNode, input, innerType); } return new ObjectList(values); } @@ -112,55 +108,84 @@ static ObjectList doList( @CompilerDirectives.TruffleBoundary static Object doIterable( Node node, - RawLanguage language, Input input, Rql2TypeWithProperties t, @Bind("$node") Node thisNode, - @Cached(inline = false) @Cached.Shared("kryoRead") KryoReadNode kryo) { + @Cached(inline = false) @Cached.Exclusive KryoReadNode kryo) { Rql2IterableType iterableType = (Rql2IterableType) t; Rql2TypeWithProperties innerType = (Rql2TypeWithProperties) iterableType.innerType(); int size = input.readInt(); Object[] values = new Object[size]; for (int i = 0; i < size; i++) { - values[i] = kryo.execute(node, language, input, innerType); + values[i] = kryo.execute(node, input, innerType); } return new ObjectList(values).toIterable(); } + public static RecordNodes.AddPropNode[] createAddProps(int size) { + RecordNodes.AddPropNode[] addProps = new RecordNodes.AddPropNode[size]; + for (int i = 0; i < size; i++) { + addProps[i] = RecordNodesFactory.AddPropNodeGen.create(); + } + return addProps; + } + + public static KryoReadNode[] createKryoRead(int size) { + KryoReadNode[] kryoRead = new KryoReadNode[size]; + for (int i = 0; i < size; i++) { + kryoRead[i] = KryoNodesFactory.KryoReadNodeGen.create(); + } + return kryoRead; + } + + public static boolean hasDuplicateKeys(Rql2RecordType t) { + Vector atts = t.atts(); + List list = new ArrayList<>(); + for (int i = 0; i < atts.size(); i++) { + list.add(atts.apply(i).idn()); + } + return list.size() != list.stream().distinct().count(); + } + + public static RawLanguage getRawLanguage(Node node) { + return RawLanguage.get(node); + } + @Specialization(guards = {"isRecordKind(t)"}) - @CompilerDirectives.TruffleBoundary - static RecordObject doRecord( + @ExplodeLoop + static Object doRecord( Node node, - RawLanguage language, Input input, - Rql2TypeWithProperties t, + Rql2RecordType t, @Bind("$node") Node thisNode, - @Cached(inline = false) @Cached.Shared("kryoRead") KryoReadNode kryo, - @CachedLibrary(limit = "2") InteropLibrary records) { - Rql2RecordType recordType = (Rql2RecordType) t; - RecordObject record = language.createRecord(); - recordType - .atts() - .forall( - att -> { - Rql2TypeWithProperties attType = (Rql2TypeWithProperties) att.tipe(); - Object value = kryo.execute(thisNode, language, input, attType); - try { - records.writeMember(record, att.idn(), value); - } catch (UnsupportedMessageException - | UnknownIdentifierException - | UnsupportedTypeException e) { - throw new RawTruffleInternalErrorException(e); - } - return true; - }); + @Cached(value = "hasDuplicateKeys(t)", allowUncached = true) boolean hasDuplicateKeys, + @Cached(value = "getRawLanguage(thisNode)", allowUncached = true) RawLanguage language, + @Cached(value = "createAddProps(t.atts().size())", allowUncached = true) + RecordNodes.AddPropNode[] addPropNode, + @Cached(value = "addPropNode.length", allowUncached = true) int size, + @Cached(value = "createKryoRead(size)", allowUncached = true) KryoReadNode[] kryo) { + Object record = language.createPureRecord(); + for (int i = 0; i < size; i++) { + Rql2TypeWithProperties attType = getTipe(t, i); + Object value = kryo[i].execute(thisNode, input, attType); + addPropNode[i].execute(thisNode, record, getIdn(t, i), value, hasDuplicateKeys); + } return record; } + @CompilerDirectives.TruffleBoundary + public static Rql2TypeWithProperties getTipe(Rql2RecordType t, int index) { + return (Rql2TypeWithProperties) t.atts().apply(index).tipe(); + } + + @CompilerDirectives.TruffleBoundary + public static String getIdn(Rql2RecordType t, int index) { + return t.atts().apply(index).idn(); + } + @Specialization(guards = {"isIntervalKind(t)"}) @CompilerDirectives.TruffleBoundary - static IntervalObject doInterval( - Node node, RawLanguage language, Input input, Rql2TypeWithProperties t) { + static IntervalObject doInterval(Node node, Input input, Rql2TypeWithProperties t) { int years = input.readInt(); int months = input.readInt(); int weeks = input.readInt(); @@ -174,8 +199,7 @@ static IntervalObject doInterval( @Specialization(guards = {"isTimeKind(t)"}) @CompilerDirectives.TruffleBoundary - static TimeObject doTime( - Node node, RawLanguage language, Input input, Rql2TypeWithProperties t) { + static TimeObject doTime(Node node, Input input, Rql2TypeWithProperties t) { int hours = input.readInt(); int minutes = input.readInt(); int seconds = input.readInt(); @@ -186,8 +210,7 @@ static TimeObject doTime( @Specialization(guards = {"isDateKind(t)"}) @CompilerDirectives.TruffleBoundary - static DateObject doDate( - Node node, RawLanguage language, Input input, Rql2TypeWithProperties t) { + static DateObject doDate(Node node, Input input, Rql2TypeWithProperties t) { int year = input.readInt(); int month = input.readInt(); int day = input.readInt(); @@ -196,8 +219,7 @@ static DateObject doDate( @Specialization(guards = {"isTimestampKind(t)"}) @CompilerDirectives.TruffleBoundary - static TimestampObject doTimestamp( - Node node, RawLanguage language, Input input, Rql2TypeWithProperties t) { + static TimestampObject doTimestamp(Node node, Input input, Rql2TypeWithProperties t) { int year = input.readInt(); int month = input.readInt(); int day = input.readInt(); @@ -218,57 +240,55 @@ static TimestampObject doTimestamp( @Specialization(guards = {"isBooleanKind(t)"}) @CompilerDirectives.TruffleBoundary - static boolean doBoolean( - Node node, RawLanguage language, Input input, Rql2TypeWithProperties t) { + static boolean doBoolean(Node node, Input input, Rql2TypeWithProperties t) { return input.readBoolean(); } @Specialization(guards = {"isStringKind(t)"}) @CompilerDirectives.TruffleBoundary - static String doString(Node node, RawLanguage language, Input input, Rql2TypeWithProperties t) { + static String doString(Node node, Input input, Rql2TypeWithProperties t) { return input.readString(); } @Specialization(guards = {"isDecimalKind(t)"}) @CompilerDirectives.TruffleBoundary - static DecimalObject doDecimal( - Node node, RawLanguage language, Input input, Rql2TypeWithProperties t) { + static DecimalObject doDecimal(Node node, Input input, Rql2TypeWithProperties t) { return new DecimalObject(new BigDecimal(input.readString())); } @Specialization(guards = {"isDoubleKind(t)"}) @CompilerDirectives.TruffleBoundary - static double doDouble(Node node, RawLanguage language, Input input, Rql2TypeWithProperties t) { + static double doDouble(Node node, Input input, Rql2TypeWithProperties t) { return input.readDouble(); } @Specialization(guards = {"isFloatKind(t)"}) @CompilerDirectives.TruffleBoundary - static float doFloat(Node node, RawLanguage language, Input input, Rql2TypeWithProperties t) { + static float doFloat(Node node, Input input, Rql2TypeWithProperties t) { return input.readFloat(); } @Specialization(guards = {"isLongKind(t)"}) @CompilerDirectives.TruffleBoundary - static long doLong(Node node, RawLanguage language, Input input, Rql2TypeWithProperties t) { + static long doLong(Node node, Input input, Rql2TypeWithProperties t) { return input.readLong(); } @Specialization(guards = {"isIntKind(t)"}) @CompilerDirectives.TruffleBoundary - static int doInt(Node node, RawLanguage language, Input input, Rql2TypeWithProperties t) { + static int doInt(Node node, Input input, Rql2TypeWithProperties t) { return input.readInt(); } @Specialization(guards = {"isShortKind(t)"}) @CompilerDirectives.TruffleBoundary - static short doShort(Node node, RawLanguage language, Input input, Rql2TypeWithProperties t) { + static short doShort(Node node, Input input, Rql2TypeWithProperties t) { return input.readShort(); } @Specialization(guards = {"isByteKind(t)"}) @CompilerDirectives.TruffleBoundary - static byte doByte(Node node, RawLanguage language, Input input, Rql2TypeWithProperties t) { + static byte doByte(Node node, Input input, Rql2TypeWithProperties t) { return input.readByte(); } } @@ -286,14 +306,16 @@ public abstract void execute( Node node, Output output, Rql2TypeWithProperties type, Object maybeTryable); @Specialization(guards = "isTryable(type)") + @CompilerDirectives.TruffleBoundary static void doTryable( Node node, Output output, Rql2TypeWithProperties type, Object maybeTryable, @Bind("$node") Node thisNode, + @Cached TryableNullableNodes.IsErrorNode isErrorNode, @Cached(inline = false) @Cached.Exclusive KryoWriteNode kryo) { - boolean isSuccess = Tryable.isSuccess(maybeTryable); + boolean isSuccess = !isErrorNode.execute(thisNode, maybeTryable); output.writeBoolean(isSuccess); if (isSuccess) { kryo.execute( @@ -308,14 +330,16 @@ static void doTryable( } @Specialization(guards = "isNullable(type)") + @CompilerDirectives.TruffleBoundary static void doNullable( Node node, Output output, Rql2TypeWithProperties type, Object maybeOption, @Bind("$node") Node thisNode, + @Cached TryableNullableNodes.IsNullNode isNullNode, @Cached(inline = false) @Cached.Exclusive KryoWriteNode kryo) { - boolean isDefined = Nullable.isNotNull(maybeOption); + boolean isDefined = !isNullNode.execute(thisNode, maybeOption); output.writeBoolean(isDefined); if (isDefined) { kryo.execute( @@ -327,6 +351,7 @@ static void doNullable( } @Specialization(guards = "isListKind(type)") + @CompilerDirectives.TruffleBoundary static void doList( Node node, Output output, @@ -335,7 +360,7 @@ static void doList( @Bind("$node") Node thisNode, @Cached ListNodes.SizeNode sizeNode, @Cached ListNodes.GetNode getNode, - @Cached(inline = false) @Cached.Shared("kryo") KryoWriteNode kryo) { + @Cached(inline = false) @Cached.Exclusive KryoWriteNode kryo) { int size = (int) sizeNode.execute(thisNode, o); output.writeInt(size); Rql2TypeWithProperties elementType = @@ -347,6 +372,7 @@ static void doList( } @Specialization(guards = "isIterableKind(type)") + @CompilerDirectives.TruffleBoundary static void doIterable( Node node, Output output, @@ -357,7 +383,7 @@ static void doIterable( @Cached GeneratorNodes.GeneratorHasNextNode generatorHasNextNode, @Cached GeneratorNodes.GeneratorNextNode generatorNextNode, @Cached GeneratorNodes.GeneratorCloseNode generatorCloseNode, - @Cached(inline = false) @Cached.Shared("kryo") KryoWriteNode kryo, + @Cached(inline = false) @Cached.Exclusive KryoWriteNode kryo, @Cached(inline = false) IterableNodes.GetGeneratorNode getGeneratorNode) { Rql2TypeWithProperties elementType = (Rql2TypeWithProperties) ((Rql2IterableType) type).innerType(); @@ -378,35 +404,50 @@ static void doIterable( } } - @Specialization( - guards = {"isRecordKind(type)"}, - limit = "1") + public static RecordNodes.GetValueNode[] createGetValue(int size) { + RecordNodes.GetValueNode[] getValueNodes = new RecordNodes.GetValueNode[size]; + for (int i = 0; i < size; i++) { + getValueNodes[i] = RecordNodesFactory.GetValueNodeGen.create(); + } + return getValueNodes; + } + + public static KryoWriteNode[] createKryoWrite(int size) { + KryoWriteNode[] kryoWrite = new KryoWriteNode[size]; + for (int i = 0; i < size; i++) { + kryoWrite[i] = KryoNodesFactory.KryoWriteNodeGen.create(); + } + return kryoWrite; + } + + @Specialization(guards = {"isRecordKind(type)"}) + @ExplodeLoop static void doRecord( Node node, Output output, Rql2RecordType type, Object o, @Bind("$node") Node thisNode, - @Cached(inline = false) @Cached.Shared("kryo") KryoWriteNode kryo, - @CachedLibrary("o") InteropLibrary recordLibrary, - @CachedLibrary(limit = "2") InteropLibrary arrayLibrary) { - try { - Object keys = recordLibrary.getMembers(o); - long length = arrayLibrary.getArraySize(keys); - Vector atts = type.atts(); - for (int i = 0; i < length; i++) { - String member = (String) arrayLibrary.readArrayElement(keys, i); - Object field = recordLibrary.readMember(o, member); - kryo.execute(thisNode, output, (Rql2TypeWithProperties) atts.apply(i).tipe(), field); - } - } catch (UnsupportedMessageException - | InvalidArrayIndexException - | UnknownIdentifierException e) { - throw new RawTruffleInternalErrorException(e); + @Cached RecordNodes.GetKeysNode getKeysNode, + @Cached(value = "getKeysNode.execute(thisNode, o)", dimensions = 1, allowUncached = true) + Object[] keys, + @Cached("keys.length") int size, + @Cached(value = "createKryoWrite(size)", allowUncached = true) KryoWriteNode[] kryo, + @Cached(value = "createGetValue(size)", allowUncached = true) + RecordNodes.GetValueNode[] getValueNode) { + for (int i = 0; i < size; i++) { + Object field = getValueNode[i].execute(thisNode, o, keys[i]); + kryo[i].execute(thisNode, output, getTipe(type, i), field); } } + @CompilerDirectives.TruffleBoundary + public static Rql2TypeWithProperties getTipe(Rql2RecordType t, int index) { + return (Rql2TypeWithProperties) t.atts().apply(index).tipe(); + } + @Specialization(guards = {"isDateKind(type)"}) + @CompilerDirectives.TruffleBoundary static void doDate(Node node, Output output, Rql2TypeWithProperties type, DateObject o) { LocalDate date = o.getDate(); output.writeInt(date.getYear()); @@ -415,6 +456,7 @@ static void doDate(Node node, Output output, Rql2TypeWithProperties type, DateOb } @Specialization(guards = {"isTimeKind(type)"}) + @CompilerDirectives.TruffleBoundary static void doTime(Node node, Output output, Rql2TypeWithProperties type, TimeObject o) { LocalTime time = o.getTime(); output.writeInt(time.getHour()); @@ -424,6 +466,7 @@ static void doTime(Node node, Output output, Rql2TypeWithProperties type, TimeOb } @Specialization(guards = {"isTimestampKind(type)"}) + @CompilerDirectives.TruffleBoundary static void doTimestamp( Node node, Output output, Rql2TypeWithProperties type, TimestampObject o) { LocalDateTime timestamp = o.getTimestamp(); @@ -437,6 +480,7 @@ static void doTimestamp( } @Specialization(guards = {"isIntervalKind(type)"}) + @CompilerDirectives.TruffleBoundary static void doInterval( Node node, Output output, Rql2TypeWithProperties type, IntervalObject o) { output.writeInt(o.getYears()); @@ -450,46 +494,55 @@ static void doInterval( } @Specialization(guards = {"isByteKind(type)"}) + @CompilerDirectives.TruffleBoundary static void doByte(Node node, Output output, Rql2TypeWithProperties type, byte o) { output.writeByte(o); } @Specialization(guards = {"isShortKind(type)"}) + @CompilerDirectives.TruffleBoundary static void doShort(Node node, Output output, Rql2TypeWithProperties type, short o) { output.writeShort(o); } @Specialization(guards = {"isIntKind(type)"}) + @CompilerDirectives.TruffleBoundary static void doInt(Node node, Output output, Rql2TypeWithProperties type, int o) { output.writeInt(o); } @Specialization(guards = {"isLongKind(type)"}) + @CompilerDirectives.TruffleBoundary static void doLong(Node node, Output output, Rql2TypeWithProperties type, long o) { output.writeLong(o); } @Specialization(guards = {"isFloatKind(type)"}) + @CompilerDirectives.TruffleBoundary static void doFloat(Node node, Output output, Rql2TypeWithProperties type, float o) { output.writeFloat(o); } @Specialization + @CompilerDirectives.TruffleBoundary static void doDouble(Node node, Output output, Rql2TypeWithProperties type, double o) { output.writeDouble(o); } @Specialization + @CompilerDirectives.TruffleBoundary static void doDecimal(Node node, Output output, Rql2TypeWithProperties type, DecimalObject o) { output.writeString(o.getBigDecimal().toString()); } @Specialization + @CompilerDirectives.TruffleBoundary static void doString(Node node, Output output, Rql2TypeWithProperties type, String o) { output.writeString(o); } @Specialization + @CompilerDirectives.TruffleBoundary static void doBool(Node node, Output output, Rql2TypeWithProperties type, boolean o) { output.writeBoolean(o); } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/operators/OperatorNodes.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/operators/OperatorNodes.java index 9a343b35d..be727d75a 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/operators/OperatorNodes.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/operators/OperatorNodes.java @@ -14,25 +14,22 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.InvalidArrayIndexException; -import com.oracle.truffle.api.interop.UnknownIdentifierException; -import com.oracle.truffle.api.interop.UnsupportedMessageException; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import raw.runtime.truffle.ast.expressions.builtin.temporals.interval_package.IntervalNodes; -import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; import raw.runtime.truffle.runtime.generator.collection.GeneratorNodes; import raw.runtime.truffle.runtime.iterable.IterableNodes; import raw.runtime.truffle.runtime.primitives.*; -import raw.runtime.truffle.runtime.record.RecordObject; +import raw.runtime.truffle.runtime.record.DuplicateKeyRecord; +import raw.runtime.truffle.runtime.record.PureRecord; +import raw.runtime.truffle.runtime.record.RecordNodes; import raw.runtime.truffle.tryable_nullable.Nullable; import raw.runtime.truffle.tryable_nullable.Tryable; +import raw.runtime.truffle.tryable_nullable.TryableNullableNodes; public class OperatorNodes { @@ -190,54 +187,85 @@ static int doInterval( return compareNode.execute(thisNode, left, right); } - @Specialization(limit = "3") + @Specialization static int doRecord( Node node, - RecordObject left, - RecordObject right, + PureRecord left, + PureRecord right, @Bind("$node") Node thisNode, @Cached(inline = false) @Cached.Shared("compare") CompareNode compare, - @CachedLibrary("left") InteropLibrary lefts, - @CachedLibrary(limit = "3") InteropLibrary arrays, - @CachedLibrary("right") InteropLibrary rights) { - try { - Object leftKeys = lefts.getMembers(left); - long leftSize = arrays.getArraySize(leftKeys); - Object rightKeys = rights.getMembers(right); - long rightSize = arrays.getArraySize(rightKeys); - if (leftSize > rightSize) { - return 1; - } else if (leftSize < rightSize) { - return -1; + @Cached @Cached.Shared("getKey") RecordNodes.GetKeysNode getKeysNode, + @Cached @Cached.Shared("getValue") RecordNodes.GetValueNode getValueNode) { + Object[] leftKeys = getKeysNode.execute(thisNode, left); + Object[] rightKeys = getKeysNode.execute(thisNode, right); + if (leftKeys.length > rightKeys.length) { + return 1; + } else if (leftKeys.length < rightKeys.length) { + return -1; + } + for (int i = 0; i < leftKeys.length; i++) { + String leftKey = (String) leftKeys[i]; + String rightKey = (String) rightKeys[i]; + int result = compare.execute(thisNode, leftKey, rightKey); + if (result != 0) { + return result; } - for (int i = 0; i < leftSize; i++) { - String leftKey = (String) arrays.readArrayElement(leftKeys, i); - String rightKey = (String) arrays.readArrayElement(rightKeys, i); - int result = compare.execute(thisNode, leftKey, rightKey); - if (result != 0) { - return result; - } - Object leftValue = lefts.readMember(left, leftKey); - Object rightValue = rights.readMember(right, rightKey); - result = compare.execute(thisNode, leftValue, rightValue); - if (result != 0) { - return result; - } + Object leftValue = getValueNode.execute(thisNode, left, leftKey); + Object rightValue = getValueNode.execute(thisNode, right, rightKey); + result = compare.execute(thisNode, leftValue, rightValue); + if (result != 0) { + return result; } - return 0; - } catch (InvalidArrayIndexException - | UnsupportedMessageException - | UnknownIdentifierException e) { - throw new RawTruffleInternalErrorException(e); } + return 0; } - @Specialization(guards = {"isFailure(left) || isFailure(right)"}) - static int doTryable(Node node, Object left, Object right) { - boolean leftIsFailure = Tryable.isFailure(left); - boolean rightIsFailure = Tryable.isFailure(right); + @Specialization + static int doRecord( + Node node, + DuplicateKeyRecord left, + DuplicateKeyRecord right, + @Bind("$node") Node thisNode, + @Cached(inline = false) @Cached.Shared("compare") CompareNode compare, + @Cached @Cached.Shared("getKey") RecordNodes.GetKeysNode getKeysNode, + @Cached @Cached.Shared("getValue") RecordNodes.GetValueNode getValueNode) { + Object[] leftKeys = getKeysNode.execute(thisNode, left); + Object[] rightKeys = getKeysNode.execute(thisNode, right); + if (leftKeys.length > rightKeys.length) { + return 1; + } else if (leftKeys.length < rightKeys.length) { + return -1; + } + for (int i = 0; i < leftKeys.length; i++) { + String leftKey = (String) leftKeys[i]; + String rightKey = (String) rightKeys[i]; + int result = compare.execute(thisNode, leftKey, rightKey); + if (result != 0) { + return result; + } + Object leftValue = getValueNode.execute(thisNode, left, leftKey); + Object rightValue = getValueNode.execute(thisNode, right, rightKey); + result = compare.execute(thisNode, leftValue, rightValue); + if (result != 0) { + return result; + } + } + return 0; + } + + @Specialization(guards = {"isError(left) || isError(right)"}) + static int doTryable( + Node node, + Object left, + Object right, + @Bind("$node") Node thisNode, + @Cached TryableNullableNodes.GetErrorNode getErrorNode) { + boolean leftIsFailure = Tryable.isError(left); + boolean rightIsFailure = Tryable.isError(right); if (leftIsFailure && rightIsFailure) { - return Tryable.getFailure(left).compareTo(Tryable.getFailure(right)); + return getErrorNode + .execute(thisNode, left) + .compareTo(getErrorNode.execute(thisNode, right)); } if (leftIsFailure) { return -1; @@ -365,12 +393,17 @@ static Object doNullableTryable(Node node, Object left, Object right) { } } - @Specialization(guards = {"isFailure(left) || isFailure(right)"}) - static Object doTryable(Node node, Object left, Object right) { - if (Tryable.isFailure(left)) { - throw new RawTruffleRuntimeException(Tryable.getFailure(left)); + @Specialization(guards = {"isError(left) || isError(right)"}) + static Object doTryable( + Node node, + Object left, + Object right, + @Bind("$node") Node thisNode, + @Cached TryableNullableNodes.GetErrorNode getErrorNode) { + if (Tryable.isError(left)) { + throw new RawTruffleRuntimeException(getErrorNode.execute(thisNode, left)); } else { - throw new RawTruffleRuntimeException(Tryable.getFailure(right)); + throw new RawTruffleRuntimeException(getErrorNode.execute(thisNode, right)); } } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/RecordObject.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/DuplicateKeyRecord.java similarity index 51% rename from snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/RecordObject.java rename to snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/DuplicateKeyRecord.java index cf86a8ab5..d3373cc03 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/RecordObject.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/DuplicateKeyRecord.java @@ -12,47 +12,80 @@ package raw.runtime.truffle.runtime.record; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.interop.*; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.DynamicObject; -import com.oracle.truffle.api.object.DynamicObjectLibrary; import com.oracle.truffle.api.object.Shape; -import java.util.*; +import java.util.Arrays; +import java.util.Vector; import raw.runtime.truffle.RawLanguage; import raw.utils.RecordFieldsNaming; @ExportLibrary(InteropLibrary.class) -public final class RecordObject implements TruffleObject { +public class DuplicateKeyRecord extends DynamicObject implements TruffleObject { + private final Vector keys = new Vector<>(); + private final Vector cachedDistinctKeys = new Vector<>(); + private boolean distinctValid = false; + + public DuplicateKeyRecord(Shape shape) { + super(shape); + updateDistinctKeys(); + } + + @CompilerDirectives.TruffleBoundary + private void updateDistinctKeys() { + cachedDistinctKeys.clear(); + Vector ks = new Vector<>(); + for (Object key : keys) { + ks.add((String) key); + } + cachedDistinctKeys.addAll(RecordFieldsNaming.makeDistinct(ks)); + distinctValid = true; + } + + public Object[] getDistinctKeys() { + if (!distinctValid) { + updateDistinctKeys(); + } + return cachedDistinctKeys.toArray(); + } + + public boolean keyExist(Object key) { + return keys.contains(key); + } + + public int getKeySize() { + return keys.size(); + } - public final Vector keys = new Vector<>(); - private final Vector distinctKeys; - private boolean validDistinctKeys = true; - public final DynamicObject values; + @CompilerDirectives.TruffleBoundary + public void addKey(Object key) { + keys.add(key); + distinctValid = false; + } - public RecordObject(Shape shape) { - this.values = new RecordStorageObject(shape); - this.distinctKeys = new Vector<>(); + public void removeKey(int index) { + keys.remove(index); + distinctValid = false; } - private Vector getDistinctKeys() { - if (!validDistinctKeys) { - refreshDistinctKeys(); - validDistinctKeys = true; + public int getKeyIndex(Object key) { + if (!distinctValid) { + updateDistinctKeys(); } - return distinctKeys; + return cachedDistinctKeys.indexOf(key); } - @TruffleBoundary - public void refreshDistinctKeys() { - distinctKeys.clear(); - distinctKeys.addAll(RecordFieldsNaming.makeDistinct(keys)); + public Object[] getKeys() { + return keys.toArray(); } @ExportMessage @@ -75,54 +108,16 @@ boolean hasMembers() { return true; } - public String[] keys() { - // Non-interop API. Return possibly duplicate keys. - return keys.toArray(new String[0]); - } - @ExportMessage Object getMembers(@SuppressWarnings("unused") boolean includeInternal) { // This is the interop API, we return distinct keys. - return new Keys(getDistinctKeys().toArray()); - } - - @ExportLibrary(InteropLibrary.class) - static final class Keys implements TruffleObject { - - private final Object[] keys; - - Keys(Object[] keys) { - this.keys = keys; - } - - @ExportMessage - Object readArrayElement(long index) throws InvalidArrayIndexException { - if (!isArrayElementReadable(index)) { - throw InvalidArrayIndexException.create(index); - } - return keys[(int) index]; - } - - @ExportMessage - boolean hasArrayElements() { - return true; - } - - @ExportMessage - long getArraySize() { - return keys.length; - } - - @ExportMessage - boolean isArrayElementReadable(long index) { - return index >= 0 && index < keys.length; - } + return new KeysObject(getDistinctKeys()); } @ExportMessage(name = "isMemberReadable") @ExportMessage(name = "isMemberModifiable") boolean existsMember(String member) { - return getDistinctKeys().contains(member); + return Arrays.asList(getDistinctKeys()).contains(member); } @ExportMessage @@ -136,16 +131,12 @@ boolean isMemberRemovable(String member, @CachedLibrary("this") InteropLibrary r } @ExportMessage - Object readMember(String name, @CachedLibrary("this.values") DynamicObjectLibrary valuesLibrary) - throws UnknownIdentifierException { + Object readMember( + String name, + @Cached(inline = true) DuplicateKeyRecordNodes.GetValueNode getValueNode, + @Bind("$node") Node thisNode) { // Interop API, we assume the searched key should be found in the distinct keys. - int idx = getDistinctKeys().indexOf(name); - Object result = valuesLibrary.getOrDefault(values, idx, null); - if (result == null) { - /* Property does not exist. */ - throw UnknownIdentifierException.create(name); - } - return result; + return getValueNode.execute(thisNode, this, name); } // adds a value by key only (auto-increment the index) @@ -161,16 +152,16 @@ public void writeMember( String name, Object value, @Bind("$node") Node thisNode, - @Cached(inline = true) RecordNodes.AddByKeyNode addByKey) { - addByKey.execute(thisNode, this, name, value); + @Cached(inline = true) DuplicateKeyRecordNodes.AddPropNode addPropNode) { + // this returns a value but we don't use it (we are immutable) + addPropNode.execute(thisNode, this, name, value); } @ExportMessage - void removeMember(String name, @CachedLibrary("this.values") DynamicObjectLibrary valuesLibrary) { - valuesLibrary.removeKey(values, name); - } - - void invalidateDistinctKeys() { - validDistinctKeys = false; + void removeMember( + String name, + @Bind("$node") Node thisNode, + @Cached(inline = true) RecordNodes.RemovePropNode removePropNode) { + removePropNode.execute(thisNode, this, name); } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/DuplicateKeyRecordNodes.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/DuplicateKeyRecordNodes.java new file mode 100644 index 000000000..ae558466b --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/DuplicateKeyRecordNodes.java @@ -0,0 +1,289 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.runtime.record; + +import static raw.runtime.truffle.PropertyType.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.NodeInfo; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import com.oracle.truffle.api.object.DynamicObjectLibrary; +import raw.runtime.truffle.PropertyType; +import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; + +// (az) Whenever using any of these nodes, create one per property +public class DuplicateKeyRecordNodes { + @NodeInfo(shortName = "DuplicateKeyRecord.AddPropNode") + @GenerateUncached + @GenerateInline + @ImportStatic(PropertyType.class) + public abstract static class AddPropNode extends Node { + + public abstract DuplicateKeyRecord execute(Node node, Object record, Object key, Object value); + + @Specialization(limit = "3") + static DuplicateKeyRecord exec( + Node node, + DuplicateKeyRecord duplicateKeyRecord, + Object key, + byte item, + @CachedLibrary("duplicateKeyRecord") DynamicObjectLibrary valuesLibrary) { + int keysSize = duplicateKeyRecord.getKeySize(); + valuesLibrary.putInt(duplicateKeyRecord, keysSize, item); + valuesLibrary.setPropertyFlags(duplicateKeyRecord, keysSize, BYTE_TYPE); + duplicateKeyRecord.addKey(key); + return duplicateKeyRecord; + } + + @Specialization(limit = "3") + static DuplicateKeyRecord exec( + Node node, + DuplicateKeyRecord duplicateKeyRecord, + Object key, + short item, + @CachedLibrary("duplicateKeyRecord") DynamicObjectLibrary valuesLibrary) { + int keysSize = duplicateKeyRecord.getKeySize(); + valuesLibrary.putInt(duplicateKeyRecord, keysSize, item); + valuesLibrary.setPropertyFlags(duplicateKeyRecord, keysSize, SHORT_TYPE); + duplicateKeyRecord.addKey(key); + return duplicateKeyRecord; + } + + @Specialization(limit = "3") + static DuplicateKeyRecord exec( + Node node, + DuplicateKeyRecord duplicateKeyRecord, + Object key, + int item, + @CachedLibrary("duplicateKeyRecord") DynamicObjectLibrary valuesLibrary) { + int keysSize = duplicateKeyRecord.getKeySize(); + valuesLibrary.putInt(duplicateKeyRecord, keysSize, item); + valuesLibrary.setPropertyFlags(duplicateKeyRecord, keysSize, INT_TYPE); + duplicateKeyRecord.addKey(key); + return duplicateKeyRecord; + } + + @Specialization(limit = "3") + static DuplicateKeyRecord exec( + Node node, + DuplicateKeyRecord duplicateKeyRecord, + Object key, + long item, + @CachedLibrary("duplicateKeyRecord") DynamicObjectLibrary valuesLibrary) { + int keysSize = duplicateKeyRecord.getKeySize(); + valuesLibrary.putLong(duplicateKeyRecord, keysSize, item); + valuesLibrary.setPropertyFlags(duplicateKeyRecord, keysSize, LONG_TYPE); + duplicateKeyRecord.addKey(key); + return duplicateKeyRecord; + } + + @Specialization(limit = "3") + static DuplicateKeyRecord exec( + Node node, + DuplicateKeyRecord duplicateKeyRecord, + Object key, + double item, + @CachedLibrary("duplicateKeyRecord") DynamicObjectLibrary valuesLibrary) { + int keysSize = duplicateKeyRecord.getKeySize(); + valuesLibrary.putDouble(duplicateKeyRecord, keysSize, item); + valuesLibrary.setPropertyFlags(duplicateKeyRecord, keysSize, DOUBLE_TYPE); + duplicateKeyRecord.addKey(key); + return duplicateKeyRecord; + } + + @Specialization(limit = "3") + static DuplicateKeyRecord exec( + Node node, + DuplicateKeyRecord duplicateKeyRecord, + Object key, + Object item, + @CachedLibrary("duplicateKeyRecord") DynamicObjectLibrary valuesLibrary) { + int keysSize = duplicateKeyRecord.getKeySize(); + valuesLibrary.putWithFlags(duplicateKeyRecord, keysSize, item, OBJECT_TYPE); + duplicateKeyRecord.addKey(key); + return duplicateKeyRecord; + } + } + + @NodeInfo(shortName = "DuplicateKeyRecord.Exist") + @GenerateUncached + @GenerateInline + @ImportStatic(PropertyType.class) + public abstract static class ExistNode extends Node { + + public abstract boolean execute(Node node, DuplicateKeyRecord duplicateKeyRecord, Object key); + + @Specialization + static boolean exec(Node node, DuplicateKeyRecord duplicateKeyRecord, Object key) { + return duplicateKeyRecord.keyExist(key); + } + } + + @NodeInfo(shortName = "DuplicateKeyRecord.RemoveProp") + @GenerateUncached + @GenerateInline + @ImportStatic(PropertyType.class) + public abstract static class RemovePropNode extends Node { + + public abstract Object execute(Node node, DuplicateKeyRecord duplicateKeyRecord, Object key); + + @Specialization(limit = "3") + static DuplicateKeyRecord exec( + Node node, + DuplicateKeyRecord duplicateKeyRecord, + Object key, + @CachedLibrary("duplicateKeyRecord") DynamicObjectLibrary valuesLibrary) { + int keyIndex = duplicateKeyRecord.getKeyIndex(key); + valuesLibrary.removeKey(duplicateKeyRecord, keyIndex); + duplicateKeyRecord.removeKey(keyIndex); + return duplicateKeyRecord; + } + } + + @NodeInfo(shortName = "DuplicateKeyRecord.GetKeys") + @GenerateUncached + @GenerateInline + @ImportStatic(PropertyType.class) + public abstract static class GetKeysNode extends Node { + + public abstract Object[] execute(Node node, DuplicateKeyRecord record); + + @Specialization + static Object[] exec(Node node, DuplicateKeyRecord record) { + return record.getDistinctKeys(); + } + } + + @NodeInfo(shortName = "DuplicateKeyRecord.GetValue") + @GenerateUncached + @GenerateInline + @ImportStatic(PropertyType.class) + public abstract static class GetValueNode extends Node { + + public abstract Object execute(Node node, DuplicateKeyRecord record, Object key); + + @Specialization( + limit = "3", + guards = "isByte(valuesLibrary.getPropertyFlagsOrDefault(duplicateKeyRecord, key, 7))") + static byte getByte( + Node node, + DuplicateKeyRecord duplicateKeyRecord, + Object key, + @CachedLibrary("duplicateKeyRecord") DynamicObjectLibrary valuesLibrary) { + try { + int idx = duplicateKeyRecord.getKeyIndex(key); + return (byte) valuesLibrary.getIntOrDefault(duplicateKeyRecord, idx, -1); + } catch (UnexpectedResultException e) { + throw new RawTruffleInternalErrorException("Unexpected result", e); + } + } + + @Specialization( + limit = "3", + guards = "isShort(valuesLibrary.getPropertyFlagsOrDefault(duplicateKeyRecord, key, 7))") + static short getShort( + Node node, + DuplicateKeyRecord duplicateKeyRecord, + Object key, + @CachedLibrary("duplicateKeyRecord") DynamicObjectLibrary valuesLibrary) { + try { + int idx = duplicateKeyRecord.getKeyIndex(key); + return (short) valuesLibrary.getIntOrDefault(duplicateKeyRecord, idx, -1); + } catch (UnexpectedResultException e) { + throw new RawTruffleInternalErrorException("Unexpected result", e); + } + } + + @Specialization( + limit = "3", + guards = "isInt(valuesLibrary.getPropertyFlagsOrDefault(duplicateKeyRecord, key, 7))") + static int getInt( + Node node, + DuplicateKeyRecord duplicateKeyRecord, + Object key, + @CachedLibrary("duplicateKeyRecord") DynamicObjectLibrary valuesLibrary) { + try { + int idx = duplicateKeyRecord.getKeyIndex(key); + return valuesLibrary.getIntOrDefault(duplicateKeyRecord, idx, -1); + } catch (UnexpectedResultException e) { + throw new RawTruffleInternalErrorException("Unexpected result", e); + } + } + + @Specialization( + limit = "3", + guards = "isLong(valuesLibrary.getPropertyFlagsOrDefault(duplicateKeyRecord, key, 7))") + static long getLong( + Node node, + DuplicateKeyRecord duplicateKeyRecord, + Object key, + @CachedLibrary("duplicateKeyRecord") DynamicObjectLibrary valuesLibrary) { + try { + int idx = duplicateKeyRecord.getKeyIndex(key); + return valuesLibrary.getLongOrDefault(duplicateKeyRecord, idx, -1); + } catch (UnexpectedResultException e) { + throw new RawTruffleInternalErrorException("Unexpected result", e); + } + } + + @Specialization( + limit = "3", + guards = "isDouble(valuesLibrary.getPropertyFlagsOrDefault(duplicateKeyRecord, key, 7))") + static double getDouble( + Node node, + DuplicateKeyRecord duplicateKeyRecord, + Object key, + @CachedLibrary("duplicateKeyRecord") DynamicObjectLibrary valuesLibrary) { + try { + int idx = duplicateKeyRecord.getKeyIndex(key); + return valuesLibrary.getDoubleOrDefault(duplicateKeyRecord, idx, -1); + } catch (UnexpectedResultException e) { + throw new RawTruffleInternalErrorException("Unexpected result", e); + } + } + + @Specialization(limit = "3") + static Object getObject( + Node node, + DuplicateKeyRecord duplicateKeyRecord, + Object key, + @CachedLibrary("duplicateKeyRecord") DynamicObjectLibrary valuesLibrary) { + int idx = duplicateKeyRecord.getKeyIndex(key); + return valuesLibrary.getOrDefault(duplicateKeyRecord, idx, null); + } + } + + @NodeInfo(shortName = "DuplicateKeyRecord.GetValueByIndex") + @GenerateUncached + @GenerateInline + @ImportStatic(PropertyType.class) + public abstract static class GetValueByIndexNode extends Node { + public abstract Object execute(Node node, DuplicateKeyRecord record, int index); + + @Specialization(limit = "3") + static Object exec( + Node node, + DuplicateKeyRecord record, + int index, + @Bind("$node") Node thisNode, + @CachedLibrary("record") DynamicObjectLibrary valuesLibrary) { + Object[] keys = valuesLibrary.getKeyArray(record); + if (index < 0 || index >= keys.length) { + throw new RawTruffleInternalErrorException("Index out of bounds in record"); + } + return valuesLibrary.getOrDefault(record, index, null); + } + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/KeysObject.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/KeysObject.java new file mode 100644 index 000000000..b2800d539 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/KeysObject.java @@ -0,0 +1,52 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.runtime.record; + +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.InvalidArrayIndexException; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.ExportLibrary; +import com.oracle.truffle.api.library.ExportMessage; + +@ExportLibrary(InteropLibrary.class) +final class KeysObject implements TruffleObject { + + private final Object[] keys; + + KeysObject(Object[] keys) { + this.keys = keys; + } + + @ExportMessage + Object readArrayElement(long index) throws InvalidArrayIndexException { + if (!isArrayElementReadable(index)) { + throw InvalidArrayIndexException.create(index); + } + return keys[(int) index]; + } + + @ExportMessage + boolean hasArrayElements() { + return true; + } + + @ExportMessage + long getArraySize() { + return keys.length; + } + + @ExportMessage + boolean isArrayElementReadable(long index) { + return index >= 0 && index < keys.length; + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/PureRecord.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/PureRecord.java new file mode 100644 index 000000000..4acaee108 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/PureRecord.java @@ -0,0 +1,115 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.runtime.record; + +import com.oracle.truffle.api.TruffleLanguage; +import com.oracle.truffle.api.dsl.Bind; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.interop.*; +import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.library.ExportLibrary; +import com.oracle.truffle.api.library.ExportMessage; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.object.DynamicObject; +import com.oracle.truffle.api.object.Shape; +import raw.runtime.truffle.RawLanguage; + +@ExportLibrary(InteropLibrary.class) +public class PureRecord extends DynamicObject implements TruffleObject { + public PureRecord(Shape shape) { + super(shape); + } + + @ExportMessage + boolean hasLanguage() { + return true; + } + + @ExportMessage + Class> getLanguage() { + return RawLanguage.class; + } + + @ExportMessage + Object toDisplayString(@SuppressWarnings("unused") boolean allowSideEffects) { + return "Record"; + } + + @ExportMessage + boolean hasMembers() { + return true; + } + + @ExportMessage + Object getMembers( + @SuppressWarnings("unused") boolean includeInternal, + @Cached(inline = true) PureRecordNodes.GetKeysNode getKeysNode, + @Bind("$node") Node thisNode) { + Object[] keys = getKeysNode.execute(thisNode, this); + return new KeysObject(keys); + } + + @ExportMessage(name = "isMemberReadable") + @ExportMessage(name = "isMemberModifiable") + boolean existsMember( + String member, + @Cached(inline = true) @Cached.Shared("exists") PureRecordNodes.ExistNode existsNode, + @Bind("$node") Node thisNode) { + return existsNode.execute(thisNode, this, member); + } + + @ExportMessage + boolean isMemberInsertable(String member, @CachedLibrary("this") InteropLibrary receivers) { + return false; + } + + @ExportMessage + boolean isMemberRemovable(String member, @CachedLibrary("this") InteropLibrary receivers) { + return receivers.isMemberModifiable(this, member); + } + + @ExportMessage + Object readMember( + String name, + @Cached(inline = true) PureRecordNodes.GetValueNode getValueNode, + @Bind("$node") Node thisNode) { + // Interop API, we assume the searched key should be found in the distinct keys. + return getValueNode.execute(thisNode, this, name); + } + + // adds a value by key only (auto-increment the index) + // TODO replace all internal calls to writeMember by calls to addByKey + // public void addByKey(String key, Object value) { + // valuesLibrary.put( + // values, keys.size(), value); // "key" to use in the dynamic object is the current index. + // keys.add(key); // the original key is added (possible duplicate) + // } + + @ExportMessage + public void writeMember( + String name, + Object value, + @Bind("$node") Node thisNode, + @Cached(inline = true) PureRecordNodes.AddPropNode addPropNode) { + // this returns a value but we don't use it (we are immutable) + addPropNode.execute(thisNode, this, name, value); + } + + @ExportMessage + void removeMember( + String name, + @Bind("$node") Node thisNode, + @Cached(inline = true) PureRecordNodes.RemovePropNode removePropNode) { + removePropNode.execute(thisNode, this, name); + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/PureRecordNodes.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/PureRecordNodes.java new file mode 100644 index 000000000..df0d796a7 --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/PureRecordNodes.java @@ -0,0 +1,304 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.runtime.record; + +import static raw.runtime.truffle.PropertyType.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.NodeInfo; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import com.oracle.truffle.api.object.DynamicObjectLibrary; +import raw.runtime.truffle.PropertyType; +import raw.runtime.truffle.RawLanguage; +import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; + +// (az) Whenever using any of these nodes, create one per property +public class PureRecordNodes { + @NodeInfo(shortName = "PureRecord.AddPropNode") + @GenerateUncached + @GenerateInline + @ImportStatic(PropertyType.class) + public abstract static class AddPropNode extends Node { + + public abstract void execute(Node node, PureRecord record, Object key, Object value); + + @Specialization(limit = "3") + static void exec( + Node node, + PureRecord pureRecord, + Object key, + byte item, + @CachedLibrary("pureRecord") DynamicObjectLibrary valuesLibrary) { + valuesLibrary.putInt(pureRecord, key, item); + valuesLibrary.setPropertyFlags(pureRecord, key, BYTE_TYPE); + } + + @Specialization(limit = "3") + static void exec( + Node node, + PureRecord pureRecord, + Object key, + short item, + @CachedLibrary("pureRecord") DynamicObjectLibrary valuesLibrary) { + valuesLibrary.putInt(pureRecord, key, item); + valuesLibrary.setPropertyFlags(pureRecord, key, SHORT_TYPE); + } + + @Specialization(limit = "3") + static void exec( + Node node, + PureRecord pureRecord, + Object key, + int item, + @CachedLibrary("pureRecord") DynamicObjectLibrary valuesLibrary) { + valuesLibrary.putInt(pureRecord, key, item); + valuesLibrary.setPropertyFlags(pureRecord, key, INT_TYPE); + } + + @Specialization(limit = "3") + static void exec( + Node node, + PureRecord pureRecord, + Object key, + long item, + @CachedLibrary("pureRecord") @Cached.Exclusive DynamicObjectLibrary valuesLibrary) { + valuesLibrary.putLong(pureRecord, key, item); + valuesLibrary.setPropertyFlags(pureRecord, key, LONG_TYPE); + } + + @Specialization(limit = "3") + static void exec( + Node node, + PureRecord pureRecord, + Object key, + double item, + @CachedLibrary("pureRecord") @Cached.Exclusive DynamicObjectLibrary valuesLibrary) { + valuesLibrary.putDouble(pureRecord, key, item); + valuesLibrary.setPropertyFlags(pureRecord, key, DOUBLE_TYPE); + } + + @Specialization(limit = "3") + static void exec( + Node node, + PureRecord pureRecord, + Object key, + Object item, + @CachedLibrary("pureRecord") @Cached.Exclusive DynamicObjectLibrary valuesLibrary) { + valuesLibrary.putWithFlags(pureRecord, key, item, OBJECT_TYPE); + } + + // @Specialization(guards = "existNode.execute(thisNode, pureRecord, key)") + // static Object execTransition( + // Node node, + // PureRecord pureRecord, + // Object key, + // Object item, + // @Bind("$node") Node thisNode, + // @Cached PureRecordNodes.GetValueNode getValueNode, + // @Cached PureRecordNodes.GetKeysNode getKeysNode, + // @Cached DuplicateKeyRecordNodes.AddPropNode addPropNode, + // @Cached @Cached.Shared PureRecordNodes.ExistNode existNode) { + // Object[] keys = getKeysNode.execute(thisNode, pureRecord); + // DuplicateKeyRecord newRecord = RawLanguage.get(thisNode).createDuplicateKeyRecord(); + // for (Object ikey : keys) { + // newRecord = + // addPropNode.execute( + // thisNode, newRecord, ikey, getValueNode.execute(thisNode, pureRecord, ikey)); + // } + // addPropNode.execute(thisNode, newRecord, key, item); + // return newRecord; + // } + } + + @NodeInfo(shortName = "PureRecord.RemovePropNode") + @GenerateUncached + @GenerateInline + @ImportStatic(PropertyType.class) + public abstract static class RemovePropNode extends Node { + + public abstract Object execute(Node node, PureRecord pureRecord, Object key); + + @Specialization + static Object exec( + Node node, + PureRecord pureRecord, + Object key, + @Bind("$node") Node thisNode, + @Cached AddPropNode addPropNode, + @Cached GetKeysNode getKeysNode, + @Cached GetValueNode getValueNode) { + RawLanguage lang = RawLanguage.get(thisNode); + PureRecord newRecord = lang.createPureRecord(); + Object[] keys = getKeysNode.execute(thisNode, pureRecord); + for (Object k : keys) { + if (!k.equals(key)) { + addPropNode.execute( + thisNode, newRecord, k, getValueNode.execute(thisNode, pureRecord, k)); + } + } + return newRecord; + } + } + + @NodeInfo(shortName = "PureRecord.Exist") + @GenerateUncached + @GenerateInline + @ImportStatic(PropertyType.class) + public abstract static class ExistNode extends Node { + + public abstract boolean execute(Node node, PureRecord pureRecord, Object key); + + @Specialization + static boolean exec( + Node node, + PureRecord pureRecord, + Object key, + @CachedLibrary(limit = "8") DynamicObjectLibrary valuesLibrary) { + return valuesLibrary.containsKey(pureRecord, key); + } + } + + @NodeInfo(shortName = "PureRecord.GetKeysNode") + @GenerateUncached + @GenerateInline + @ImportStatic(PropertyType.class) + public abstract static class GetKeysNode extends Node { + + public abstract Object[] execute(Node node, PureRecord record); + + @Specialization(limit = "3") + static Object[] exec( + Node node, + PureRecord pureRecord, + @CachedLibrary("pureRecord") DynamicObjectLibrary valuesLibrary) { + return valuesLibrary.getKeyArray(pureRecord); + } + } + + @NodeInfo(shortName = "ConcatRecord.GetValueByIndex") + @GenerateUncached + @GenerateInline + @ImportStatic(PropertyType.class) + public abstract static class GetValueByIndexNode extends Node { + public abstract Object execute(Node node, PureRecord record, int index); + + @Specialization(limit = "3") + static Object exec( + Node node, + PureRecord pureRecord, + int index, + @Bind("$node") Node thisNode, + @CachedLibrary("pureRecord") DynamicObjectLibrary valuesLibrary) { + Object[] keys = valuesLibrary.getKeyArray(pureRecord); + if (index < 0 || index >= keys.length) { + throw new RawTruffleInternalErrorException("Index out of bounds in record"); + } + return valuesLibrary.getOrDefault(pureRecord, keys[index], null); + } + } + + @NodeInfo(shortName = "PureRecord.Get") + @GenerateUncached + @GenerateInline + @ImportStatic(PropertyType.class) + public abstract static class GetValueNode extends Node { + + public abstract Object execute(Node node, PureRecord pureRecord, Object key); + + @Specialization( + limit = "3", + guards = "isByte(valuesLibrary.getPropertyFlagsOrDefault(pureRecord, key, 7))") + static byte getByte( + Node node, + PureRecord pureRecord, + Object key, + @CachedLibrary("pureRecord") DynamicObjectLibrary valuesLibrary) { + try { + return (byte) valuesLibrary.getIntOrDefault(pureRecord, key, -1); + } catch (UnexpectedResultException e) { + throw new RawTruffleInternalErrorException("Unexpected result", e); + } + } + + @Specialization( + limit = "3", + guards = "isShort(valuesLibrary.getPropertyFlagsOrDefault(pureRecord, key, 7))") + static short getShort( + Node node, + PureRecord pureRecord, + Object key, + @CachedLibrary("pureRecord") DynamicObjectLibrary valuesLibrary) { + try { + return (short) valuesLibrary.getIntOrDefault(pureRecord, key, -1); + } catch (UnexpectedResultException e) { + throw new RawTruffleInternalErrorException("Unexpected result", e); + } + } + + @Specialization( + limit = "3", + guards = "isInt(valuesLibrary.getPropertyFlagsOrDefault(pureRecord, key, 7))") + static int getInt( + Node node, + PureRecord pureRecord, + Object key, + @CachedLibrary("pureRecord") DynamicObjectLibrary valuesLibrary) { + try { + return valuesLibrary.getIntOrDefault(pureRecord, key, -1); + } catch (UnexpectedResultException e) { + throw new RawTruffleInternalErrorException("Unexpected result", e); + } + } + + @Specialization( + limit = "3", + guards = "isLong(valuesLibrary.getPropertyFlagsOrDefault(pureRecord, key, 7))") + static long getLong( + Node node, + PureRecord pureRecord, + Object key, + @CachedLibrary("pureRecord") DynamicObjectLibrary valuesLibrary) { + try { + return valuesLibrary.getLongOrDefault(pureRecord, key, -1); + } catch (UnexpectedResultException e) { + throw new RawTruffleInternalErrorException("Unexpected result", e); + } + } + + @Specialization( + limit = "3", + guards = "isDouble(valuesLibrary.getPropertyFlagsOrDefault(pureRecord, key, 7))") + static double getDouble( + Node node, + PureRecord pureRecord, + Object key, + @CachedLibrary("pureRecord") DynamicObjectLibrary valuesLibrary) { + try { + return valuesLibrary.getDoubleOrDefault(pureRecord, key, -1); + } catch (UnexpectedResultException e) { + throw new RawTruffleInternalErrorException("Unexpected result", e); + } + } + + @Specialization(limit = "3") + static Object getObject( + Node node, + PureRecord pureRecord, + Object key, + @CachedLibrary("pureRecord") DynamicObjectLibrary valuesLibrary) { + return valuesLibrary.getOrDefault(pureRecord, key, null); + } + } +} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/RecordNodes.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/RecordNodes.java index fddd16e6a..04d7b9a0f 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/RecordNodes.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/RecordNodes.java @@ -12,103 +12,178 @@ package raw.runtime.truffle.runtime.record; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import static raw.runtime.truffle.PropertyType.*; + import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.interop.InvalidArrayIndexException; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; -import com.oracle.truffle.api.object.DynamicObjectLibrary; -import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException; +// (az) Whenever using any of these nodes, create one per property public class RecordNodes { - @NodeInfo(shortName = "Record.ReadIndexNode") + + @NodeInfo(shortName = "Record.AddProp") + @GenerateUncached + @GenerateInline + public abstract static class AddPropNode extends Node { + + public abstract void execute( + Node node, Object record, Object key, Object value, boolean hasDuplicateKeys); + + @Specialization(guards = "!hasDuplicateKeys") + static void exec( + Node node, + PureRecord record, + Object key, + Object value, + boolean hasDuplicateKeys, + @Bind("$node") Node thisNode, + @Cached PureRecordNodes.AddPropNode addPropNode) { + addPropNode.execute(thisNode, record, key, value); + } + + @Specialization(guards = "hasDuplicateKeys") + static void exec( + Node node, + DuplicateKeyRecord record, + Object key, + Object value, + boolean hasDuplicateKeys, + @Bind("$node") Node thisNode, + @Cached DuplicateKeyRecordNodes.AddPropNode addPropNode) { + addPropNode.execute(thisNode, record, key, value); + } + } + + @NodeInfo(shortName = "Record.Exists") @GenerateUncached @GenerateInline - public abstract static class ReadIndexNode extends Node { + public abstract static class ExistsNode extends Node { + + public abstract boolean execute(Node node, Object record, String key); + + @Specialization + static boolean exec( + Node node, + PureRecord record, + String key, + @Bind("$node") Node thisNode, + @Cached PureRecordNodes.ExistNode addPropNode) { + return addPropNode.execute(thisNode, record, key); + } + + @Specialization + static boolean exec(Node node, DuplicateKeyRecord record, String key) { + return record.keyExist(key); + } + } + + @NodeInfo(shortName = "Record.GetValue") + @GenerateUncached + @GenerateInline + public abstract static class GetValueNode extends Node { + + public abstract Object execute(Node node, Object record, Object key); - public abstract Object execute(Node node, RecordObject record, int idx); + @Specialization + static Object exec( + Node node, + PureRecord record, + Object key, + @Bind("$node") Node thisNode, + @Cached PureRecordNodes.GetValueNode getValueNode) { + return getValueNode.execute(thisNode, record, key); + } - @Specialization(limit = "3") + @Specialization static Object exec( Node node, - RecordObject record, - int idx, - @CachedLibrary("record.values") DynamicObjectLibrary valuesLibrary) { - if (idx < 0 || idx >= record.keys.size()) { - throw new RawTruffleInternalErrorException(InvalidArrayIndexException.create(idx)); - } - return valuesLibrary.getOrDefault(record.values, idx, null); + DuplicateKeyRecord record, + Object key, + @Bind("$node") Node thisNode, + @Cached DuplicateKeyRecordNodes.GetValueNode getValueNode) { + return getValueNode.execute(thisNode, record, key); } } - @NodeInfo(shortName = "Record.ReadByKeyNode") + @NodeInfo(shortName = "Record.GetValueByIndex") @GenerateUncached @GenerateInline - public abstract static class ReadByKeyNode extends Node { + public abstract static class GetValueByIndexNode extends Node { - public abstract Object execute(Node node, RecordObject record, String key); + public abstract Object execute(Node node, Object record, int index); @Specialization static Object exec( Node node, - RecordObject record, - String key, + PureRecord record, + int index, @Bind("$node") Node thisNode, - @Cached ReadIndexNode readIdx) { - return readIdx.execute(thisNode, record, record.keys.indexOf(key)); + @Cached PureRecordNodes.GetValueByIndexNode getValueByIndexNode) { + return getValueByIndexNode.execute(thisNode, record, index); + } + + @Specialization + static Object exec( + Node node, + DuplicateKeyRecord record, + int index, + @Bind("$node") Node thisNode, + @Cached DuplicateKeyRecordNodes.GetValueByIndexNode getValueByIndexNode) { + return getValueByIndexNode.execute(thisNode, record, index); } } - @NodeInfo(shortName = "Record.WriteIndexNode") + @NodeInfo(shortName = "Record.GetKeys") @GenerateUncached @GenerateInline - public abstract static class WriteIndexNode extends Node { + public abstract static class GetKeysNode extends Node { - public abstract void execute(Node node, RecordObject record, int idx, String key, Object value); + public abstract Object[] execute(Node node, Object record); - @Specialization(limit = "3") - static void exec( + @Specialization + static Object[] exec( Node node, - RecordObject record, - int idx, - String key, - Object value, - @CachedLibrary("record.values") DynamicObjectLibrary valuesLibrary) { - if (idx >= record.keys.size()) { - record.keys.setSize(idx + 1); - } - record.keys.set(idx, key); - record.invalidateDistinctKeys(); - valuesLibrary.put(record.values, idx, value); + PureRecord record, + @Bind("$node") Node thisNode, + @Cached PureRecordNodes.GetKeysNode getKeysNode) { + return getKeysNode.execute(thisNode, record); + } + + @Specialization + static Object[] exec( + Node node, + DuplicateKeyRecord record, + @Bind("$node") Node thisNode, + @Cached DuplicateKeyRecordNodes.GetKeysNode getKeysNode) { + return getKeysNode.execute(thisNode, record); } } - @NodeInfo(shortName = "Record.AddByKeyNode") + @NodeInfo(shortName = "Record.RemoveProp") @GenerateUncached @GenerateInline - public abstract static class AddByKeyNode extends Node { + public abstract static class RemovePropNode extends Node { - public abstract void execute(Node node, RecordObject record, String key, Object value); + public abstract Object execute(Node node, Object record, String key); - @Specialization(limit = "3") - static void exec( + @Specialization + static Object exec( Node node, - RecordObject record, + PureRecord record, String key, - Object value, - @CachedLibrary("record.values") DynamicObjectLibrary valuesLibrary) { - valuesLibrary.put( - record.values, - record.keys.size(), - value); // "key" to use in the dynamic object is the current index. - addKey(record, key); // the original key is added (possible duplicate) - record.invalidateDistinctKeys(); + @Bind("$node") Node thisNode, + @Cached PureRecordNodes.RemovePropNode removePropNode) { + return removePropNode.execute(thisNode, record, key); } - @TruffleBoundary - private static void addKey(RecordObject record, String key) { - record.keys.add(key); + @Specialization + static Object exec( + Node node, + DuplicateKeyRecord record, + String key, + @Bind("$node") Node thisNode, + @Cached DuplicateKeyRecordNodes.RemovePropNode removePropNode) { + return removePropNode.execute(thisNode, record, key); } } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/RecordStorageObject.java b/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/RecordStorageObject.java deleted file mode 100644 index 0d102fce9..000000000 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/runtime/record/RecordStorageObject.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2023 RAW Labs S.A. - * - * Use of this software is governed by the Business Source License - * included in the file licenses/BSL.txt. - * - * As of the Change Date specified in that file, in accordance with - * the Business Source License, use of this software will be governed - * by the Apache License, Version 2.0, included in the file - * licenses/APL.txt. - */ - -package raw.runtime.truffle.runtime.record; - -import com.oracle.truffle.api.object.DynamicObject; -import com.oracle.truffle.api.object.Shape; - -// This is an implementation of `DynamicObject` used as an internal storage of our RecordObject. -class RecordStorageObject extends DynamicObject { - - protected RecordStorageObject(Shape shape) { - super(shape); - } -} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/tryable_nullable/Tryable.java b/snapi-truffle/src/main/java/raw/runtime/truffle/tryable_nullable/Tryable.java index 345559b65..8ac326bb3 100644 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/tryable_nullable/Tryable.java +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/tryable_nullable/Tryable.java @@ -12,20 +12,14 @@ package raw.runtime.truffle.tryable_nullable; -import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; import raw.runtime.truffle.runtime.primitives.ErrorObject; public class Tryable { - public static boolean isFailure(Object value) { + public static boolean isError(Object value) { return value instanceof ErrorObject; } public static boolean isSuccess(Object value) { return !(value instanceof ErrorObject); } - - public static String getFailure(Object value) { - if (!isFailure(value)) throw new RawTruffleRuntimeException("not a failure"); - return ((ErrorObject) value).getMessage(); - } } diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/tryable_nullable/TryableNullable.java b/snapi-truffle/src/main/java/raw/runtime/truffle/tryable_nullable/TryableNullable.java deleted file mode 100644 index c6bb5a054..000000000 --- a/snapi-truffle/src/main/java/raw/runtime/truffle/tryable_nullable/TryableNullable.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2023 RAW Labs S.A. - * - * Use of this software is governed by the Business Source License - * included in the file licenses/BSL.txt. - * - * As of the Change Date specified in that file, in accordance with - * the Business Source License, use of this software will be governed - * by the Apache License, Version 2.0, included in the file - * licenses/APL.txt. - */ - -package raw.runtime.truffle.tryable_nullable; - -import raw.runtime.truffle.runtime.primitives.ErrorObject; -import raw.runtime.truffle.runtime.primitives.NullObject; - -public class TryableNullable { - public static boolean handlePredicate(Object value, boolean defaultValue) { - if (value == null || value == NullObject.INSTANCE || value instanceof ErrorObject) { - return defaultValue; - } - return (Boolean) value; - } - - public static Object getOrElse(Object value, Object defaultValue) { - if (value == null || value == NullObject.INSTANCE || value instanceof ErrorObject) { - return defaultValue; - } - return value; - } - - public static boolean isValue(Object value) { - return Nullable.isNotNull(value) && Tryable.isSuccess(value); - } -} diff --git a/snapi-truffle/src/main/java/raw/runtime/truffle/tryable_nullable/TryableNullableNodes.java b/snapi-truffle/src/main/java/raw/runtime/truffle/tryable_nullable/TryableNullableNodes.java new file mode 100644 index 000000000..58a8e7a8a --- /dev/null +++ b/snapi-truffle/src/main/java/raw/runtime/truffle/tryable_nullable/TryableNullableNodes.java @@ -0,0 +1,151 @@ +/* + * Copyright 2023 RAW Labs S.A. + * + * Use of this software is governed by the Business Source License + * included in the file licenses/BSL.txt. + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0, included in the file + * licenses/APL.txt. + */ + +package raw.runtime.truffle.tryable_nullable; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.NodeInfo; +import raw.runtime.truffle.runtime.exceptions.RawTruffleRuntimeException; +import raw.runtime.truffle.runtime.primitives.ErrorObject; +import raw.runtime.truffle.runtime.primitives.NullObject; + +public class TryableNullableNodes { + @NodeInfo(shortName = "TryableNodes.IsNull") + @GenerateUncached + @GenerateInline + @ImportStatic(Nullable.class) + public abstract static class IsNullNode extends Node { + + public abstract boolean execute(Node node, Object value); + + @Specialization(guards = "isNull(value)") + static boolean exec(Node node, NullObject value) { + return true; + } + + @Specialization(guards = "!isNull(value)") + static boolean exec(Node node, Object value) { + return false; + } + } + + @NodeInfo(shortName = "TryableNodes.IsError") + @GenerateUncached + @GenerateInline + @ImportStatic(Tryable.class) + public abstract static class IsErrorNode extends Node { + + public abstract boolean execute(Node node, Object value); + + @Specialization(guards = "isError(value)") + static boolean exec(Node node, ErrorObject value) { + return true; + } + + @Specialization(guards = "!isError(value)") + static boolean exec(Node node, Object value) { + return false; + } + } + + @NodeInfo(shortName = "TryableNodes.GetFailure") + @GenerateUncached + @GenerateInline + @ImportStatic(Tryable.class) + public abstract static class GetErrorNode extends Node { + + public abstract String execute(Node node, Object value); + + @Specialization(guards = "isError(value)") + static String exec(Node node, ErrorObject value) { + return value.getMessage(); + } + + @Specialization(guards = "!isError(value)") + static String exec(Node node, Object value) { + throw new RawTruffleRuntimeException("not a failure"); + } + } + + @NodeInfo(shortName = "TryableNodes.HandlePredicate") + @GenerateUncached + @GenerateInline + @ImportStatic({Tryable.class, Nullable.class}) + public abstract static class HandlePredicateNode extends Node { + + public abstract boolean execute(Node node, Object value, boolean defaultValue); + + @Specialization(guards = "isError(value)") + static boolean exec(Node node, ErrorObject value, boolean defaultValue) { + return defaultValue; + } + + @Specialization(guards = "isNull(value)") + static boolean exec(Node node, NullObject value, boolean defaultValue) { + return defaultValue; + } + + @Specialization(guards = {"!isError(value)", "!isNull(value)"}) + static boolean exec(Node node, boolean value, boolean defaultValue) { + return value; + } + } + + @NodeInfo(shortName = "TryableNodes.GetOrElse") + @GenerateUncached + @GenerateInline + @ImportStatic({Tryable.class, Nullable.class}) + public abstract static class GetOrElseNode extends Node { + + public abstract Object execute(Node node, Object value, Object defaultValue); + + @Specialization(guards = "isError(value)") + static Object exec(Node node, ErrorObject value, Object defaultValue) { + return defaultValue; + } + + @Specialization(guards = "isNull(value)") + static Object exec(Node node, NullObject value, Object defaultValue) { + return defaultValue; + } + + @Specialization(guards = {"!isError(value)", "!isNull(value)"}) + static Object exec(Node node, Object value, Object defaultValue) { + return value; + } + } + + @NodeInfo(shortName = "TryableNodes.IsValue") + @GenerateUncached + @GenerateInline + @ImportStatic({Tryable.class, Nullable.class}) + public abstract static class IsValueNode extends Node { + + public abstract boolean execute(Node node, Object value); + + @Specialization(guards = {"!isError(value)", "!isNull(value)"}) + static boolean exec(Node node, Object value) { + return true; + } + + @Specialization(guards = "isError(value)") + static boolean exec(Node node, ErrorObject value) { + return false; + } + + @Specialization(guards = "isNull(value)") + static boolean exec(Node node, NullObject value) { + return false; + } + } +}