B DSLB DSL
G VMG VM
M MM M
D S LD S L
https://pxhere.com/en/photo/1057524
SELECT country,
COUNT(1) AS count
FROM Customer
GROUP BY country;
Given my account has a balance of € 430
When I receive a money transfer of € 500
Then my account should have a balance of € 930
Setup(
Boat on StartingShore,
Wolf on StartingShore,
Sheep on StartingShore,
Cabbage on StartingShore
) execute (
Boat move Cabbage to StartingShore,
Boat move Sheep to DestinationShore,
Boat move None to StartingShore,
Boat move Cabbage to DestinationShore,
Boat move Sheep to StartingShore,
Boat move Wolf to DestinationShore,
Boat move None to StartingShore,
Boat move Sheep to DestinationShore
)
https://github.com/NRBPerdijk/dsl-for-the-dense/
+ + > + + + + + [ < + > - ] + + + + + + + + [ < + + + + + + > - ] < .
B *B *
This program adds the numbers 2 and 5
+ + Store the number 2 in the first slot
> + + + + + Store the number 5 in the second slot
[ Move back and forth between first and second slot
< + > - While "moving" ones from the second to the first slot
]
The first slot now has '7' in it but we need to output the ASCII value for that
The ASCII value is 48 higher than the number we have
The second slot is now empty
It will act as a counter so we can add 6 * 8 to the first slot
+ + + + + + + + Store 8 in it
[ Again move back and forth between first and second slot
< + + + + + + while adding 6 to the first slot
> - before reducing the counter in the second slot
]
< . Go back to the first slot and print it
0 1 2 3 4 ... 29 997 29 998 29 999
2 5 3 0 0 0 0 0
↑
command meaning
+ increase value
- decrease value
. print value to std out
, read one byte from std in
[ if value eq 0, jump after matching ]
] if value neq 0, jump after matching [
< move pointer left
> move pointer right
https://www.thepinkhumanist.com/articles/330-life-of-alan-turing-examined-in-a-new-graphic-novel
https://commons.wikimedia.org/wiki/File:USA_tar_bubble_la_brea_CA.jpg
G VMG VM
“One VM to rule them all
cc-by-sa/2.0 - © Lairich Rig - https://www.geograph.org.uk/photo/3203827
BB
yapi.bf calculating 15 digits of π
Runtime Average time (ms/op) Error
Java HotSpot(TM) 64-Bit Server VM 53 ± 1
OpenJDK GraalVM CE 19.0.0 45 ± 1
All tests are ran on an 2018 MacBook Pro with 2.6 GHz Intel Core i7 and 16 GB 2400 MHz DDR4. The machine runs macOS Mojave 10.14.4 and JDK
1.8.0_212. Tests measured with . Each test ran 5 times with 5 warmup iterations.jmh
BB
yapi.bf calculating 45 digits of π
Runtime Average time (ms/op) Error
Java HotSpot(TM) 64-Bit Server VM 207 ± 2
OpenJDK GraalVM CE 19.0.0 185 ± 3
All tests are ran on an 2018 MacBook Pro with 2.6 GHz Intel Core i7 and 16 GB 2400 MHz DDR4. The machine runs macOS Mojave 10.14.4 and JDK
1.8.0_212. Tests measured with . Each test ran 5 times with 5 warmup iterations.jmh
TT
cc-by-sa/2.5 - © Darvin DeShazer - https://mushroomobserver.org/2538
“open source library for building
programming language
implementations as interpreters for
self-modifying Abstract Syntax Trees.
A S TA S T
ROOT
INCR_VAL INCR_VAL INCR_VAL INCR_VAL INCR_VAL JUMP INCR_VAL INCR_VAL
DECR_PTR INCR_VAL INCR_PTR DECR_VAL
(part of the program that adds 5 and 2)
https://chrisseaton.com/rubytruffle/pldi17-truffle/pldi17-truffle.pdf
P EP E
Calculate for positive integers
If we know (or assume) that , the program becomes simpler:
x
n
f (x, n) =
⎧
⎩
⎨
⎪
⎪
1
,(f (x, 0.5 ∗ n))
2
x ∗ f (x, n − 1),
if n = 0
if n is even
otherwise
n = 5
f (x) = x ∗ ( )x
2
2
BB
https://pxhere.com/en/photo/493605
BB
@Override
public void execute(final VirtualFrame frame) {
final int currentValue = someCalculation();
doPrint(getContext().getOutput(), (char) currentValue);
}
@TruffleBoundary
private void doPrint(final PrintWriter out, final char value) {
out.print(value);
out.flush();
}
SS
https://www.mammoet.com/cases/Tennet/
SS
@Specialization(guards = "b 0")
public double divide(int a, int b) {
return a / b;
}
SS
@Specialization(rewriteOn = ArithmeticException.class)
int doAddNoOverflow(int a, int b) {
return Math.addExact(a, b);
}
@Specialization
long doAddWithOverflow(int a, int b) {
return a + b;
}
execute(Integer.MAX_VALUE - 1, 1) doAddNoOverflow(Integer.MAX_VALUE - 1, 1)
execute(Integer.MAX_VALUE , 1) doAddNoOverflow(Integer.MAX_VALUE, 1)
throws ArithmeticException
doAddWithOverflow(Integer.MAX_VALUE, 1)
execute(Integer.MAX_VALUE - 1, 1) doAddWithOverflow(Integer.MAX_VALUE - 1, 1)
W G VM JVMW G VM JVM
function abs (int i)
if ( we saw only positive integers in the input ) {
return i;
} else {
transferToInterpreterAndInvalidate;
return i < 0 ? i : i;
}
}
B TB T
LL
Converts a sequence of characters into a sequence of tokens.
PP
Converts a sequence of tokens into (hierarchical) data structure.
P LP L
1. Write some regular expressions
2. Use a parser generator (like )ANTLR
cc-by-nc/2.5 - © Randall Munroe - https://www.xkcd.com/1171/
II
G VM UG VM U
GraalVM comes with the GraalVM Updater (gu)
Use gu to install components, such as language packs or tools.
e.g. gu install native-image
gu -L install brainfuck component-0.1-SNAPSHOT.jar
CC
Distribute your language implementation as a component:
$ tree
.
├── META-INF
│ ├── MANIFEST.MF
│ ├── permissions
│ └── symlinks
└── jre
└── languages
└── bf
├── bin
│ └── bf
├── brainfuck.jar
└── launcher
└── bf launcher.jar
6 directories, 6 files
UU
1. Prepare source code
2. Prepare GraalVM polyglot context
3. Evaluate the source code
input = "+ + > + + + + + [ < + > - ] + + + + + + + + [ < + + + + + + > - ] < .";
source = Source.newBuilder("bf", input, "user input").build();
output = new ByteArrayOutputStream();
context = Context.newBuilder("bf").out(output).build();
context.eval(source);
System.out.println(output.toString());
TT
“Implementing your own language
using GraalVM will not only give you
high performance. More importantly, it
allows your language to connect with
the rich tooling provided by the
GraalVM ecosystem.
https://www.graalvm.org/docs/graalvm-as-a-platform/
https://pxhere.com/en/photo/1067853
DD
Start the launcher with --inspect
Debugger listening on port 9229.
To start debugging, open the following URL in Chrome:
chrome-devtools://devtools/bundled/js_app.html?ws=127.0.0.1:9229/77b52d12-53f20cb0ab35
OO
The Truffle framework has an Instrument API to write other tools, e.g.
code coverage measurement, profilers.
1. Source code-related events
2. Allocation events
3. Language runtime and thread creation events
4. Application execution events
WW
Yes, you can run any language with GraalVM.
... but it may take some time.
It's certainly fun
... and it might even be profitable.
TT
You don't need to write a parser yourself
(and maybe you don't want to, either)
Take time to think about the AST
using a wrong structure leads to hard-to-track bugs
refactoring it later is very hard and time-consuming
@mthmulders  Oracle Code One
Q AQ A
Sample code:
Please help conference organisers: rate this talk
in the app or at the panel outside the door!
http://bit.ly/brainfuck-jvm

Building a DSL with GraalVM (CodeOne)

  • 1.
    B DSLB DSL GVMG VM M MM M
  • 2.
    D S LDS L https://pxhere.com/en/photo/1057524
  • 3.
    SELECT country, COUNT(1) AScount FROM Customer GROUP BY country;
  • 4.
    Given my accounthas a balance of € 430 When I receive a money transfer of € 500 Then my account should have a balance of € 930
  • 5.
    Setup( Boat on StartingShore, Wolfon StartingShore, Sheep on StartingShore, Cabbage on StartingShore ) execute ( Boat move Cabbage to StartingShore, Boat move Sheep to DestinationShore, Boat move None to StartingShore, Boat move Cabbage to DestinationShore, Boat move Sheep to StartingShore, Boat move Wolf to DestinationShore, Boat move None to StartingShore, Boat move Sheep to DestinationShore ) https://github.com/NRBPerdijk/dsl-for-the-dense/
  • 6.
    + + >+ + + + + [ < + > - ] + + + + + + + + [ < + + + + + + > - ] < .
  • 7.
    B *B * Thisprogram adds the numbers 2 and 5 + + Store the number 2 in the first slot > + + + + + Store the number 5 in the second slot [ Move back and forth between first and second slot < + > - While "moving" ones from the second to the first slot ] The first slot now has '7' in it but we need to output the ASCII value for that The ASCII value is 48 higher than the number we have The second slot is now empty It will act as a counter so we can add 6 * 8 to the first slot + + + + + + + + Store 8 in it [ Again move back and forth between first and second slot < + + + + + + while adding 6 to the first slot > - before reducing the counter in the second slot ] < . Go back to the first slot and print it
  • 8.
    0 1 23 4 ... 29 997 29 998 29 999 2 5 3 0 0 0 0 0 ↑
  • 9.
    command meaning + increasevalue - decrease value . print value to std out , read one byte from std in [ if value eq 0, jump after matching ] ] if value neq 0, jump after matching [ < move pointer left > move pointer right
  • 10.
  • 11.
  • 12.
    G VMG VM “OneVM to rule them all cc-by-sa/2.0 - © Lairich Rig - https://www.geograph.org.uk/photo/3203827
  • 14.
    BB yapi.bf calculating 15digits of π Runtime Average time (ms/op) Error Java HotSpot(TM) 64-Bit Server VM 53 ± 1 OpenJDK GraalVM CE 19.0.0 45 ± 1 All tests are ran on an 2018 MacBook Pro with 2.6 GHz Intel Core i7 and 16 GB 2400 MHz DDR4. The machine runs macOS Mojave 10.14.4 and JDK 1.8.0_212. Tests measured with . Each test ran 5 times with 5 warmup iterations.jmh
  • 15.
    BB yapi.bf calculating 45digits of π Runtime Average time (ms/op) Error Java HotSpot(TM) 64-Bit Server VM 207 ± 2 OpenJDK GraalVM CE 19.0.0 185 ± 3 All tests are ran on an 2018 MacBook Pro with 2.6 GHz Intel Core i7 and 16 GB 2400 MHz DDR4. The machine runs macOS Mojave 10.14.4 and JDK 1.8.0_212. Tests measured with . Each test ran 5 times with 5 warmup iterations.jmh
  • 16.
    TT cc-by-sa/2.5 - ©Darvin DeShazer - https://mushroomobserver.org/2538 “open source library for building programming language implementations as interpreters for self-modifying Abstract Syntax Trees.
  • 17.
    A S TAS T ROOT INCR_VAL INCR_VAL INCR_VAL INCR_VAL INCR_VAL JUMP INCR_VAL INCR_VAL DECR_PTR INCR_VAL INCR_PTR DECR_VAL (part of the program that adds 5 and 2)
  • 18.
  • 19.
    P EP E Calculatefor positive integers If we know (or assume) that , the program becomes simpler: x n f (x, n) = ⎧ ⎩ ⎨ ⎪ ⎪ 1 ,(f (x, 0.5 ∗ n)) 2 x ∗ f (x, n − 1), if n = 0 if n is even otherwise n = 5 f (x) = x ∗ ( )x 2 2
  • 20.
  • 21.
    BB @Override public void execute(finalVirtualFrame frame) { final int currentValue = someCalculation(); doPrint(getContext().getOutput(), (char) currentValue); } @TruffleBoundary private void doPrint(final PrintWriter out, final char value) { out.print(value); out.flush(); }
  • 22.
  • 23.
    SS @Specialization(guards = "b0") public double divide(int a, int b) { return a / b; }
  • 24.
    SS @Specialization(rewriteOn = ArithmeticException.class) intdoAddNoOverflow(int a, int b) { return Math.addExact(a, b); } @Specialization long doAddWithOverflow(int a, int b) { return a + b; } execute(Integer.MAX_VALUE - 1, 1) doAddNoOverflow(Integer.MAX_VALUE - 1, 1) execute(Integer.MAX_VALUE , 1) doAddNoOverflow(Integer.MAX_VALUE, 1) throws ArithmeticException doAddWithOverflow(Integer.MAX_VALUE, 1) execute(Integer.MAX_VALUE - 1, 1) doAddWithOverflow(Integer.MAX_VALUE - 1, 1)
  • 25.
    W G VMJVMW G VM JVM function abs (int i) if ( we saw only positive integers in the input ) { return i; } else { transferToInterpreterAndInvalidate; return i < 0 ? i : i; } }
  • 26.
  • 28.
    LL Converts a sequenceof characters into a sequence of tokens.
  • 29.
    PP Converts a sequenceof tokens into (hierarchical) data structure.
  • 30.
    P LP L 1.Write some regular expressions 2. Use a parser generator (like )ANTLR cc-by-nc/2.5 - © Randall Munroe - https://www.xkcd.com/1171/
  • 31.
  • 32.
    G VM UGVM U GraalVM comes with the GraalVM Updater (gu) Use gu to install components, such as language packs or tools. e.g. gu install native-image gu -L install brainfuck component-0.1-SNAPSHOT.jar
  • 33.
    CC Distribute your languageimplementation as a component: $ tree . ├── META-INF │ ├── MANIFEST.MF │ ├── permissions │ └── symlinks └── jre └── languages └── bf ├── bin │ └── bf ├── brainfuck.jar └── launcher └── bf launcher.jar 6 directories, 6 files
  • 34.
    UU 1. Prepare sourcecode 2. Prepare GraalVM polyglot context 3. Evaluate the source code input = "+ + > + + + + + [ < + > - ] + + + + + + + + [ < + + + + + + > - ] < ."; source = Source.newBuilder("bf", input, "user input").build(); output = new ByteArrayOutputStream(); context = Context.newBuilder("bf").out(output).build(); context.eval(source); System.out.println(output.toString());
  • 35.
    TT “Implementing your ownlanguage using GraalVM will not only give you high performance. More importantly, it allows your language to connect with the rich tooling provided by the GraalVM ecosystem. https://www.graalvm.org/docs/graalvm-as-a-platform/ https://pxhere.com/en/photo/1067853
  • 36.
    DD Start the launcherwith --inspect Debugger listening on port 9229. To start debugging, open the following URL in Chrome: chrome-devtools://devtools/bundled/js_app.html?ws=127.0.0.1:9229/77b52d12-53f20cb0ab35
  • 38.
    OO The Truffle frameworkhas an Instrument API to write other tools, e.g. code coverage measurement, profilers. 1. Source code-related events 2. Allocation events 3. Language runtime and thread creation events 4. Application execution events
  • 39.
    WW Yes, you canrun any language with GraalVM. ... but it may take some time. It's certainly fun ... and it might even be profitable.
  • 40.
    TT You don't needto write a parser yourself (and maybe you don't want to, either) Take time to think about the AST using a wrong structure leads to hard-to-track bugs refactoring it later is very hard and time-consuming
  • 41.
    @mthmulders  Oracle Code One QAQ A Sample code: Please help conference organisers: rate this talk in the app or at the panel outside the door! http://bit.ly/brainfuck-jvm