Skip to content

Commit 9d605cf

Browse files
committed
Merge branch 'topic/builtin_specializations' into 'master'
Rewrite LKQL built-ins as specialized nodes Closes #130 See merge request eng/libadalang/langkit-query-language!300
2 parents da059e9 + 9539af9 commit 9d605cf

22 files changed

+734
-614
lines changed

lkql_jit/language/src/main/java/com/adacore/lkql_jit/built_ins/AbstractBuiltInFunctionBody.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
package com.adacore.lkql_jit.built_ins;
77

8+
import com.adacore.lkql_jit.nodes.LKQLNode;
89
import com.adacore.lkql_jit.nodes.expressions.Expr;
910
import com.adacore.lkql_jit.nodes.expressions.FunCall;
1011
import com.oracle.truffle.api.frame.VirtualFrame;
@@ -24,12 +25,24 @@ protected AbstractBuiltInFunctionBody() {
2425
super(null);
2526
}
2627

28+
// ----- Getters -----
29+
30+
public FunCall getCallNode() {
31+
return callNode;
32+
}
33+
2734
// ----- Setters -----
2835

2936
public void setCallNode(FunCall callNode) {
3037
this.callNode = callNode;
3138
}
3239

40+
// ----- Instance methods -----
41+
42+
public LKQLNode argNode(int index) {
43+
return this.callNode.getArgList().getArgs()[index];
44+
}
45+
3346
// ----- Class methods -----
3447

3548
/** Create a new built-in function body from the given callback representing its execution. */
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//
2+
// Copyright (C) 2005-2024, AdaCore
3+
// SPDX-License-Identifier: GPL-3.0-or-later
4+
//
5+
6+
package com.adacore.lkql_jit.built_ins;
7+
8+
import com.adacore.lkql_jit.LKQLTypeSystem;
9+
import com.oracle.truffle.api.dsl.TypeSystemReference;
10+
import com.oracle.truffle.api.frame.VirtualFrame;
11+
import com.oracle.truffle.api.nodes.Node;
12+
13+
public abstract class SpecializedBuiltInBody<
14+
T extends SpecializedBuiltInBody.SpecializedBuiltInNode>
15+
extends AbstractBuiltInFunctionBody {
16+
17+
// ----- Attributes -----
18+
19+
/** This node represents the execution of the built-in function. */
20+
@Child protected T specializedNode;
21+
22+
// ----- Constructors -----
23+
24+
/** Create a new specialized body with its corresponding execution node. */
25+
public SpecializedBuiltInBody(T specializedNode) {
26+
this.specializedNode = specializedNode;
27+
this.specializedNode.body = this;
28+
}
29+
30+
// ----- Instance methods -----
31+
32+
/** Dispatch the function arguments to the specialized execution node. */
33+
protected abstract Object dispatch(Object[] args);
34+
35+
@Override
36+
public Object executeGeneric(VirtualFrame frame) {
37+
return this.dispatch(frame.getArguments());
38+
}
39+
40+
// ----- Inner classes -----
41+
42+
/** This class represents an execution node, payload of a built-in body. */
43+
@TypeSystemReference(LKQLTypeSystem.class)
44+
public abstract static class SpecializedBuiltInNode extends Node {
45+
// ----- Attributes -----
46+
47+
/** The built-in body that owns this specialized node. */
48+
protected SpecializedBuiltInBody body;
49+
}
50+
}

lkql_jit/language/src/main/java/com/adacore/lkql_jit/built_ins/functions/BaseNameFunction.java

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55

66
package com.adacore.lkql_jit.built_ins.functions;
77

8-
import com.adacore.lkql_jit.LKQLTypeSystemGen;
98
import com.adacore.lkql_jit.built_ins.BuiltInFunctionValue;
9+
import com.adacore.lkql_jit.built_ins.SpecializedBuiltInBody;
1010
import com.adacore.lkql_jit.exception.LKQLRuntimeException;
1111
import com.adacore.lkql_jit.nodes.expressions.Expr;
12-
import com.adacore.lkql_jit.nodes.expressions.FunCall;
1312
import com.adacore.lkql_jit.utils.LKQLTypesHelper;
1413
import com.adacore.lkql_jit.utils.functions.FileUtils;
15-
import com.oracle.truffle.api.frame.VirtualFrame;
14+
import com.oracle.truffle.api.dsl.Fallback;
15+
import com.oracle.truffle.api.dsl.Specialization;
1616

1717
/**
1818
* This class represents the "base_name" built-in function in the LKQL language.
@@ -21,33 +21,39 @@
2121
*/
2222
public final class BaseNameFunction {
2323

24-
// ----- Attributes -----
25-
26-
/** The name of the built-in. */
2724
public static final String NAME = "base_name";
2825

29-
// ----- Class methods -----
30-
26+
/** Get a brand new "base_name" function value. */
3127
public static BuiltInFunctionValue getValue() {
3228
return new BuiltInFunctionValue(
3329
NAME,
3430
"Given a string that represents a file name, returns the basename",
3531
new String[] {"str"},
3632
new Expr[] {null},
37-
(VirtualFrame frame, FunCall call) -> {
38-
// Get the file full path
39-
Object path = frame.getArguments()[0];
40-
41-
// Check the argument type
42-
if (!LKQLTypeSystemGen.isString(path)) {
43-
throw LKQLRuntimeException.wrongType(
44-
LKQLTypesHelper.LKQL_STRING,
45-
LKQLTypesHelper.fromJava(path),
46-
call.getArgList().getArgs()[0]);
33+
new SpecializedBuiltInBody<>(BaseNameFunctionFactory.BaseNameExprNodeGen.create()) {
34+
@Override
35+
protected Object dispatch(Object[] args) {
36+
return specializedNode.executeBaseName(args[0]);
4737
}
48-
49-
// Return the base name of the file
50-
return FileUtils.baseName(LKQLTypeSystemGen.asString(path));
5138
});
5239
}
40+
41+
/** Expression of the "base_name" function. */
42+
abstract static class BaseNameExpr extends SpecializedBuiltInBody.SpecializedBuiltInNode {
43+
44+
public abstract String executeBaseName(Object fileName);
45+
46+
@Specialization
47+
protected String executeOnString(String fileName) {
48+
return FileUtils.baseName(fileName);
49+
}
50+
51+
@Fallback
52+
protected String invalidType(Object notValid) {
53+
throw LKQLRuntimeException.wrongType(
54+
LKQLTypesHelper.LKQL_STRING,
55+
LKQLTypesHelper.fromJava(notValid),
56+
body.argNode(0));
57+
}
58+
}
5359
}

lkql_jit/language/src/main/java/com/adacore/lkql_jit/built_ins/functions/ConcatFunction.java

Lines changed: 76 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@
77

88
import com.adacore.lkql_jit.LKQLTypeSystemGen;
99
import com.adacore.lkql_jit.built_ins.BuiltInFunctionValue;
10+
import com.adacore.lkql_jit.built_ins.SpecializedBuiltInBody;
1011
import com.adacore.lkql_jit.exception.LKQLRuntimeException;
1112
import com.adacore.lkql_jit.nodes.expressions.Expr;
12-
import com.adacore.lkql_jit.nodes.expressions.FunCall;
1313
import com.adacore.lkql_jit.runtime.values.lists.LKQLList;
1414
import com.adacore.lkql_jit.utils.LKQLTypesHelper;
1515
import com.adacore.lkql_jit.utils.functions.ArrayUtils;
1616
import com.adacore.lkql_jit.utils.functions.StringUtils;
17-
import com.oracle.truffle.api.frame.VirtualFrame;
17+
import com.oracle.truffle.api.CompilerDirectives;
18+
import com.oracle.truffle.api.dsl.Cached;
19+
import com.oracle.truffle.api.dsl.Fallback;
20+
import com.oracle.truffle.api.dsl.Specialization;
1821

1922
/**
2023
* This class represents the "concat" built-in function in the LKQL language.
@@ -23,92 +26,86 @@
2326
*/
2427
public final class ConcatFunction {
2528

26-
// ----- Attributes -----
27-
28-
/** The name of the function. */
2929
public static final String NAME = "concat";
3030

31-
// ----- Class methods -----
32-
31+
/** Get a brand new "concat" function value. */
3332
public static BuiltInFunctionValue getValue() {
3433
return new BuiltInFunctionValue(
3534
NAME,
3635
"Given a list of lists or strings, return a concatenated list or string",
3736
new String[] {"lists"},
3837
new Expr[] {null},
39-
(VirtualFrame frame, FunCall call) -> {
40-
41-
// Get the argument
42-
Object lists = frame.getArguments()[0];
43-
44-
// Check the type of the argument
45-
if (!LKQLTypeSystemGen.isLKQLList(lists)) {
46-
throw LKQLRuntimeException.wrongType(
47-
LKQLTypesHelper.LKQL_LIST,
48-
LKQLTypesHelper.fromJava(lists),
49-
call.getArgList().getArgs()[0]);
50-
}
51-
52-
// Cast the argument to list
53-
LKQLList listValue = LKQLTypeSystemGen.asLKQLList(lists);
54-
55-
// If the list is not empty
56-
if (listValue.size() > 0) {
57-
final Object firstItem = listValue.get(0);
58-
59-
// If the first value is a string look for strings in the list
60-
if (LKQLTypeSystemGen.isString(firstItem)) {
61-
// Create a string builder and add all strings in the list
62-
String result = LKQLTypeSystemGen.asString(firstItem);
63-
for (int i = 1; i < listValue.size(); i++) {
64-
final Object item = listValue.get(i);
65-
if (!LKQLTypeSystemGen.isString(item)) {
66-
throw LKQLRuntimeException.wrongType(
67-
LKQLTypesHelper.LKQL_STRING,
68-
LKQLTypesHelper.fromJava(item),
69-
call.getArgList().getArgs()[0]);
70-
}
71-
result =
72-
StringUtils.concat(
73-
result, LKQLTypeSystemGen.asString(item));
74-
}
75-
76-
// Return the result
77-
return result;
78-
}
79-
80-
// If the first item is a list look for lists in the list
81-
if (LKQLTypeSystemGen.isLKQLList(firstItem)) {
82-
// Create a result array and add all list of the argument
83-
Object[] result = LKQLTypeSystemGen.asLKQLList(firstItem).getContent();
84-
for (int i = 1; i < listValue.size(); i++) {
85-
final Object item = listValue.get(i);
86-
if (!LKQLTypeSystemGen.isLKQLList(item)) {
87-
throw LKQLRuntimeException.wrongType(
88-
LKQLTypesHelper.LKQL_LIST,
89-
LKQLTypesHelper.fromJava(item),
90-
call.getArgList().getArgs()[0]);
91-
}
92-
result =
93-
ArrayUtils.concat(
94-
result,
95-
LKQLTypeSystemGen.asLKQLList(item).getContent());
96-
}
97-
return new LKQLList(result);
98-
}
99-
100-
// Else there is an error
101-
throw LKQLRuntimeException.wrongType(
102-
LKQLTypesHelper.typeUnion(
103-
LKQLTypesHelper.LKQL_LIST, LKQLTypesHelper.LKQL_STRING),
104-
LKQLTypesHelper.fromJava(firstItem),
105-
call.getArgList().getArgs()[0]);
106-
}
107-
108-
// If the list is empty just return an empty list
109-
else {
110-
return new LKQLList(new Object[0]);
38+
new SpecializedBuiltInBody<>(ConcatFunctionFactory.ConcatExprNodeGen.create()) {
39+
@Override
40+
protected Object dispatch(Object[] args) {
41+
return specializedNode.executeConcat(args[0]);
11142
}
11243
});
11344
}
45+
46+
/** Expression of the "concat" function. */
47+
abstract static class ConcatExpr extends SpecializedBuiltInBody.SpecializedBuiltInNode {
48+
49+
public abstract Object executeConcat(Object list);
50+
51+
protected static boolean isString(Object o) {
52+
return LKQLTypeSystemGen.isString(o);
53+
}
54+
55+
protected static boolean isList(Object o) {
56+
return LKQLTypeSystemGen.isLKQLList(o);
57+
}
58+
59+
@Specialization(guards = {"list.size() > 0", "isString(list.get(0))"})
60+
protected String onListOfStrings(LKQLList list) {
61+
// Create a string builder and add all strings in the list
62+
String result = LKQLTypeSystemGen.asString(list.get(0));
63+
for (int i = 1; i < list.size(); i++) {
64+
final Object item = list.get(i);
65+
if (!LKQLTypeSystemGen.isString(item)) {
66+
this.invalidElemType(list, item);
67+
}
68+
result = StringUtils.concat(result, LKQLTypeSystemGen.asString(item));
69+
}
70+
return result;
71+
}
72+
73+
@Specialization(guards = {"list.size() > 0", "isList(list.get(0))"})
74+
protected LKQLList onListOfLists(LKQLList list) {
75+
Object[] result = LKQLTypeSystemGen.asLKQLList(list.get(0)).getContent();
76+
for (int i = 1; i < list.size(); i++) {
77+
final Object item = list.get(i);
78+
if (!LKQLTypeSystemGen.isLKQLList(item)) {
79+
this.invalidElemType(list, item);
80+
}
81+
result = ArrayUtils.concat(result, LKQLTypeSystemGen.asLKQLList(item).getContent());
82+
}
83+
return new LKQLList(result);
84+
}
85+
86+
@Specialization(guards = "notValidElem.size() > 0")
87+
@CompilerDirectives.TruffleBoundary
88+
protected LKQLList invalidElemType(
89+
@SuppressWarnings("unused") LKQLList notValidElem,
90+
@Cached("notValidElem.get(0)") Object elem) {
91+
throw LKQLRuntimeException.wrongType(
92+
LKQLTypesHelper.LKQL_LIST
93+
+ " of "
94+
+ LKQLTypesHelper.typeUnion(
95+
LKQLTypesHelper.LKQL_LIST, LKQLTypesHelper.LKQL_STRING),
96+
LKQLTypesHelper.fromJava(elem) + " element",
97+
body.argNode(0));
98+
}
99+
100+
@Specialization(guards = "emptyList.size() == 0")
101+
protected LKQLList onEmptyList(@SuppressWarnings("unused") LKQLList emptyList) {
102+
return new LKQLList(new Object[0]);
103+
}
104+
105+
@Fallback
106+
protected LKQLList invalidType(Object notValid) {
107+
throw LKQLRuntimeException.wrongType(
108+
LKQLTypesHelper.LKQL_LIST, LKQLTypesHelper.fromJava(notValid), body.argNode(0));
109+
}
110+
}
114111
}

lkql_jit/language/src/main/java/com/adacore/lkql_jit/built_ins/functions/DocFunction.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,9 @@
1919
*/
2020
public final class DocFunction {
2121

22-
// ----- Attributes -----
23-
24-
/** The name of the function. */
2522
public static final String NAME = "doc";
2623

27-
// ----- Class methods -----
28-
24+
/** Get a brand new "doc" function value. */
2925
public static BuiltInFunctionValue getValue() {
3026
return new BuiltInFunctionValue(
3127
NAME,

lkql_jit/language/src/main/java/com/adacore/lkql_jit/built_ins/functions/DocumentBuiltins.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,18 @@
1919
public class DocumentBuiltins {
2020
public static final String NAME = "document_builtins";
2121

22+
/** Get a brand new "document_builtins" function value. */
23+
public static BuiltInFunctionValue getValue() {
24+
return new BuiltInFunctionValue(
25+
NAME,
26+
"Return a string in the RsT format containing documentation for all built-ins",
27+
new String[] {},
28+
new Expr[] {},
29+
(VirtualFrame frame, FunCall call) ->
30+
documentBuiltinsImpl(frame.materialize(), call));
31+
}
32+
33+
/** Function for the "document_builtins" execution. */
2234
@CompilerDirectives.TruffleBoundary
2335
public static String documentBuiltinsImpl(
2436
@SuppressWarnings("unused") MaterializedFrame frame,
@@ -93,14 +105,4 @@ public static String documentBuiltinsImpl(
93105
throw new RuntimeException(e);
94106
}
95107
}
96-
97-
public static BuiltInFunctionValue getValue() {
98-
return new BuiltInFunctionValue(
99-
NAME,
100-
"Return a string in the RsT format containing documentation for all built-ins",
101-
new String[] {},
102-
new Expr[] {},
103-
(VirtualFrame frame, FunCall call) ->
104-
documentBuiltinsImpl(frame.materialize(), call));
105-
}
106108
}

0 commit comments

Comments
 (0)