invokedynamic: Evolution of a Language Feature
-
Upload
danheidinga -
Category
Technology
-
view
408 -
download
0
Transcript of invokedynamic: Evolution of a Language Feature
![Page 1: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/1.jpg)
Evolution of a Language Feature
Dan Heidinga, J9 VM Interpreter Lead
@DanHeidinga
26 October 2015
Invokedynamic
Brian Goetz, Java Language Architect
Oracle
![Page 2: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/2.jpg)
Who am I?
I've been involved with virtual machine development at IBM
since 2007 and am now the J9 Virtual Machine Team Lead.
J9 is IBM's independent implementation of the JVM.
I've represented IBM on both the JSR 292 ('invokedynamic')
and JSR 335 ('lambda') expert groups and lead J9's
implementation of both JSRs.
I’ve also maintain the bytecode verifier and deal with various
other parts of the runtime.
2
![Page 3: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/3.jpg)
Who am I?
Brian Goetz is the Java Language Architect at Oracle, and is
one of the leading authorities on the Java platform.
He is the author of the very successful 'Java Concurrency in
Practice', and has published over 75 articles on software
development.
He was the specification lead for JSR-335 (Lambda
Expressions for the Java Language) and has served on
numerous other JCP Expert Groups.
3
![Page 4: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/4.jpg)
Important disclaimers
THE INFORMATION CONTAINED IN THIS PRESENTATION IS PROVIDED FOR INFORMATIONAL PURPOSES ONLY.
WHILST EFFORTS WERE MADE TO VERIFY THE COMPLETENESS AND ACCURACY OF THE INFORMATION
CONTAINED IN THIS PRESENTATION, IT IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED.
ALL PERFORMANCE DATA INCLUDED IN THIS PRESENTATION HAVE BEEN GATHERED IN A CONTROLLED
ENVIRONMENT. YOUR OWN TEST RESULTS MAY VARY BASED ON HARDWARE, SOFTWARE OR
INFRASTRUCTURE DIFFERENCES.
ALL DATA INCLUDED IN THIS PRESENTATION ARE MEANT TO BE USED ONLY AS A GUIDE.
IN ADDITION, THE INFORMATION CONTAINED IN THIS PRESENTATION IS BASED ON IBM’S CURRENT
PRODUCT PLANS AND STRATEGY, WHICH ARE SUBJECT TO CHANGE BY IBM, WITHOUT NOTICE.
IBM AND ITS AFFILIATED COMPANIES SHALL NOT BE RESPONSIBLE FOR ANY DAMAGES ARISING OUT
OF THE USE OF, OR OTHERWISE RELATED TO, THIS PRESENTATION OR ANY OTHER DOCUMENTATION.
NOTHING CONTAINED IN THIS PRESENTATION IS INTENDED TO, OR SHALL HAVE THE EFFECT OF:
– CREATING ANY WARRANT OR REPRESENTATION FROM IBM, ITS AFFILIATED COMPANIES OR ITS
OR THEIR SUPPLIERS AND/OR LICENSORS
4
![Page 5: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/5.jpg)
Danger: highly technical talk!
This talk assumes you’re familiar with:
– JVM bytecode set
– java.lang.invoke.MethodHandle and related classes
– invokedynamic
5
![Page 6: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/6.jpg)
Full bleed images preferredText over top of full bleed images would be in white or a color from the color palette that
would offer good contrast. Also, colored text in Arial Bold would have greater impact.
![Page 7: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/7.jpg)
JVM Specification, first edition
7
![Page 8: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/8.jpg)
JVM Specification, first edition
8
![Page 9: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/9.jpg)
The JVM: a highly tuned performance machine
https://commons.wikimedia.org/wiki/File:Fernando_Alonso_2010_Jerez_test_14.jpg9
![Page 10: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/10.jpg)
It’s fastest when you stay on the pathJVM optimized and tuned for the Java language.
As long as the language maps cleanly to Java’s semantics, good perf is likely
10
![Page 11: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/11.jpg)
JVM invoke instructions
Prior to Java 7, there were 4 bytecodes to invoke methods:
– invokespecial: constructors, super calls, private methods
– invokevirtual: receiver based selection of instance methods
– invokestatic: static methods
– invokeinterface: interface based selection of instance methods
The semantics are tightly defined by the JVM spec
11
![Page 12: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/12.jpg)
12
ResolutionAccess checkingType constraintsSelection
![Page 13: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/13.jpg)
Ruby fib
Show Ruby fib and outline why it’s not the same as the Java version
13
def fib(x)
if x < 2
return x
end
return fib(x-2) + fib(x-1)
end
![Page 14: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/14.jpg)
Ruby fib
6 method sends for Ruby vs 2 for Java
14
def fib(x)
if x < 2
return x
end
return fib(x-2) + fib(x-1)
end
![Page 15: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/15.jpg)
JRuby: ~1.6 implementation
15
CachingCallSite DynamicMethod
@JRubyMethod(name = "+")
public IRubyObject op_plus(ThreadContext ctx, IRubyObject other)
{
if (other instanceof RubyFixnum) {
return addFixnum(ctx, (RubyFixnum)other);
}
return addOther(ctx, other);
}
![Page 16: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/16.jpg)
Second class performance citizen: Dynamic languages
Simulation overheads:
– Inlining depth limits
– Inlining bytecode size limits
– Reflection overhead
– Non-inlinable caching / Hashtable lookups
– Type mismatches: sharp types vs IRubyObject
Complexity
– Generating invokers at build time based on annotations
– Need to ensure the cache is correct
16
![Page 17: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/17.jpg)
JVM Specification, first edition
17
![Page 18: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/18.jpg)
Birth of JSR 292 EG
18
New JVM instruction, invokedynamic, designed to support the implementation of dynamically typed object oriented languages.
… investigate support for hotswapping
![Page 19: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/19.jpg)
The problem: linkage + typing
JVM invoke instructions are tightly tied to Java
– Linkage must match the JVM rules
My language uses different dispatch rules
– Metaclass
– Multiple dispatch
– Mixins
User’s need to control the linkage
19https://en.wikipedia.org/wiki/Burr_puzzle#/media/File:SixPartWoodKnot.jpg
![Page 20: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/20.jpg)
RestartMethodException & VM method cache
Invokedynamic
– like invokevirtual except:
arguments not required to match the method’s signature
support for “doesNotUnderstand” handler
– recursive lookup for method exactly matching descriptor
else call handler, which can:
implement the method & return result
pick a method and return it (via RestartMethodException)
> VM can cache the “restart” method
20
![Page 21: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/21.jpg)
From InvokeDynamic to target method
Invokedynamic Target method
21
User supplied
logic
Tell the VM what
method to link to
![Page 22: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/22.jpg)
From InvokeDynamic to target method
Invokedynamic
Static data:
Caller
Method name
Descriptor
Other data
Target method
22
User supplied
logic
Tell the VM what
method to link to
BootstrapMethod
![Page 23: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/23.jpg)
From InvokeDynamic to target method
Invokedynamic
java.lang.invoke.CallSite
Target method
23
User supplied
logic
Tell the VM what
method to link to
BootstrapMethod
![Page 24: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/24.jpg)
From InvokeDynamic to target method
Invokedynamic
java.lang.invoke.CallSite
Target method
24
User supplied
logic
Tell the VM what
method to link to
BootstrapMethod
![Page 25: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/25.jpg)
From InvokeDynamic to target method
Invokedynamic Target method
25
java.lang.invoke.CallSite
Indy is permanently linked to the CallSite (1 time)
Invocation of target method can occur many times
![Page 26: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/26.jpg)
Anatomy of a CallSite
26
CallSite
type
target
MethodType
(String)V
MethodHandle
link(String)V
![Page 27: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/27.jpg)
Anatomy of a CallSite
27
CallSite
type
target
MethodType
(String)V
MethodHandle
link(String)V
The link() handle does two things:1. It sets CallSite target2. Completes the call
![Page 28: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/28.jpg)
Anatomy of a CallSite
28
CallSite
type
target
MethodType
(String)V
MethodHandle
link(String)V
GuardWithTest
test
target
fallback
MethodHandle
Guard()boolean
MethodHandle
Method(String)V
![Page 29: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/29.jpg)
Invokedynamic: bytecode factory
Lazy constants
New semantics
New bytecodes
All these and more can be emulated using invokedynamic
– Bootstrap Method to link the CallSite
– Java code that implements the new operation
– Really the ultimate bytecode emulation tool
29
![Page 30: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/30.jpg)
Interface injection
A Class implements all the methods for an interface
Doesn’t declare it implements it
– How can we allow the interface invocation to proceed?
30
Foo foo = new Foo();if (foo instanceof Injected) {
Injected i = (Injected) foo;System.out.println(i.m());
}
instanceof
checkcast
invokeinterface
![Page 31: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/31.jpg)
Interface injection: 3 Bootstrap Methods
31
![Page 32: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/32.jpg)
Interface injection: 2 helpers
32
![Page 33: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/33.jpg)
Interface injection: bytecode
33
0: new #14 // class Foo
3: dup
4: invokespecial #15 // Method Foo."<init>":()V
7: astore_1
8: aload_1
9: invokedynamic #28, 0 // InvokeDynamic #0:instanceof:(LObject;)Z
14: ifeq 36
17: aload_1
18: invokedynamic #36, 0 // InvokeDynamic #1:checkcast:(LObject;)LInjected;
23: astore_2
24: getstatic #42 // Field System.out:LPrintStream;
27: aload_2
28: invokedynamic #50, 0 // InvokeDynamic #2:m:(LObject;)LString;
33: invokevirtual #56 // Method PrintStream.println:(LString;)V
36: return
BootstrapMethods:
0: #22 invokestatic Runtime.instanceOfBSM:(LLookup;LString;LMethodType;LClass;)LCallSite;
Method arguments:
#24 Injected
1: #32 invokestatic Runtime.checkcastBSM:(LLookup;LString;LMethodType;LClass;)LCallSite;
Method arguments:
#24 Injected
2: #46 invokestatic
Runtime.invokeinterfaceBSM:(LLookup;LString;LMethodType;Ljava/lang/Class;)LCallSite;
Method arguments:
#24 Injected
![Page 34: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/34.jpg)
[jsr-292-eg] our package name 01/06/2011
Invokedynamic is more than dynamic languages!
Lambda can be built on top of invokedynamic and MethodHandles
(Painfully) renamed the package from java.dyn to java.lang.invoke at development cutoff
34
![Page 35: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/35.jpg)
Birth of JSR 292 EG
35
New JVM instruction, invokedynamic, designed to support the implementation of dynamically typed object oriented languages.
… investigate support for hotswapping
![Page 36: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/36.jpg)
Wait, what is a dyn language anyway?
Static Dynamic
36
![Page 37: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/37.jpg)
Wait, what is a dyn language anyway?
Static Dynamic
37
Compile time
Runtime
![Page 38: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/38.jpg)
Wait, what is a dyn language anyway?
Static Dynamic
38
Compile time
Runtime
![Page 39: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/39.jpg)
Wait, what is a dyn language anyway?
Static
Typing
Dispatch
Dynamic
Binding
(Un)Loading
39
![Page 40: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/40.jpg)
Its not just for dynamic languages anymore
Java 8 gave us Lambda expressions
– But how do we compile this lambda?
40
Predicate<Person> pred = p -> p.age < minAge;
![Page 41: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/41.jpg)
Its not just for dynamic languages anymore
So, if indy is for dynamic languages, why is the Java compiler using it?
– All the types involved are static
– We can use indy to give us a dynamic code generation strategy
Generate inner classes?
Use method handles?
Use dynamic proxies?
Use VM-private APIs for constructing objects?
Indy lets us turn this choice into a pure implementation detail
– Separate from the binary representation
41
![Page 42: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/42.jpg)
Desugaring lambdas to methods
First, we desugar the lambda to a method
– Signature matches functional interface method
– Plus captured arguments prepended
– Simplest lambdas desugar to static methods
But some need access to receiver, and so are instance methods
42
Predicate<Person> pred = p -> p.age < minAge;
private static boolean lambda$1(int minAge, Person p) {
return p.age < minAge;
}
![Page 43: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/43.jpg)
Its not just for dynamic languages anymore
We use indy to embed a recipe for constructing a lambda, including
– The desugared implementation method (static)
– The functional interface we are converting to (static)
– Additional metadata, such as serialization information (static)
– Values captured from the lexical scope (dynamic)
The capture site is called the lambda factory
– Invoked with indy, returns an instance of the desired functional interface
– Subsequent captures bypass the (slow) linkage path
43
![Page 44: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/44.jpg)
Factories and metafactories
We generate an indy call site which, when called, returns the lambda
– This is the lambda factory
– Bootstrap for the lambda factory
selects the translation strategy
Bootstrap is called the lambda metafactory
Part of Java runtime
– Captured args passed
to lambda factory
44
list.removeIf(p -> p.age < minAge);
private static boolean lambda$1(int minAge, Person p) {
return p.getAge() >= minAge;
}
Predicate $p = indy[bootstrap=LambdaMetafactory,
staticargs=[Predicate, lambda$1],
dynargs=[minAge])
list.removeIf($p);
![Page 45: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/45.jpg)
Full bleed images preferredText over top of full bleed images would be in white or a color from the color palette that
would offer good contrast. Also, colored text in Arial Bold would have greater impact.
![Page 46: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/46.jpg)
Optimized String concat (JEP tbd)
46
String m(String a, int b) {
return a + "(" + b + ")";
}
java.lang.String m(java.lang.String, int);
0: new #2 // class StringBuilder
3: dup
4: invokespecial #3 // Method StringBuilder.<init>:()V
7: aload_1
8: invokevirtual #4 // Method StringBuilder.append:(LString;)LStringBuilder;
11: ldc #5 // String (
13: invokevirtual #4 // Method StringBuilder.append:(LString;)LStringBuilder;
16: iload_2
17: invokevirtual #6 // Method StringBuilder.append:(I)LStringBuilder;
20: ldc #7 // String )
22: invokevirtual #4 // Method StringBuilder.append:(LString;)LStringBuilder;
25: invokevirtual #8 // Method StringBuilder.toString:()LString;
28: areturn
http://openjdk.java.net/jeps/8085796
![Page 47: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/47.jpg)
Optimized String concat (JEP tbd)
47
String m(String a, int b) {
return a + "(" + b + ")";
}
java.lang.String m(java.lang.String, int);
0: aload_1
1: ldc #2 // String (
3: iload_2
4: ldc #3 // String )
6: invokedynamic #4, 0
// InvokeDynamic #0:stringConcat:(LString;LString;ILString;)LString;
11: areturn
BootstrapMethods:
0: #19 invokestatic StringConcatFactory.stringConcat:
(LMethodHandles$Lookup;LString;LMethodType;LString;[LObject;)LCallSite;
http://openjdk.java.net/jeps/8085796
![Page 48: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/48.jpg)
48
![Page 49: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/49.jpg)
Invoking Specialized Generic Static Methods
We need to capture the type argument at the callsite.
How does m access the type information at run-time?
class C {
static <any T> T m(T i) {…}
}
int i = C.<int>m(3);
![Page 50: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/50.jpg)
Embed specialized type information in the invokedynamic Callsite
Invoking Specialized Static Methods (cont’d)
7: iconst_38: invokedynamic #4, 0 // InvokeDynamic #0:m:(LFoo;I)V
BootstrapMethods:0: #26 invokestatic GenericMethodSpecializer.metafactory:
(LMethodHandles$Lookup;LString;LMethodType;[LObject;)LCallSite;Method arguments:#27 LC;#28 invokevirtual C.m:(LObject;)V#29 I
![Page 51: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/51.jpg)
51
![Page 52: invokedynamic: Evolution of a Language Feature](https://reader034.fdocuments.in/reader034/viewer/2022052606/58827b981a28ab24788b57a3/html5/thumbnails/52.jpg)
52
Legal Notice
IBM and the IBM logo are trademarks or registered trademarks of IBM Corporation, in the United States, other
countries or both.
Java and all Java-based marks, among others, are trademarks or registered trademarks of Oracle in the United
States, other countries or both.
Other company, product and service names may be trademarks or service marks of others.
THE INFORMATION DISCUSSED IN THIS PRESENTATION IS PROVIDED FOR INFORMATIONAL
PURPOSES ONLY. WHILE EFFORTS WERE MADE TO VERIFY THE COMPLETENESS AND
ACCURACY OF THE INFORMATION, IT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, AND IBM SHALL NOT BE RESPONSIBLE FOR ANY DAMAGES ARISING OUT
OF THE USE OF, OR OTHERWISE RELATED TO, SUCH INFORMATION. ANY INFORMATION
CONCERNING IBM'S PRODUCT PLANS OR STRATEGY IS SUBJECT TO CHANGE BY IBM WITHOUT
NOTICE.