Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Building a DSL with GraalVM (javaBin online)

83 views

Published on

GraalVM is a virtual machine that can run many languages on top of the Java Virtual Machine. It comes with support for JavaScript, Ruby, Python… But what if you're building a DSL, or your language is not listed? Fear not!

In this session we'll discover what it takes to run another language in GraalVM. Using GraalVM, we don't only get a fast runtime, but we'll also get great tool support. With Brainfuck as an example, we'll see how we can run guest languages inside Java applications. It might not bring us profit, but at least it will bring some fun.

Published in: Software
  • Be the first to comment

  • Be the first to like this

Building a DSL with GraalVM (javaBin online)

  1. 1. B 
 
DSL
 G VM 
 
 
 
 
 M 
M @mthmulders  javaBin
  2. 2. W 
A 
Y 
C 
F www.slido.com,
event
code
#26563 @mthmulders  javaBin
  3. 3. D 
S 
L https://pxhere.com/en/photo/1057524 @mthmulders  javaBin
  4. 4. SELECT


country,
 








COUNT(1)
AS
count
 FROM




Customer
 GROUP
BY
country;
 @mthmulders  javaBin
  5. 5. 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
 @mthmulders  javaBin
  6. 6. 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/ @mthmulders  javaBin
  7. 7. +
+
>
+
+
+
+
+
[
<
+
>
-
]
+
+
+
+
+
+
+
+
[
<
+
+
+
+
+
+
>
-
]
<
.
 @mthmulders  javaBin
  8. 8. B This
program
adds
the
numbers
2
and
5
 
 +
+















Store
the
number
2
in
the
f rst
slot
 >
+
+
+
+
+







Store
the
number
5
in
the
second
slot
 
 [

















Move
back
and
forth
between
f rst
and
second
slot
 
 



<
+
>
-







While
"moving"
ones
from
the
second
to
the
f rst
slot
 ]
 
 The
f rst
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
f rst
slot
 +
+
+
+
+
+
+
+



Store
8
in
it
 
 [

















Again
move
back
and
forth
between
f rst
and
second
slot
 



<
+
+
+
+
+
+

while
adding
6
to
the
f rst
slot
 



>
-











before
reducing
the
counter
in
the
second
slot
 ]
 
 <
.















Go
back
to
the
f rst
slot
and
print
it
 @mthmulders  javaBin
  9. 9. 0 1 2 3 4 ... 29
997 29
998 29
999 2 5 3 0 0 0 0 0 ↑ @mthmulders  javaBin
  10. 10. 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 @mthmulders  javaBin
  11. 11. https://www.thepinkhumanist.com/articles/330-life-of-alan-turing-examined-in-a-new-graphic-novel @mthmulders  javaBin
  12. 12. https://commons.wikimedia.org/wiki/File:USA_tar_bubble_la_brea_CA.jpg @mthmulders  javaBin
  13. 13. G VM “One
VM
to
rule
them
all cc-by-sa/2.0
-
©
Lairich
Rig
-
https://www.geograph.org.uk/photo/3203827 @mthmulders  javaBin
  14. 14. @mthmulders  javaBin
  15. 15. B 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 @mthmulders  javaBin
  16. 16. B 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 @mthmulders  javaBin
  17. 17. T 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. @mthmulders  javaBin
  18. 18. A 
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) @mthmulders  javaBin
  19. 19. https://chrisseaton.com/rubytruffle/pldi17-truffle/pldi17-truffle.pdf @mthmulders  javaBin
  20. 20. P 
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 @mthmulders  javaBin
  21. 21. N 
 
POJO public
class
BFIncrementByteNode
extends
Node
{
 



/**
The
slot
that
holds
the
data
pointer.
 
 



private
f nal
FrameSlot
dataPointerSlot;
 
 



public
BFIncrementByteNode(f nal
FrameSlot
dataPointerSlot)
{
 







this.dataPointerSlot
=
dataPointerSlot;
 



}
 
 



@Override
public
void
execute(f nal
VirtualFrame
frame)
{
 







 
Find
the
memory
location
 







f nal
int
dataPointer
=
FrameUtil.getIntSafe(frame,
dataPointerSlot);
 







f nal
FrameSlot
currentByteSlot
=
frame.getFrameDescriptor().f ndFrameSlot(dataPointer);
 
 







 
Find
the
current
value
in
that
location
 







f nal
byte
currentValue
=
FrameUtil.getByteSafe(frame,
currentByteSlot);
 
 







 
Increase
the
current
value
 







f nal
byte
newValue
=
(byte)
(1
+
currentValue);
 
 







 
Store
the
current
value
 







frame.setByte(getSlot(frame),
newValue);
 



}
 }
 @mthmulders  javaBin
  22. 22. B https://pxhere.com/en/photo/493605 @mthmulders  javaBin
  23. 23. B @Override
 public
void
execute(f nal
VirtualFrame
frame)
{
 



f nal
int
currentValue
=
someCalculation();
 



doPrint(getContext().getOutput(),
(char)
currentValue);
 }
 
 @TruffleBoundary
 private
void
doPrint(f nal
PrintWriter
out,
f nal
char
value)
{
 



out.print(value);
 



out.flush();
 }
 @mthmulders  javaBin
  24. 24. S https://www.mammoet.com/cases/Tennet/ @mthmulders  javaBin
  25. 25. S @Specialization(guards
=
"b
 
0")
 public
double
divide(int
a,
int
b)
{
 



return
a
/
b;
 }
 @mthmulders  javaBin
  26. 26. S @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)
 @mthmulders  javaBin
  27. 27. W 
 
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;
 



}
 }
 @mthmulders  javaBin
  28. 28. B 
 
 
 
T @mthmulders  javaBin
  29. 29. @mthmulders  javaBin
  30. 30. L Converts
a
sequence
of
characters
into
a
sequence
of
tokens. 
 
 
 
 @mthmulders  javaBin
  31. 31. P Converts
a
sequence
of
tokens
into
(hierarchical)
data
structure. 
 
 
 
 @mthmulders  javaBin
  32. 32. P 
 
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/ @mthmulders  javaBin
  33. 33. I 
 
 @mthmulders  javaBin
  34. 34. G 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-0.1-SNAPSHOT-component.jar
 @mthmulders  javaBin
  35. 35. C 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
f les
 @mthmulders  javaBin
  36. 36. U 
 
 
 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());
 @mthmulders  javaBin
  37. 37. T “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 @mthmulders  javaBin
  38. 38. G 
L 
D 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
 @mthmulders  javaBin
  39. 39. @mthmulders  javaBin
  40. 40. G 
L 
C 
 Start
the
launcher
with
­­coverage,
and
optionally

 ­­coverage.Output=detailed
 ­­coverage.OutputFile=coverage.txt ------------------------------------------------------------------------------------------------
 Code
coverage
histogram.
 

Shows
what
percent
of
each
element
was
covered
during
execution
 ------------------------------------------------------------------------------------------------
 
Path






















































|

Statements
|



Lines
|



Roots

 ------------------------------------------------------------------------------------------------
 
~/Code/brainfuck jvm/launcher/src/test/resources/sample.bf
|




100.00%
|

100.00%
|



0.00%

 ------------------------------------------------------------------------------------------------
 @mthmulders  javaBin
  41. 41. W 
 
 
 The
Truffle
framework
has
an
Instrument
API
to
write
other
tools: 1.
Source
code-related
events 2.
Allocation
events 3.
Language
runtime
and
thread
creation
events 4.
Application
execution
events @mthmulders  javaBin
  42. 42. W 
 Yes,
you
can
run
any
language
with
GraalVM.
 ...
but
it
may
take
some
time. It's
certainly
fun
 ...
and
it
might
even
be
profitable. @mthmulders  javaBin
  43. 43. T 
 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  javaBin
  44. 44. Q
 
A 
 
 
 
 Sample
code:
 Follow-up
project:
 http://bit.ly/brainfuck-jvm https://bit.ly/scheme4graalvm @mthmulders  javaBin

×