The following is intended to outline our general product direction. It is intended for information purposes
only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code,
or functionality, and should not be relied upon in making purchasing decisions. The development,
release, timing, and pricing of any features or functionality described for Oracle’s products may change
and remains at the sole discretion of Oracle Corporation.
Statements in this presentation relating to Oracle’s future plans, expectations, beliefs, intentions and
prospects are “forward-looking statements” and are subject to material risks and uncertainties. A detailed
discussion of these factors and other risks that affect our business is contained in Oracle’s Securities and
Exchange Commission (SEC) filings, including our most recent reports on Form 10-K and Form 10-Q
under the heading “Risk Factors.” These filings are available on the SEC’s website or on Oracle’s website
at http://www.oracle.com/investor. All information in this presentation is current as of September 2019
and Oracle undertakes no duty to update any statement in light of new information or future events.
Safe Harbor
Copyright © 2019 Oracle and/or its affiliates.
Invokedynamic for Mere Mortals
[DEV4253]
Principal Member of Technical Staff
Java Platform Group
September 17, 2019
David Buck
Copyright © 2019 Oracle and/or its affiliates.
JVM Sustaining Engineer
OpenJDK Update Project
Maintainer
JavaOne Rock Star
Co-author of Oracle WebLogic
Server 11g 構築・運用ガイド
@DavidBuckJP
https://blogs.oracle.com/buck/
Who am I? David Buck (left)
Program Agenda
Introduction
java.lang.invoke
invokedynamic instruction
Other stuff
1
2
3
4
4
Introduction
5
Target Audience
Not compiler writers
Curious
6
Motivation
Understand javap output better
Understand the value JVM has as a multi-language JVM
7
Da Vinci Machine Project
The JVM is a great platform for running all sorts of languages
Great performance
Portability
Security (sandbox)
Pre-existing libraries and frameworks
8
JVM-specific
Scala
Clojure
Groovy
Ceylon
Fortress
Gosu
Kotlin
Ported to JVM
JRuby
Jython
Smalltalk
Ada
Scheme
REXX
Prolog
Pascal
Common LISP
(a small subset of) JVM languages
9
Java Code
Language Runtime
10
JVM
OS
Java
Class Library
JRuby Runtime
JVM
OS
Java
Class Library
Ruby Code
non-Java language wish list
Continuations
Dynamic invocation
Tail recursion
Interface injection
Other stuff
11
non-Java language wish list
Continuations
Dynamic invocation
Tail recursion
Interface injection
Other stuff
12
What is dynamic typing?
13
What is dynamic typing?
def addtwo(a, b)
a + b;
end
14
What is dynamic typing?
We do not know what the types are until runtime
15
statically-typed vs. dynamically-typed
When do we type check / link?
Compilation time (javac)
Runtime
16
Compile-time checking / linking
Catch errors early
Limits the type of code we can write (false positives)
17
Run time checking / linking
Allow more freedom of programming (less false positives)
Less guarantees about runtime behavior
18
dynamic typing != type inference
object InferenceTest1 extends App {
val x = 1 + 2 * 3 // the type of x is Int
val y = x.toString() // the type of y is String
def succ(x: Int) = x + 1 // succ returns Int values
}
(Shamelessly copied from http://docs.scala-
lang.org/tutorials/tour/local-type-inference.html)
19
dynamic typing != week typing
a = "40"
b = a + 2
20
Dynamically-typed languages
Allow more programs, but have to do more runtime checking.
No perfect type information at compile time
21
Polymorphism != Dynamic typing (?!)
public String bar(Object o) {
return "You passed me " + o.toString();
}
22
The original invocation lineup
invokestatic
Class method
invokevirtual
Instance method
invokeinterface
Interface method
Invokespecial
Everything else (private, super class, constructors)
23
The original invocation lineup
invokestatic
Class method
invokevirtual
Instance method
invokeinterface
Interface method
Invokespecial
Everything else (private, super class, constructors)
24
invokestatic
public class InvokeStaticExample {
public static void main(String[] args) {
InvokeStaticExample.foo();
}
public static void foo() {
System.out.println("I am foo!");
}
}
25
The original invocation lineup
invokestatic
Class method
invokevirtual
Instance method
invokeinterface
Interface method
Invokespecial
Everything else (private, super class, constructors)
26
invokevirtual
public class InvokeVirtualExample {
public static void main(String[] args) {
InvokeVirtualExample ive = new InvokeVirtualExample();
ive.foo();
}
public void foo() {
System.out.println("I am foo!");
}
}
27
The original invocation lineup
invokestatic
Class method
invokevirtual
Instance method
invokeinterface
Interface method
Invokespecial
Everything else (private, super class, constructors)
28
public class InvokeInterfaceExample
implements MyInterface {
public static void main(String[] args)
{
MyInterface iie = new
InvokeInterfaceExample();
iie.foo();
}
public void foo() {
System.out.println("I am foo!");
}
}
interface MyInterface {
public void foo();
}
29
invokeinterface
The original invocation lineup
invokestatic
Class method
invokevirtual
Instance method
invokeinterface
Interface method
Invokespecial
Everything else (private, super class, constructors)
30
invokespecial
public class InvokeSpecialExample {
public static void main(String[] args) {
InvokeSpecialExample ise = new InvokeSpecialExample();
ise.foo();
}
private void foo() {
System.out.println("I am foo!");
}
}
31
Poor dynamic languages on JVM?
invocation logic is not baked into the JVM like it is for Java
we need to fall back on reflection
32
Reflection is slow
security check on each invocation
all arguments are Objects (boxing)
33
What the JVM doesn’t know can hurt it
34
Caller
Reflection
Magic! Callee
Reflection prevents inlining!
35
Caller
Reflection
Magic! Callee
No one writes code like this
if (false) {
// do some important stuff...
System.out.println("I'm important!");
}
36
Or this…
boolean cond = true;
if (cond) {
// do some important stuff...
System.out.println("I'm important!");
}
37
public void methodB() {
// ...
methodA(false);
// ...
}
public void methodA(boolean
optionalStuff) {
// ...
if (optionalStuff) {
// do some optional, but
important stuff...
System.out.println("I'm important
sometimes!");
}
// ...
}
38
But we do write stuff like
JSR-292
java.lang.invoke API
A “better reflection”
invokedynamic bytecode
Allows us to dispatch to linkage logic defined by invoke API
39
invokedynamic
We call it “indy”
No clear way to express in Java language
Important milestone for JVM
First new instruction in decades
First new JVM feature to only (mainly) target non-java languages
40
java.lang.invoke API
MethodHandle
CallSite
Bootstrap Method (BSM)
41
MethodHandle
42
int foo()Method Handle
MethodHandle
Points to a method
Is a “function pointer” (am I allowed to say this?)
Polymorphic signature
43
MethodHandle Performance
44
MethodHandle Performance
Early performance was not ideal
45
MethodHandle Performance
Early performance was not ideal
Performance improved tremendously with lambda forms
46
MethodHandle Performance
Early performance was not ideal
Performance improved tremendously with lambda forms
Is now often significantly faster than reflection
47
MethodHandle Performance
Early performance was not ideal
Performance improved tremendously with lambda forms
Is now often significantly faster than reflection
Can be used independently of invokedynamic
48
CallSite
49
private void doStuff();
descriptor: ()V
flags: ACC_PRIVATE
Code:
stack=2, locals=2, args_size=1
0: new #7
3: dup
4: invokespecial #8
7: astore_1
8: aload_1
9: aload_0
10: invokedynamic #9, 0
15: invokevirtual #10
18: return
CS Method Handle int foo()
CallSite
50
private void doStuff();
descriptor: ()V
flags: ACC_PRIVATE
Code:
stack=2, locals=2, args_size=1
0: new #7
3: dup
4: invokespecial #8
7: astore_1
8: aload_1
9: aload_0
10: invokedynamic #9, 0
15: invokevirtual #10
18: return
CS
int bar()
int foo()
CallSite
Reifies Indy invocation side
Has a MethodHandle
51
Bootstrapping Step 1
52
private void doStuff();
descriptor: ()V
flags: ACC_PRIVATE
Code:
stack=2, locals=2, args_size=1
0: new #7
3: dup
4: invokespecial #8
7: astore_1
8: aload_1
9: aload_0
10: invokedynamic #9, 0
15: invokevirtual #10
18: return
Bootstrapping Step 2
53
private void doStuff();
descriptor: ()V
flags: ACC_PRIVATE
Code:
stack=2, locals=2, args_size=1
0: new #7
3: dup
4: invokespecial #8
7: astore_1
8: aload_1
9: aload_0
10: invokedynamic #9, 0
15: invokevirtual #10
18: return BootStrap Method
Bootstrapping Step 3
54
private void doStuff();
descriptor: ()V
flags: ACC_PRIVATE
Code:
stack=2, locals=2, args_size=1
0: new #7
3: dup
4: invokespecial #8
7: astore_1
8: aload_1
9: aload_0
10: invokedynamic #9, 0
15: invokevirtual #10
18: return BootStrap Method
int foo()
Bootstrapping Step 4
55
private void doStuff();
descriptor: ()V
flags: ACC_PRIVATE
Code:
stack=2, locals=2, args_size=1
0: new #7
3: dup
4: invokespecial #8
7: astore_1
8: aload_1
9: aload_0
10: invokedynamic #9, 0
15: invokevirtual #10
18: return BootStrap Method
int foo()
CS
Bootstrapping Step 5
56
private void doStuff();
descriptor: ()V
flags: ACC_PRIVATE
Code:
stack=2, locals=2, args_size=1
0: new #7
3: dup
4: invokespecial #8
7: astore_1
8: aload_1
9: aload_0
10: invokedynamic #9, 0
15: invokevirtual #10
18: return
int foo()
CS
Bootstrap Method
Only called on the first invocation of each indy bytecode
Returns a CallSite
57
"Dr Martens, black, old" by Tarquin
is licensed under CC BY-SA 3.0
Indy lifecycle
Initial Invocation
1. A specific indy invocation is executed for the first time
2. Bootstrap method is called and if finds (generates?!) a method to
run
3. Bootstrap method returns a permanent CallSite object for this
indy invocation
4. We jump to the method pointed to by the CallSite
58
Indy Lifecycle
All subsequent calls
We jump to the method pointed to by the CallSite
59
Picture from
National Archives and Records Administration
This performance tragedy becomes
60
Caller
Reflection
Magic! Callee
61
Caller Callee
MethodHandle
Linkage != Invocation
62
Linkage != Invocation
Linkage (i.e. bootstrap)
Usually only needs to be done once
Is expensive
63
Linkage != Invocation
Linkage (i.e. bootstrap)
Usually only needs to be done once
Is expensive
Invocation
Done a lot
Only needs a jmp/call (and possibly a guard)
64
Linkage != Invocation
Avoid the cost of linkage on almost every call
65
• Mismatch between language and bytecode
• JDK <= 8 javac uses StringBuilder.append()
• StringBuilder has performance issues
• JDK >= 9 uses invoke dynamic
Copyright © 2019 Oracle and/or its affiliates.
String Concatenation
Takeaways
67
Takeaways
Invokedynamic lets us programmatically alter linkage
68
Takeaways
Invokedynamic lets us programmatically alter linkage
Then it gets out of the way! (linkage != invocation)
69
Takeaways
Invokedynamic lets us programmatically alter linkage
Then it gets out of the way! (linkage != invocation)
The Invoke API can often be used without indy
70
Takeaways
Invokedynamic lets us programmatically alter linkage
Then it gets out of the way! (linkage != invocation)
The Invoke API can often be used without indy
JVM is a great platform for just about any language!
71
Resources
JVM Language Summit
http://openjdk.java.net/projects/mlvm/jvmlangsummit/
Linkers & Loaders book
http://linker.iecc.com/
John Rose’s Blog
https://blogs.oracle.com/jrose/
72
Thank You!
73
The preceding is intended to outline our general product direction. It is intended for information purposes
only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code,
or functionality, and should not be relied upon in making purchasing decisions. The development,
release, timing, and pricing of any features or functionality described for Oracle’s products may change
and remains at the sole discretion of Oracle Corporation.
Statements in this presentation relating to Oracle’s future plans, expectations, beliefs, intentions and
prospects are “forward-looking statements” and are subject to material risks and uncertainties. A detailed
discussion of these factors and other risks that affect our business is contained in Oracle’s Securities and
Exchange Commission (SEC) filings, including our most recent reports on Form 10-K and Form 10-Q
under the heading “Risk Factors.” These filings are available on the SEC’s website or on Oracle’s website
at http://www.oracle.com/investor. All information in this presentation is current as of September 2019
and Oracle undertakes no duty to update any statement in light of new information or future events.
Safe Harbor
Copyright © 2019 Oracle and/or its affiliates.

invokedynamic for Mere Mortals [Code One 2019]

  • 1.
    The following isintended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, timing, and pricing of any features or functionality described for Oracle’s products may change and remains at the sole discretion of Oracle Corporation. Statements in this presentation relating to Oracle’s future plans, expectations, beliefs, intentions and prospects are “forward-looking statements” and are subject to material risks and uncertainties. A detailed discussion of these factors and other risks that affect our business is contained in Oracle’s Securities and Exchange Commission (SEC) filings, including our most recent reports on Form 10-K and Form 10-Q under the heading “Risk Factors.” These filings are available on the SEC’s website or on Oracle’s website at http://www.oracle.com/investor. All information in this presentation is current as of September 2019 and Oracle undertakes no duty to update any statement in light of new information or future events. Safe Harbor Copyright © 2019 Oracle and/or its affiliates.
  • 2.
    Invokedynamic for MereMortals [DEV4253] Principal Member of Technical Staff Java Platform Group September 17, 2019 David Buck Copyright © 2019 Oracle and/or its affiliates.
  • 3.
    JVM Sustaining Engineer OpenJDKUpdate Project Maintainer JavaOne Rock Star Co-author of Oracle WebLogic Server 11g 構築・運用ガイド @DavidBuckJP https://blogs.oracle.com/buck/ Who am I? David Buck (left)
  • 4.
  • 5.
  • 6.
  • 7.
    Motivation Understand javap outputbetter Understand the value JVM has as a multi-language JVM 7
  • 8.
    Da Vinci MachineProject The JVM is a great platform for running all sorts of languages Great performance Portability Security (sandbox) Pre-existing libraries and frameworks 8
  • 9.
  • 10.
    Java Code Language Runtime 10 JVM OS Java ClassLibrary JRuby Runtime JVM OS Java Class Library Ruby Code
  • 11.
    non-Java language wishlist Continuations Dynamic invocation Tail recursion Interface injection Other stuff 11
  • 12.
    non-Java language wishlist Continuations Dynamic invocation Tail recursion Interface injection Other stuff 12
  • 13.
    What is dynamictyping? 13
  • 14.
    What is dynamictyping? def addtwo(a, b) a + b; end 14
  • 15.
    What is dynamictyping? We do not know what the types are until runtime 15
  • 16.
    statically-typed vs. dynamically-typed Whendo we type check / link? Compilation time (javac) Runtime 16
  • 17.
    Compile-time checking /linking Catch errors early Limits the type of code we can write (false positives) 17
  • 18.
    Run time checking/ linking Allow more freedom of programming (less false positives) Less guarantees about runtime behavior 18
  • 19.
    dynamic typing !=type inference object InferenceTest1 extends App { val x = 1 + 2 * 3 // the type of x is Int val y = x.toString() // the type of y is String def succ(x: Int) = x + 1 // succ returns Int values } (Shamelessly copied from http://docs.scala- lang.org/tutorials/tour/local-type-inference.html) 19
  • 20.
    dynamic typing !=week typing a = "40" b = a + 2 20
  • 21.
    Dynamically-typed languages Allow moreprograms, but have to do more runtime checking. No perfect type information at compile time 21
  • 22.
    Polymorphism != Dynamictyping (?!) public String bar(Object o) { return "You passed me " + o.toString(); } 22
  • 23.
    The original invocationlineup invokestatic Class method invokevirtual Instance method invokeinterface Interface method Invokespecial Everything else (private, super class, constructors) 23
  • 24.
    The original invocationlineup invokestatic Class method invokevirtual Instance method invokeinterface Interface method Invokespecial Everything else (private, super class, constructors) 24
  • 25.
    invokestatic public class InvokeStaticExample{ public static void main(String[] args) { InvokeStaticExample.foo(); } public static void foo() { System.out.println("I am foo!"); } } 25
  • 26.
    The original invocationlineup invokestatic Class method invokevirtual Instance method invokeinterface Interface method Invokespecial Everything else (private, super class, constructors) 26
  • 27.
    invokevirtual public class InvokeVirtualExample{ public static void main(String[] args) { InvokeVirtualExample ive = new InvokeVirtualExample(); ive.foo(); } public void foo() { System.out.println("I am foo!"); } } 27
  • 28.
    The original invocationlineup invokestatic Class method invokevirtual Instance method invokeinterface Interface method Invokespecial Everything else (private, super class, constructors) 28
  • 29.
    public class InvokeInterfaceExample implementsMyInterface { public static void main(String[] args) { MyInterface iie = new InvokeInterfaceExample(); iie.foo(); } public void foo() { System.out.println("I am foo!"); } } interface MyInterface { public void foo(); } 29 invokeinterface
  • 30.
    The original invocationlineup invokestatic Class method invokevirtual Instance method invokeinterface Interface method Invokespecial Everything else (private, super class, constructors) 30
  • 31.
    invokespecial public class InvokeSpecialExample{ public static void main(String[] args) { InvokeSpecialExample ise = new InvokeSpecialExample(); ise.foo(); } private void foo() { System.out.println("I am foo!"); } } 31
  • 32.
    Poor dynamic languageson JVM? invocation logic is not baked into the JVM like it is for Java we need to fall back on reflection 32
  • 33.
    Reflection is slow securitycheck on each invocation all arguments are Objects (boxing) 33
  • 34.
    What the JVMdoesn’t know can hurt it 34 Caller Reflection Magic! Callee
  • 35.
  • 36.
    No one writescode like this if (false) { // do some important stuff... System.out.println("I'm important!"); } 36
  • 37.
    Or this… boolean cond= true; if (cond) { // do some important stuff... System.out.println("I'm important!"); } 37
  • 38.
    public void methodB(){ // ... methodA(false); // ... } public void methodA(boolean optionalStuff) { // ... if (optionalStuff) { // do some optional, but important stuff... System.out.println("I'm important sometimes!"); } // ... } 38 But we do write stuff like
  • 39.
    JSR-292 java.lang.invoke API A “betterreflection” invokedynamic bytecode Allows us to dispatch to linkage logic defined by invoke API 39
  • 40.
    invokedynamic We call it“indy” No clear way to express in Java language Important milestone for JVM First new instruction in decades First new JVM feature to only (mainly) target non-java languages 40
  • 41.
  • 42.
  • 43.
    MethodHandle Points to amethod Is a “function pointer” (am I allowed to say this?) Polymorphic signature 43
  • 44.
  • 45.
  • 46.
    MethodHandle Performance Early performancewas not ideal Performance improved tremendously with lambda forms 46
  • 47.
    MethodHandle Performance Early performancewas not ideal Performance improved tremendously with lambda forms Is now often significantly faster than reflection 47
  • 48.
    MethodHandle Performance Early performancewas not ideal Performance improved tremendously with lambda forms Is now often significantly faster than reflection Can be used independently of invokedynamic 48
  • 49.
    CallSite 49 private void doStuff(); descriptor:()V flags: ACC_PRIVATE Code: stack=2, locals=2, args_size=1 0: new #7 3: dup 4: invokespecial #8 7: astore_1 8: aload_1 9: aload_0 10: invokedynamic #9, 0 15: invokevirtual #10 18: return CS Method Handle int foo()
  • 50.
    CallSite 50 private void doStuff(); descriptor:()V flags: ACC_PRIVATE Code: stack=2, locals=2, args_size=1 0: new #7 3: dup 4: invokespecial #8 7: astore_1 8: aload_1 9: aload_0 10: invokedynamic #9, 0 15: invokevirtual #10 18: return CS int bar() int foo()
  • 51.
    CallSite Reifies Indy invocationside Has a MethodHandle 51
  • 52.
    Bootstrapping Step 1 52 privatevoid doStuff(); descriptor: ()V flags: ACC_PRIVATE Code: stack=2, locals=2, args_size=1 0: new #7 3: dup 4: invokespecial #8 7: astore_1 8: aload_1 9: aload_0 10: invokedynamic #9, 0 15: invokevirtual #10 18: return
  • 53.
    Bootstrapping Step 2 53 privatevoid doStuff(); descriptor: ()V flags: ACC_PRIVATE Code: stack=2, locals=2, args_size=1 0: new #7 3: dup 4: invokespecial #8 7: astore_1 8: aload_1 9: aload_0 10: invokedynamic #9, 0 15: invokevirtual #10 18: return BootStrap Method
  • 54.
    Bootstrapping Step 3 54 privatevoid doStuff(); descriptor: ()V flags: ACC_PRIVATE Code: stack=2, locals=2, args_size=1 0: new #7 3: dup 4: invokespecial #8 7: astore_1 8: aload_1 9: aload_0 10: invokedynamic #9, 0 15: invokevirtual #10 18: return BootStrap Method int foo()
  • 55.
    Bootstrapping Step 4 55 privatevoid doStuff(); descriptor: ()V flags: ACC_PRIVATE Code: stack=2, locals=2, args_size=1 0: new #7 3: dup 4: invokespecial #8 7: astore_1 8: aload_1 9: aload_0 10: invokedynamic #9, 0 15: invokevirtual #10 18: return BootStrap Method int foo() CS
  • 56.
    Bootstrapping Step 5 56 privatevoid doStuff(); descriptor: ()V flags: ACC_PRIVATE Code: stack=2, locals=2, args_size=1 0: new #7 3: dup 4: invokespecial #8 7: astore_1 8: aload_1 9: aload_0 10: invokedynamic #9, 0 15: invokevirtual #10 18: return int foo() CS
  • 57.
    Bootstrap Method Only calledon the first invocation of each indy bytecode Returns a CallSite 57 "Dr Martens, black, old" by Tarquin is licensed under CC BY-SA 3.0
  • 58.
    Indy lifecycle Initial Invocation 1.A specific indy invocation is executed for the first time 2. Bootstrap method is called and if finds (generates?!) a method to run 3. Bootstrap method returns a permanent CallSite object for this indy invocation 4. We jump to the method pointed to by the CallSite 58
  • 59.
    Indy Lifecycle All subsequentcalls We jump to the method pointed to by the CallSite 59 Picture from National Archives and Records Administration
  • 60.
    This performance tragedybecomes 60 Caller Reflection Magic! Callee
  • 61.
  • 62.
  • 63.
    Linkage != Invocation Linkage(i.e. bootstrap) Usually only needs to be done once Is expensive 63
  • 64.
    Linkage != Invocation Linkage(i.e. bootstrap) Usually only needs to be done once Is expensive Invocation Done a lot Only needs a jmp/call (and possibly a guard) 64
  • 65.
    Linkage != Invocation Avoidthe cost of linkage on almost every call 65
  • 66.
    • Mismatch betweenlanguage and bytecode • JDK <= 8 javac uses StringBuilder.append() • StringBuilder has performance issues • JDK >= 9 uses invoke dynamic Copyright © 2019 Oracle and/or its affiliates. String Concatenation
  • 67.
  • 68.
    Takeaways Invokedynamic lets usprogrammatically alter linkage 68
  • 69.
    Takeaways Invokedynamic lets usprogrammatically alter linkage Then it gets out of the way! (linkage != invocation) 69
  • 70.
    Takeaways Invokedynamic lets usprogrammatically alter linkage Then it gets out of the way! (linkage != invocation) The Invoke API can often be used without indy 70
  • 71.
    Takeaways Invokedynamic lets usprogrammatically alter linkage Then it gets out of the way! (linkage != invocation) The Invoke API can often be used without indy JVM is a great platform for just about any language! 71
  • 72.
    Resources JVM Language Summit http://openjdk.java.net/projects/mlvm/jvmlangsummit/ Linkers& Loaders book http://linker.iecc.com/ John Rose’s Blog https://blogs.oracle.com/jrose/ 72
  • 73.
  • 74.
    The preceding isintended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, timing, and pricing of any features or functionality described for Oracle’s products may change and remains at the sole discretion of Oracle Corporation. Statements in this presentation relating to Oracle’s future plans, expectations, beliefs, intentions and prospects are “forward-looking statements” and are subject to material risks and uncertainties. A detailed discussion of these factors and other risks that affect our business is contained in Oracle’s Securities and Exchange Commission (SEC) filings, including our most recent reports on Form 10-K and Form 10-Q under the heading “Risk Factors.” These filings are available on the SEC’s website or on Oracle’s website at http://www.oracle.com/investor. All information in this presentation is current as of September 2019 and Oracle undertakes no duty to update any statement in light of new information or future events. Safe Harbor Copyright © 2019 Oracle and/or its affiliates.