Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
9a560075
D
dragonwell8_jdk
项目概览
openanolis
/
dragonwell8_jdk
通知
4
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_jdk
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
9a560075
编写于
11月 10, 2010
作者:
T
trims
浏览文件
操作
浏览文件
下载
差异文件
Merge
上级
78874f27
4305eb98
变更
30
隐藏空白更改
内联
并排
Showing
30 changed file
with
1428 addition
and
420 deletion
+1428
-420
src/share/classes/java/dyn/BootstrapMethod.java
src/share/classes/java/dyn/BootstrapMethod.java
+82
-0
src/share/classes/java/dyn/CallSite.java
src/share/classes/java/dyn/CallSite.java
+61
-59
src/share/classes/java/dyn/ClassValue.java
src/share/classes/java/dyn/ClassValue.java
+173
-0
src/share/classes/java/dyn/ConstantCallSite.java
src/share/classes/java/dyn/ConstantCallSite.java
+43
-0
src/share/classes/java/dyn/InvokeDynamic.java
src/share/classes/java/dyn/InvokeDynamic.java
+20
-11
src/share/classes/java/dyn/InvokeDynamicBootstrapError.java
src/share/classes/java/dyn/InvokeDynamicBootstrapError.java
+1
-5
src/share/classes/java/dyn/Linkage.java
src/share/classes/java/dyn/Linkage.java
+6
-24
src/share/classes/java/dyn/LinkagePermission.java
src/share/classes/java/dyn/LinkagePermission.java
+4
-9
src/share/classes/java/dyn/MethodHandle.java
src/share/classes/java/dyn/MethodHandle.java
+23
-9
src/share/classes/java/dyn/MethodHandleProvider.java
src/share/classes/java/dyn/MethodHandleProvider.java
+80
-0
src/share/classes/java/dyn/MethodHandles.java
src/share/classes/java/dyn/MethodHandles.java
+166
-37
src/share/classes/java/dyn/MethodType.java
src/share/classes/java/dyn/MethodType.java
+26
-10
src/share/classes/java/dyn/NoAccessException.java
src/share/classes/java/dyn/NoAccessException.java
+1
-1
src/share/classes/java/dyn/package-info.java
src/share/classes/java/dyn/package-info.java
+174
-18
src/share/classes/sun/dyn/BoundMethodHandle.java
src/share/classes/sun/dyn/BoundMethodHandle.java
+0
-51
src/share/classes/sun/dyn/CallSiteImpl.java
src/share/classes/sun/dyn/CallSiteImpl.java
+23
-12
src/share/classes/sun/dyn/FilterGeneric.java
src/share/classes/sun/dyn/FilterGeneric.java
+3
-7
src/share/classes/sun/dyn/FilterOneArgument.java
src/share/classes/sun/dyn/FilterOneArgument.java
+12
-5
src/share/classes/sun/dyn/FromGeneric.java
src/share/classes/sun/dyn/FromGeneric.java
+3
-9
src/share/classes/sun/dyn/Invokers.java
src/share/classes/sun/dyn/Invokers.java
+6
-6
src/share/classes/sun/dyn/JavaMethodHandle.java
src/share/classes/sun/dyn/JavaMethodHandle.java
+2
-67
src/share/classes/sun/dyn/MemberName.java
src/share/classes/sun/dyn/MemberName.java
+6
-1
src/share/classes/sun/dyn/MethodHandleImpl.java
src/share/classes/sun/dyn/MethodHandleImpl.java
+19
-20
src/share/classes/sun/dyn/MethodHandleNatives.java
src/share/classes/sun/dyn/MethodHandleNatives.java
+19
-15
src/share/classes/sun/dyn/SpreadGeneric.java
src/share/classes/sun/dyn/SpreadGeneric.java
+1
-5
src/share/classes/sun/dyn/ToGeneric.java
src/share/classes/sun/dyn/ToGeneric.java
+1
-5
src/share/classes/sun/dyn/util/ValueConversions.java
src/share/classes/sun/dyn/util/ValueConversions.java
+33
-13
test/java/dyn/ClassValueTest.java
test/java/dyn/ClassValueTest.java
+164
-0
test/java/dyn/JavaDocExamples.java
test/java/dyn/JavaDocExamples.java
+128
-0
test/java/dyn/MethodHandlesTest.java
test/java/dyn/MethodHandlesTest.java
+148
-21
未找到文件。
src/share/classes/java/dyn/BootstrapMethod.java
0 → 100644
浏览文件 @
9a560075
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package
java.dyn
;
import
java.lang.annotation.*
;
/**
* Annotation on InvokeDynamic method calls which requests the JVM to use a specific
* <a href="package-summary.html#bsm">bootstrap method</a>
* to link the call. This annotation is not retained as such in the class file,
* but is transformed into a constant-pool entry for the invokedynamic instruction which
* specifies the desired bootstrap method.
* <p>
* If only the <code>value</code> is given, it must name a subclass of {@link CallSite}
* with a constructor which accepts a class, string, and method type.
* If the <code>value</code> and <code>name</code> are both given, there must be
* a static method in the given class of the given name which accepts a class, string,
* and method type, and returns a reference coercible to {@link CallSite}.
* <p>
* This annotation can be placed either on the return type of a single {@link InvokeDynamic}
* call (see examples) or else it can be placed on an enclosing class or method, where it
* determines a default bootstrap method for any {@link InvokeDynamic} calls which are not
* specifically annotated with a bootstrap method.
* Every {@link InvokeDynamic} call must be given a bootstrap method.
* <p>
* Examples:
<blockquote><pre>
@BootstrapMethod(value=MyLanguageRuntime.class, name="bootstrapDynamic")
String x = (String) InvokeDynamic.greet();
//BSM => MyLanguageRuntime.bootstrapDynamic(Here.class, "greet", methodType(String.class))
@BootstrapMethod(MyCallSite.class)
void example() throws Throwable {
InvokeDynamic.greet();
//BSM => new MyCallSite(Here.class, "greet", methodType(void.class))
}
</pre></blockquote>
* <p>
*/
@Target
({
ElementType
.
TYPE_USE
,
// For defaulting every indy site within a class or method; cf. @SuppressWarnings:
ElementType
.
TYPE
,
ElementType
.
METHOD
,
ElementType
.
CONSTRUCTOR
})
@Retention
(
RetentionPolicy
.
SOURCE
)
public
@interface
BootstrapMethod
{
/** The class containing the bootstrap method. */
Class
<?>
value
();
/** The name of the bootstrap method.
* If this is the empty string, an instance of the bootstrap class is created,
* and a constructor is invoked.
* Otherwise, there must be a static method of the required name.
*/
String
name
()
default
""
;
// empty string denotes a constructor with 'new'
/** The argument types of the bootstrap method, as passed out by the JVM.
* There is usually no reason to override the default.
*/
Class
<?>[]
arguments
()
default
{
Class
.
class
,
String
.
class
,
MethodType
.
class
};
}
src/share/classes/java/dyn/CallSite.java
浏览文件 @
9a560075
...
...
@@ -25,56 +25,26 @@
package
java.dyn
;
import
sun.dyn.Access
;
import
sun.dyn.MemberName
;
import
sun.dyn.CallSiteImpl
;
import
sun.dyn.*
;
import
java.util.Collection
;
/**
* A {@code CallSite} reifies an {@code invokedynamic} instruction from bytecode,
* and controls its linkage.
* Every linked {@code CallSite} object corresponds to a distinct instance
* of the {@code invokedynamic} instruction, and vice versa.
* A {@code CallSite} is a holder for a variable {@link MethodHandle},
* which is called its {@code target}.
* Every call to a {@code CallSite} is delegated to the site's current target.
* <p>
*
Every linked {@code CallSite} object has one state variabl
e,
*
a {@link MethodHandle} reference called the {@code target}
.
*
This reference is never null. Though it can change its value
*
successive values must always have exactly the {@link MethodType method type}
*
called for by the bytecodes of the associated {@code invokedynamic} instruction
*
A call site is initially created in an <em>unlinked</em> stat
e,
*
which is distinguished by a null target variable
.
*
Before the call site may be invoked (and before certain other
*
operations are attempted), the call site must be linked to
*
a non-null target.
* <p>
* It is the responsibility of each class's
* {@link Linkage#registerBootstrapMethod(Class, MethodHandle) bootstrap method}
* to produce call sites which have been pre-linked to an initial target method.
* The required {@link MethodType type} for the target method is a parameter
* to each bootstrap method call.
* <p>
* The bootstrap method may elect to produce call sites of a
* language-specific subclass of {@code CallSite}. In such a case,
* the subclass may claim responsibility for initializing its target to
* a non-null value, by overriding {@link #initialTarget}.
* <p>
* An {@code invokedynamic} instruction which has not yet been executed
* is said to be <em>unlinked</em>. When an unlinked call site is executed,
* the containing class's bootstrap method is called to manufacture a call site,
* for the instruction. If the bootstrap method does not assign a non-null
* value to the new call site's target variable, the method {@link #initialTarget}
* is called to produce the new call site's first target method.
* <p>
* A freshly-created {@code CallSite} object is not yet in a linked state.
* An unlinked {@code CallSite} object reports null for its {@code callerClass}.
* When the JVM receives a {@code CallSite} object from a bootstrap method,
* it first ensures that its target is non-null and of the correct type.
* The JVM then links the {@code CallSite} object to the call site instruction,
* enabling the {@code callerClass} to return the class in which the instruction occurs.
* <p>
* Next, the JVM links the instruction to the {@code CallSite}, at which point
* any further execution of the {@code invokedynamic} instruction implicitly
* invokes the current target of the {@code CallSite} object.
* After this two-way linkage, both the instruction and the {@code CallSite}
* object are said to be linked.
* <p>
* This state of linkage continues until the method containing the
* dynamic call site is garbage collected, or the dynamic call site
* is invalidated by an explicit request.
* A call site may be <em>relinked</em> by changing its target.
* The new target must be non-null and must have the same
* {@linkplain MethodHandle#type() type}
* as the previous target.
* Thus, though a call site can be relinked to a series of
* successive targets, it cannot change its type.
* <p>
* Linkage happens once in the lifetime of any given {@code CallSite} object.
* Because of call site invalidation, this linkage can be repeated for
...
...
@@ -87,6 +57,10 @@ import sun.dyn.CallSiteImpl;
* Here is a sample use of call sites and bootstrap methods which links every
* dynamic call site to print its arguments:
<blockquote><pre><!-- see indy-demo/src/PrintArgsDemo.java -->
@BootstrapMethod(value=PrintArgsDemo.class, name="bootstrapDynamic")
static void test() throws Throwable {
InvokeDynamic.baz("baz arg", 2, 3.14);
}
private static void printArgs(Object... args) {
System.out.println(java.util.Arrays.deepToString(args));
}
...
...
@@ -96,17 +70,16 @@ static {
Class thisClass = lookup.lookupClass(); // (who am I?)
printArgs = lookup.findStatic(thisClass,
"printArgs", MethodType.methodType(void.class, Object[].class));
Linkage.registerBootstrapMethod("bootstrapDynamic");
}
private static CallSite bootstrapDynamic(Class caller, String name, MethodType type) {
// ignore caller and name, but match the type:
return new CallSite(MethodHandles.collectArguments(printArgs, type));
}
</pre></blockquote>
* @see Linkage#registerBootstrapMethod(java.lang.Class, java.dyn.MethodHandle)
* @author John Rose, JSR 292 EG
*/
public
class
CallSite
implements
MethodHandleProvider
{
private
static
final
Access
IMPL_TOKEN
=
Access
.
getToken
();
...
...
@@ -209,6 +182,7 @@ public class CallSite
* {@code InvokeDynamicBootstrapError}, which in turn causes the
* linkage of the {@code invokedynamic} instruction to terminate
* abnormally.
* @deprecated transitional form defined in EDR but removed in PFD
*/
protected
MethodHandle
initialTarget
(
Class
<?>
callerClass
,
String
name
,
MethodType
type
)
{
throw
new
InvokeDynamicBootstrapError
(
"target must be initialized before call site is linked: "
+
name
+
type
);
...
...
@@ -278,16 +252,44 @@ public class CallSite
*/
@Override
public
String
toString
()
{
StringBuilder
buf
=
new
StringBuilder
(
"CallSite#"
);
buf
.
append
(
hashCode
());
if
(!
isLinked
())
buf
.
append
(
"[unlinked]"
);
else
buf
.
append
(
"["
)
.
append
(
"from "
).
append
(
vmmethod
.
getDeclaringClass
().
getName
())
.
append
(
" : "
).
append
(
getTarget
().
type
())
.
append
(
" => "
).
append
(
getTarget
())
.
append
(
"]"
);
return
buf
.
toString
();
return
"CallSite"
+(
target
==
null
?
""
:
target
.
type
());
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle equivalent to an invokedynamic instruction
* which has been linked to this call site.
* <p>If this call site is a {@link ConstantCallSite}, this method
* simply returns the call site's target, since that will not change.
* <p>Otherwise, this method is equivalent to the following code:
* <p><blockquote><pre>
* MethodHandle getTarget, invoker, result;
* getTarget = MethodHandles.lookup().bind(this, "getTarget", MethodType.methodType(MethodHandle.class));
* invoker = MethodHandles.exactInvoker(this.type());
* result = MethodHandles.foldArguments(invoker, getTarget)
* </pre></blockquote>
* @return a method handle which always invokes this call site's current target
*/
public
final
MethodHandle
dynamicInvoker
()
{
if
(
this
instanceof
ConstantCallSite
)
return
getTarget
();
// will not change dynamically
MethodHandle
getTarget
=
MethodHandleImpl
.
bindReceiver
(
IMPL_TOKEN
,
GET_TARGET
,
this
);
MethodHandle
invoker
=
MethodHandles
.
exactInvoker
(
this
.
type
());
return
MethodHandles
.
foldArguments
(
invoker
,
getTarget
);
}
private
static
final
MethodHandle
GET_TARGET
;
static
{
try
{
GET_TARGET
=
MethodHandles
.
Lookup
.
IMPL_LOOKUP
.
findVirtual
(
CallSite
.
class
,
"getTarget"
,
MethodType
.
methodType
(
MethodHandle
.
class
));
}
catch
(
NoAccessException
ignore
)
{
throw
new
InternalError
();
}
}
/** Implementation of {@link MethodHandleProvider} which returns {@code this.dynamicInvoker()}. */
public
final
MethodHandle
asMethodHandle
()
{
return
dynamicInvoker
();
}
/** Implementation of {@link MethodHandleProvider}, which returns {@code this.dynamicInvoker().asType(type)}. */
public
final
MethodHandle
asMethodHandle
(
MethodType
type
)
{
return
dynamicInvoker
().
asType
(
type
);
}
}
src/share/classes/java/dyn/ClassValue.java
0 → 100644
浏览文件 @
9a560075
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package
java.dyn
;
import
java.util.WeakHashMap
;
import
java.util.concurrent.atomic.AtomicInteger
;
import
java.util.concurrent.atomic.AtomicReference
;
/**
* Lazily associate a computed value with (potentially) every class.
* @author John Rose, JSR 292 EG
*/
public
abstract
class
ClassValue
<
T
>
{
/**
* Compute the given class's derived value for this {@code ClassValue}.
* <p>
* This method will be invoked within the first thread that accesses
* the value with the {@link #get}.
* <p>
* Normally, this method is invoked at most once per class,
* but it may be invoked again in case of subsequent invocations
* of {@link #remove} followed by {@link #get}.
*
* @return the computed value for this thread-local
*/
protected
abstract
T
computeValue
(
Class
<?>
type
);
/**
* Creates a new class value.
*/
protected
ClassValue
()
{
}
/**
* Returns the value for the given class.
* If no value has yet been computed, it is obtained by
* by an invocation of the {@link #computeValue} method.
* <p>
* The actual installation of the value on the class
* is performed while the class's synchronization lock
* is held. At that point, if racing threads have
* computed values, one is chosen, and returned to
* all the racing threads.
*
* @return the current thread's value of this thread-local
*/
public
T
get
(
Class
<?>
type
)
{
ClassValueMap
map
=
getMap
(
type
);
if
(
map
!=
null
)
{
Object
x
=
map
.
get
(
this
);
if
(
x
!=
null
)
{
return
(
T
)
map
.
unmaskNull
(
x
);
}
}
return
setComputedValue
(
type
);
}
/**
* Removes the associated value for the given class.
* If this value is subsequently {@linkplain #get read} for the same class,
* its value will be reinitialized by invoking its {@link #computeValue} method.
* This may result in an additional invocation of the
* {@code computeValue} method for the given class.
*/
public
void
remove
(
Class
<?>
type
)
{
ClassValueMap
map
=
getMap
(
type
);
if
(
map
!=
null
)
{
synchronized
(
map
)
{
map
.
remove
(
this
);
}
}
}
/// Implementation...
/** The hash code for this type is based on the identity of the object,
* and is well-dispersed for power-of-two tables.
*/
public
final
int
hashCode
()
{
return
hashCode
;
}
private
final
int
hashCode
=
HASH_CODES
.
getAndAdd
(
0x61c88647
);
private
static
final
AtomicInteger
HASH_CODES
=
new
AtomicInteger
();
private
static
final
AtomicInteger
STORE_BARRIER
=
new
AtomicInteger
();
/** Slow path for {@link #get}. */
private
T
setComputedValue
(
Class
<?>
type
)
{
ClassValueMap
map
=
getMap
(
type
);
if
(
map
==
null
)
{
map
=
initializeMap
(
type
);
}
T
value
=
computeValue
(
type
);
STORE_BARRIER
.
lazySet
(
0
);
// All stores pending from computeValue are completed.
synchronized
(
map
)
{
// Warm up the table with a null entry.
map
.
preInitializeEntry
(
this
);
}
// All stores pending from table expansion are completed.
synchronized
(
map
)
{
value
=
(
T
)
map
.
initializeEntry
(
this
,
value
);
// One might fear a possible race condition here
// if the code for map.put has flushed the write
// to map.table[*] before the writes to the Map.Entry
// are done. This is not possible, since we have
// warmed up the table with an empty entry.
}
return
value
;
}
// Replace this map by a per-class slot.
private
static
final
WeakHashMap
<
Class
<?>,
ClassValueMap
>
ROOT
=
new
WeakHashMap
<
Class
<?>,
ClassValueMap
>();
private
static
ClassValueMap
getMap
(
Class
<?>
type
)
{
return
ROOT
.
get
(
type
);
}
private
static
ClassValueMap
initializeMap
(
Class
<?>
type
)
{
synchronized
(
ClassValue
.
class
)
{
ClassValueMap
map
=
ROOT
.
get
(
type
);
if
(
map
==
null
)
ROOT
.
put
(
type
,
map
=
new
ClassValueMap
());
return
map
;
}
}
static
class
ClassValueMap
extends
WeakHashMap
<
ClassValue
,
Object
>
{
/** Make sure this table contains an Entry for the given key, even if it is empty. */
void
preInitializeEntry
(
ClassValue
key
)
{
if
(!
this
.
containsKey
(
key
))
this
.
put
(
key
,
null
);
}
/** Make sure this table contains a non-empty Entry for the given key. */
Object
initializeEntry
(
ClassValue
key
,
Object
value
)
{
Object
prior
=
this
.
get
(
key
);
if
(
prior
!=
null
)
{
return
unmaskNull
(
prior
);
}
this
.
put
(
key
,
maskNull
(
value
));
return
value
;
}
Object
maskNull
(
Object
x
)
{
return
x
==
null
?
this
:
x
;
}
Object
unmaskNull
(
Object
x
)
{
return
x
==
this
?
null
:
x
;
}
}
}
src/share/classes/java/dyn/ConstantCallSite.java
0 → 100644
浏览文件 @
9a560075
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package
java.dyn
;
/**
* A {@code ConstantCallSite} is a {@link CallSite} whose target is permanent, and can never be changed.
* The only way to relink an {@code invokedynamic} instruction bound to a {@code ConstantCallSite} is
* to invalidate the instruction as a whole.
* @author John Rose, JSR 292 EG
*/
public
class
ConstantCallSite
extends
CallSite
{
/** Create a call site with a permanent target. */
public
ConstantCallSite
(
MethodHandle
target
)
{
super
(
target
);
}
/** Throw an {@link IllegalArgumentException}, because this kind of call site cannot change its target. */
@Override
public
final
void
setTarget
(
MethodHandle
ignore
)
{
throw
new
IllegalArgumentException
(
"ConstantCallSite"
);
}
}
src/share/classes/java/dyn/InvokeDynamic.java
浏览文件 @
9a560075
...
...
@@ -35,7 +35,7 @@ package java.dyn;
* The target method is a property of the reified {@linkplain CallSite call site object}
* which is linked to each active {@code invokedynamic} instruction.
* The call site object is initially produced by a
* {@linkplain
java.dyn.Linkage#registerBootstrapMethod(Class, MethodHandle)
bootstrap method}
* {@linkplain
BootstrapMethod
bootstrap method}
* associated with the class whose bytecodes include the dynamic call site.
* <p>
* The type {@code InvokeDynamic} has no particular meaning as a
...
...
@@ -45,22 +45,31 @@ package java.dyn;
* It may be imported for ease of use.
* <p>
* Here are some examples:
* <p><blockquote><pre>
* Object x; String s; int i;
* x = InvokeDynamic.greet("world"); // greet(Ljava/lang/String;)Ljava/lang/Object;
* s = InvokeDynamic.<String>hail(x); // hail(Ljava/lang/Object;)Ljava/lang/String;
* InvokeDynamic.<void>cogito(); // cogito()V
* i = InvokeDynamic.<int>#"op:+"(2, 3); // "op:+"(II)I
* </pre></blockquote>
<blockquote><pre><!-- see indy-demo/src/JavaDocExamples.java -->
@BootstrapMethod(value=Here.class, name="bootstrapDynamic")
static void example() throws Throwable {
Object x; String s; int i;
x = InvokeDynamic.greet("world"); // greet(Ljava/lang/String;)Ljava/lang/Object;
s = (String) InvokeDynamic.hail(x); // hail(Ljava/lang/Object;)Ljava/lang/String;
InvokeDynamic.cogito(); // cogito()V
i = (int) InvokeDynamic.#"op:+"(2, 3); // "op:+"(II)I
}
static MethodHandle bootstrapDynamic(Class caller, String name, MethodType type) { ... }
</pre></blockquote>
* Each of the above calls generates a single invokedynamic instruction
* with the name-and-type descriptors indicated in the comments.
* <p>
* The argument types are taken directly from the actual arguments,
* while the return type is taken from the type parameter.
* (This type parameter may be a primtive, and it defaults to {@code Object}.)
* while the return type corresponds to the target of the assignment.
* (Currently, the return type must be given as a false type parameter.
* This type parameter is an irregular use of the generic type syntax,
* and is likely to change in favor of a convention based on target typing.)
* <p>
* The final example uses a special syntax for uttering non-Java names.
* Any name legal to the JVM may be given between the double quotes.
* <p>
* None of these calls is complete without a bootstrap method,
* which must be
registered by the static initializer of the enclosing class
.
* which must be
declared for the enclosing class or method
.
* @author John Rose, JSR 292 EG
*/
@MethodHandle
.
PolymorphicSignature
...
...
src/share/classes/java/dyn/InvokeDynamicBootstrapError.java
浏览文件 @
9a560075
...
...
@@ -28,15 +28,11 @@ package java.dyn;
/**
* Thrown to indicate that an {@code invokedynamic} instruction has
* failed to find its
* {@linkplain
Linkage#registerBootstrapMethod(Class, MethodHandle)
bootstrap method},
* {@linkplain
BootstrapMethod
bootstrap method},
* or the bootstrap method has
* failed to provide a
* {@linkplain CallSite} call site with a non-null {@linkplain MethodHandle target}
* of the correct {@linkplain MethodType method type}.
* <p>
* The bootstrap method must have been declared during a class's initialization
* by a call to one of the overloadings of
* {@link Linkage#registerBootstrapMethod registerBootstrapMethod}.
*
* @author John Rose, JSR 292 EG
* @since 1.7
...
...
src/share/classes/java/dyn/Linkage.java
浏览文件 @
9a560075
...
...
@@ -25,7 +25,6 @@
package
java.dyn
;
import
java.lang.annotation.Annotation
;
import
java.dyn.MethodHandles.Lookup
;
import
java.util.WeakHashMap
;
import
sun.dyn.Access
;
...
...
@@ -56,11 +55,7 @@ public class Linkage {
* <li>the class containing the {@code invokedynamic} instruction, for which the bootstrap method was registered
* <li>the name of the method being invoked (a {@link String})
* <li>the type of the method being invoked (a {@link MethodType})
* <li><em>TBD</em> optionally, an unordered array of {@link Annotation}s attached to the call site
* <em>(Until this feature is implemented, this will always receive an empty array.)</em>
* </ul>
* <em>(TBD: The final argument type may be missing from the method handle's type.
* Additional arguments may be added in the future.)</em>
* The bootstrap method acts as a factory method which accepts the given arguments
* and returns a {@code CallSite} object (possibly of a subclass of {@code CallSite}).
* <p>
...
...
@@ -86,6 +81,7 @@ public class Linkage {
* or is already running in another thread
* @exception SecurityException if there is a security manager installed,
* and a {@link LinkagePermission} check fails for "registerBootstrapMethod"
* @deprecated Use @{@link BootstrapMethod} annotations instead
*/
public
static
void
registerBootstrapMethod
(
Class
callerClass
,
MethodHandle
bootstrapMethod
)
{
...
...
@@ -97,14 +93,9 @@ public class Linkage {
static
private
void
checkBSM
(
MethodHandle
mh
)
{
if
(
mh
==
null
)
throw
newIllegalArgumentException
(
"null bootstrap method"
);
if
(
mh
.
type
()
==
BOOTSTRAP_METHOD_TYPE_2
)
// For now, always pass an empty array for the Annotations argument
mh
=
MethodHandles
.
insertArguments
(
mh
,
BOOTSTRAP_METHOD_TYPE_2
.
parameterCount
()-
1
,
(
Object
)
NO_ANNOTATIONS
);
if
(
mh
.
type
()
==
BOOTSTRAP_METHOD_TYPE
)
return
;
throw
new
WrongMethodTypeException
(
mh
.
toString
());
}
static
private
final
Annotation
[]
NO_ANNOTATIONS
=
{
};
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
...
...
@@ -115,6 +106,7 @@ public class Linkage {
* @throws NoSuchMethodException if there is no such method
* @throws IllegalStateException if the caller class's static initializer
* has already run, or is already running in another thread
* @deprecated Use @{@link BootstrapMethod} annotations instead
*/
public
static
void
registerBootstrapMethod
(
Class
<?>
runtime
,
String
name
)
{
...
...
@@ -131,6 +123,7 @@ public class Linkage {
* @throws IllegalArgumentException if there is no such method
* @throws IllegalStateException if the caller class's static initializer
* has already run, or is already running in another thread
* @deprecated Use @{@link BootstrapMethod} annotations instead
*/
public
static
void
registerBootstrapMethod
(
String
name
)
{
...
...
@@ -142,18 +135,10 @@ public class Linkage {
void
registerBootstrapMethodLookup
(
Class
<?>
callerClass
,
Class
<?>
runtime
,
String
name
)
{
Lookup
lookup
=
new
Lookup
(
IMPL_TOKEN
,
callerClass
);
MethodHandle
bootstrapMethod
;
// Try both types. TBD
try
{
bootstrapMethod
=
lookup
.
findStatic
(
runtime
,
name
,
BOOTSTRAP_METHOD_TYPE
_2
);
bootstrapMethod
=
lookup
.
findStatic
(
runtime
,
name
,
BOOTSTRAP_METHOD_TYPE
);
}
catch
(
NoAccessException
ex
)
{
bootstrapMethod
=
null
;
}
if
(
bootstrapMethod
==
null
)
{
try
{
bootstrapMethod
=
lookup
.
findStatic
(
runtime
,
name
,
BOOTSTRAP_METHOD_TYPE
);
}
catch
(
NoAccessException
ex
)
{
throw
new
IllegalArgumentException
(
"no such bootstrap method in "
+
runtime
+
": "
+
name
,
ex
);
}
throw
new
IllegalArgumentException
(
"no such bootstrap method in "
+
runtime
+
": "
+
name
,
ex
);
}
checkBSM
(
bootstrapMethod
);
MethodHandleImpl
.
registerBootstrap
(
IMPL_TOKEN
,
callerClass
,
bootstrapMethod
);
...
...
@@ -172,6 +157,7 @@ public class Linkage {
* and the immediate caller of this method is not in the same
* package as the caller class
* and a {@link LinkagePermission} check fails for "getBootstrapMethod"
* @deprecated
*/
public
static
MethodHandle
getBootstrapMethod
(
Class
callerClass
)
{
...
...
@@ -188,10 +174,6 @@ public class Linkage {
public
static
final
MethodType
BOOTSTRAP_METHOD_TYPE
=
MethodType
.
methodType
(
CallSite
.
class
,
Class
.
class
,
String
.
class
,
MethodType
.
class
);
static
final
MethodType
BOOTSTRAP_METHOD_TYPE_2
=
MethodType
.
methodType
(
CallSite
.
class
,
Class
.
class
,
String
.
class
,
MethodType
.
class
,
Annotation
[].
class
);
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
...
...
src/share/classes/java/dyn/LinkagePermission.java
浏览文件 @
9a560075
...
...
@@ -31,6 +31,7 @@ import java.util.Hashtable;
import
java.util.StringTokenizer
;
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* This class is for managing runtime permission checking for
* operations performed by methods in the {@link Linkage} class.
* Like a {@link RuntimePermission}, on which it is modeled,
...
...
@@ -52,13 +53,6 @@ import java.util.StringTokenizer;
* </tr>
*
* <tr>
* <td>registerBootstrapMethod.{class name}</td>
* <td>Specifying a bootstrap method for {@code invokedynamic} instructions within a class of the given name</td>
* <td>An attacker could attempt to attach a bootstrap method to a class which
* has just been loaded, thus gaining control of its {@code invokedynamic} calls.</td>
* </tr>
*
* <tr>
* <td>invalidateAll</td>
* <td>Force the relinking of invokedynamic call sites everywhere.</td>
* <td>This could allow an attacker to slow down the system,
...
...
@@ -73,8 +67,9 @@ import java.util.StringTokenizer;
* <td>See {@code invalidateAll}.</td>
* </tr>
* </table>
* <p>ISSUE: Is this still needed?
*
* @see java.
security
.RuntimePermission
* @see java.
lang
.RuntimePermission
* @see java.lang.SecurityManager
*
* @author John Rose, JSR 292 EG
...
...
@@ -86,7 +81,7 @@ public final class LinkagePermission extends BasicPermission {
/**
* Create a new LinkagePermission with the given name.
* The name is the symbolic name of the LinkagePermission, such as
* "
registerBootstrapMethod", "
invalidateCallerClass.*", etc. An asterisk
* "invalidateCallerClass.*", etc. An asterisk
* may appear at the end of the name, following a ".", or by itself, to
* signify a wildcard match.
*
...
...
src/share/classes/java/dyn/MethodHandle.java
浏览文件 @
9a560075
/*
* Copyright (c) 2008, 20
09
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 20
10
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
@@ -36,11 +36,13 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
/**
* A method handle is a typed, directly executable reference to a method,
* constructor, field, or similar low-level operation, with optional
* conversion or substitution of arguments or return values.
* transformations of arguments or return values.
* (These transformations include conversion, insertion, deletion,
* substitution. See the methods of this class and of {@link MethodHandles}.)
* <p>
* Method handles are strongly typed according to signature.
* They are not distinguished by method name or enclosing class.
* A method handle must be invoked under a signature which
exactly
matches
* A method handle must be invoked under a signature which matches
* the method handle's own {@link MethodType method type}.
* <p>
* Every method handle confesses its type via the {@code type} accessor.
...
...
@@ -174,9 +176,10 @@ assert(i == 3);
* merely a documentation convention. These type parameters do
* not play a role in type-checking method handle invocations.
* <p>
* Note: Like classes and strings, method handles that correspond directly
* to fields and methods can be represented directly as constants to be
* loaded by {@code ldc} bytecodes.
* Like classes and strings, method handles that correspond to accessible
* fields, methods, and constructors can be represented directly
* in a class file's constant pool as constants to be loaded by {@code ldc} bytecodes.
* Loading such a constant causes the component classes of its type to be loaded as necessary.
*
* @see MethodType
* @see MethodHandles
...
...
@@ -186,6 +189,7 @@ public abstract class MethodHandle
// Note: This is an implementation inheritance hack, and will be removed
// with a JVM change which moves the required hidden state onto this class.
extends
MethodHandleImpl
implements
MethodHandleProvider
{
private
static
Access
IMPL_TOKEN
=
Access
.
getToken
();
...
...
@@ -197,7 +201,7 @@ public abstract class MethodHandle
* those methods which are signature polymorphic.
*/
@java
.
lang
.
annotation
.
Target
({
java
.
lang
.
annotation
.
ElementType
.
METHOD
,
java
.
lang
.
annotation
.
ElementType
.
TYPE
})
@java
.
lang
.
annotation
.
Retention
(
java
.
lang
.
annotation
.
RetentionPolicy
.
CLASS
)
@java
.
lang
.
annotation
.
Retention
(
java
.
lang
.
annotation
.
RetentionPolicy
.
RUNTIME
)
@interface
PolymorphicSignature
{
}
private
MethodType
type
;
...
...
@@ -274,10 +278,14 @@ public abstract class MethodHandle
* and performing simple conversions for arguments and return types.
* The signature at the call site of {@code invokeGeneric} must
* have the same arity as this method handle's {@code type}.
* The same conversions are allowed on arguments or return values as are supported by
* by {@link MethodHandles#convertArguments}.
* <p>
* If the call site signature exactly matches this method handle's {@code type},
* the call proceeds as if by {@link #invokeExact}.
* <p>
* Otherwise, the call proceeds as if this method handle were first
* adjusted by calling {@link #asType} to adjust this method handle
* to the required type, and then the call proceeds as if by
* {@link #invokeExact} on the adjusted method handle.
*/
public
final
native
@PolymorphicSignature
<
R
,
A
>
R
invokeGeneric
(
A
...
args
)
throws
Throwable
;
...
...
@@ -538,4 +546,10 @@ public abstract class MethodHandle
public
final
MethodHandle
bindTo
(
Object
x
)
{
return
MethodHandles
.
insertArguments
(
this
,
0
,
x
);
}
/** Implementation of {@link MethodHandleProvider}, which returns {@code this}. */
public
final
MethodHandle
asMethodHandle
()
{
return
this
;
}
/** Implementation of {@link MethodHandleProvider}, which returns {@code this.asType(type)}. */
public
final
MethodHandle
asMethodHandle
(
MethodType
type
)
{
return
this
.
asType
(
type
);
}
}
src/share/classes/java/dyn/MethodHandleProvider.java
0 → 100644
浏览文件 @
9a560075
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package
java.dyn
;
/**
* An interface for an object to provide a target {@linkplain MethodHandle method handle} to a {@code invokedynamic} instruction.
* There are many function-like objects in various Java APIs.
* This interface provides a standard way for such function-like objects to be bound
* to a dynamic call site, by providing a view of their behavior in the form of a low-level method handle.
* <p>
* The type {@link MethodHandle} is a concrete class whose implementation
* hierarchy (if any) may be tightly coupled to the underlying JVM implementation.
* It cannot also serve as a base type for user-defined functional APIs.
* For this reason, {@code MethodHandle} cannot be subclassed to add new
* behavior to method handles. But this interface can be used to provide
* a link between a user-defined function and the {@code invokedynamic}
* instruction and the method handle API.
*/
public
interface
MethodHandleProvider
{
/** Produce a method handle which will serve as a behavioral proxy for the current object.
* The type and invocation behavior of the proxy method handle are user-defined,
* and should have some relation to the intended meaning of the original object itself.
* <p>
* The current object may have a changeable behavior.
* For example, {@link CallSite} has a {@code setTarget} method which changes its invocation.
* In such a case, it is <em>incorrect</em> for {@code asMethodHandle} to return
* a method handle whose behavior may diverge from that of the current object.
* Rather, the returned method handle must stably and permanently access
* the behavior of the current object, even if that behavior is changeable.
* <p>
* The reference identity of the proxy method handle is not guaranteed to
* have any particular relation to the reference identity of the object.
* In particular, several objects with the same intended meaning could
* share a common method handle, or the same object could return different
* method handles at different times. In the latter case, the different
* method handles should have the same type and invocation behavior,
* and be usable from any thread at any time.
* In particular, if a MethodHandleProvider is bound to an <code>invokedynamic</code>
* call site, the proxy method handle extracted at the time of binding
* will be used for an unlimited time, until the call site is rebound.
* <p>
* The type {@link MethodHandle} itself implements {@code MethodHandleProvider}, and
* for this method simply returns {@code this}.
*/
public
MethodHandle
asMethodHandle
();
/** Produce a method handle of a given type which will serve as a behavioral proxy for the current object.
* As for the no-argument version {@link #asMethodHandle()}, the invocation behavior of the
* proxy method handle is user-defined. But the type must be the given type,
* or else a {@link WrongMethodTypeException} must be thrown.
* <p>
* If the current object somehow represents a variadic or overloaded behavior,
* the method handle returned for a given type might represent only a subset of
* the current object's repertoire of behaviors, which correspond to that type.
*/
public
MethodHandle
asMethodHandle
(
MethodType
type
)
throws
WrongMethodTypeException
;
}
src/share/classes/java/dyn/MethodHandles.java
浏览文件 @
9a560075
...
...
@@ -25,15 +25,12 @@
package
java.dyn
;
import
java.lang.reflect.
Constructor
;
import
java.lang.reflect.
*
;
import
sun.dyn.Access
;
import
sun.dyn.MemberName
;
import
sun.dyn.MethodHandleImpl
;
import
sun.dyn.util.VerifyAccess
;
import
sun.dyn.util.Wrapper
;
import
java.lang.reflect.Field
;
import
java.lang.reflect.Method
;
import
java.lang.reflect.Modifier
;
import
java.util.List
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
...
...
@@ -81,6 +78,14 @@ public class MethodHandles {
* Return a {@link Lookup lookup object} which is trusted minimally.
* It can only be used to create method handles to
* publicly accessible fields and methods.
* <p>
* As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class}
* of this lookup object will be {@link java.lang.Object}.
* <p>
* The lookup class can be changed to any other class {@code C} using an expression of the form
* {@linkplain Lookup#in <code>publicLookup().in(C.class)</code>}.
* Since all classes have equal access to public names,
* such a change would confer no new access rights.
*/
public
static
Lookup
publicLookup
()
{
return
Lookup
.
PUBLIC_LOOKUP
;
...
...
@@ -90,9 +95,10 @@ public class MethodHandles {
* A <em>lookup object</em> is a factory for creating method handles,
* when the creation requires access checking.
* Method handles do not perform
* access checks when they are called; this is a major difference
* access checks when they are called, but rather when they are created.
* (This is a major difference
* from reflective {@link Method}, which performs access checking
* against every caller, on every call.
* against every caller, on every call.
)
* Therefore, method handle access
* restrictions must be enforced when a method handle is created.
* The caller class against which those restrictions are enforced
...
...
@@ -107,7 +113,7 @@ public class MethodHandles {
* It may then use this factory to create method handles on
* all of its methods, including private ones.
* It may also delegate the lookup (e.g., to a metaobject protocol)
* by passing the
{@code Lookup}
object to other code.
* by passing the
lookup
object to other code.
* If this other code creates method handles, they will be access
* checked against the original lookup class, and not with any higher
* privileges.
...
...
@@ -125,23 +131,28 @@ public class MethodHandles {
* It can also fail if a security manager is installed and refuses
* access. In any of these cases, an exception will be
* thrown from the attempted lookup.
* <p>
* In general, the conditions under which a method handle may be
* created for a method {@code M} are exactly as restrictive as the conditions
* under which the lookup class could have compiled a call to {@code M}.
* At least some of these error conditions are likely to be
* represented by checked exceptions in the final version of this API.
* This rule is applied even if the Java compiler might have created
* an wrapper method to access a private method of another class
* in the same top-level declaration.
* For example, a lookup object created for a nested class {@code C.D}
* can access private members within other related classes such as
* {@code C}, {@code C.D.E}, or {@code C.B}.
*/
public
static
final
class
Lookup
{
/** The class on behalf of whom the lookup is being performed. */
private
final
Class
<?>
lookupClass
;
/** The allowed sorts of members which may be looked up (public, etc.), with ST
RICT
for package. */
/** The allowed sorts of members which may be looked up (public, etc.), with ST
ATIC
for package. */
private
final
int
allowedModes
;
private
static
final
int
PUBLIC
=
Modifier
.
PUBLIC
,
PACKAGE
=
Modifier
.
ST
RICT
,
PACKAGE
=
Modifier
.
ST
ATIC
,
PROTECTED
=
Modifier
.
PROTECTED
,
PRIVATE
=
Modifier
.
PRIVATE
,
ALL_MODES
=
(
PUBLIC
|
PACKAGE
|
PROTECTED
|
PRIVATE
),
...
...
@@ -155,8 +166,10 @@ public class MethodHandles {
/** Which class is performing the lookup? It is this class against
* which checks are performed for visibility and access permissions.
* <p>
* This value is null if and only if this lookup was produced
* by {@link MethodHandles#publicLookup}.
* The class implies a maximum level of access permission,
* but the permissions may be additionally limited by the bitmask
* {@link #lookupModes}, which controls whether non-public members
* can be accessed.
*/
public
Class
<?>
lookupClass
()
{
return
lookupClass
;
...
...
@@ -168,10 +181,15 @@ public class MethodHandles {
}
/** Which types of members can this lookup object produce?
* The result is a bit-mask of the modifier bits PUBLIC, PROTECTED, PRIVATE, and STRICT.
* The modifier bit STRICT stands in for the (non-existent) package protection mode.
* The result is a bit-mask of the {@link Modifier} bits
* {@linkplain Modifier#PUBLIC PUBLIC (0x01)},
* {@linkplain Modifier#PROTECTED PROTECTED (0x02)},
* {@linkplain Modifier#PRIVATE PRIVATE (0x04)},
* and {@linkplain Modifier#STATIC STATIC (0x08)}.
* The modifier bit {@code STATIC} stands in for the package protection mode,
* which does not have an explicit modifier bit.
*/
int
lookupModes
()
{
public
int
lookupModes
()
{
return
allowedModes
&
ALL_MODES
;
}
...
...
@@ -621,32 +639,32 @@ public class MethodHandles {
/// Helper methods, all package-private.
MemberName
resolveOrFail
(
Class
<?>
refc
,
String
name
,
Class
<?>
type
,
boolean
isStatic
)
{
MemberName
resolveOrFail
(
Class
<?>
refc
,
String
name
,
Class
<?>
type
,
boolean
isStatic
)
throws
NoAccessException
{
checkSymbolicClass
(
refc
);
// do this before attempting to resolve
int
mods
=
(
isStatic
?
Modifier
.
STATIC
:
0
);
return
IMPL_NAMES
.
resolveOrFail
(
new
MemberName
(
refc
,
name
,
type
,
mods
),
true
,
lookupClassOrNull
());
}
MemberName
resolveOrFail
(
Class
<?>
refc
,
String
name
,
MethodType
type
,
boolean
isStatic
)
{
MemberName
resolveOrFail
(
Class
<?>
refc
,
String
name
,
MethodType
type
,
boolean
isStatic
)
throws
NoAccessException
{
checkSymbolicClass
(
refc
);
// do this before attempting to resolve
int
mods
=
(
isStatic
?
Modifier
.
STATIC
:
0
);
return
IMPL_NAMES
.
resolveOrFail
(
new
MemberName
(
refc
,
name
,
type
,
mods
),
true
,
lookupClassOrNull
());
}
MemberName
resolveOrFail
(
Class
<?>
refc
,
String
name
,
MethodType
type
,
boolean
isStatic
,
boolean
searchSupers
,
Class
<?>
specialCaller
)
{
boolean
searchSupers
,
Class
<?>
specialCaller
)
throws
NoAccessException
{
checkSymbolicClass
(
refc
);
// do this before attempting to resolve
int
mods
=
(
isStatic
?
Modifier
.
STATIC
:
0
);
return
IMPL_NAMES
.
resolveOrFail
(
new
MemberName
(
refc
,
name
,
type
,
mods
),
searchSupers
,
specialCaller
);
}
void
checkSymbolicClass
(
Class
<?>
refc
)
{
void
checkSymbolicClass
(
Class
<?>
refc
)
throws
NoAccessException
{
Class
<?>
caller
=
lookupClassOrNull
();
if
(
caller
!=
null
&&
!
VerifyAccess
.
isClassAccessible
(
refc
,
caller
))
throw
newNoAccessException
(
"symbolic reference class is not public"
,
new
MemberName
(
refc
),
caller
);
}
void
checkMethod
(
Class
<?>
refc
,
MemberName
m
,
boolean
wantStatic
)
{
void
checkMethod
(
Class
<?>
refc
,
MemberName
m
,
boolean
wantStatic
)
throws
NoAccessException
{
String
message
;
if
(
m
.
isConstructor
())
message
=
"expected a method, not a constructor"
;
...
...
@@ -659,7 +677,7 @@ public class MethodHandles {
throw
newNoAccessException
(
message
,
m
,
lookupClass
());
}
void
checkAccess
(
Class
<?>
refc
,
MemberName
m
)
{
void
checkAccess
(
Class
<?>
refc
,
MemberName
m
)
throws
NoAccessException
{
int
allowedModes
=
this
.
allowedModes
;
if
(
allowedModes
==
TRUSTED
)
return
;
int
mods
=
m
.
getModifiers
();
...
...
@@ -695,14 +713,14 @@ public class MethodHandles {
return
"member is private to package"
;
}
void
checkSpecialCaller
(
Class
<?>
specialCaller
)
{
void
checkSpecialCaller
(
Class
<?>
specialCaller
)
throws
NoAccessException
{
if
(
allowedModes
==
TRUSTED
)
return
;
if
(!
VerifyAccess
.
isSamePackageMember
(
specialCaller
,
lookupClass
()))
throw
newNoAccessException
(
"no private access for invokespecial"
,
new
MemberName
(
specialCaller
),
lookupClass
());
}
MethodHandle
restrictProtectedReceiver
(
MemberName
method
,
MethodHandle
mh
)
{
MethodHandle
restrictProtectedReceiver
(
MemberName
method
,
MethodHandle
mh
)
throws
NoAccessException
{
// The accessing class only has the right to use a protected member
// on itself or a subclass. Enforce that restriction, from JVMS 5.4.4, etc.
if
(!
method
.
isProtected
()
||
method
.
isStatic
()
...
...
@@ -712,7 +730,7 @@ public class MethodHandles {
else
return
restrictReceiver
(
method
,
mh
,
lookupClass
());
}
MethodHandle
restrictReceiver
(
MemberName
method
,
MethodHandle
mh
,
Class
<?>
caller
)
{
MethodHandle
restrictReceiver
(
MemberName
method
,
MethodHandle
mh
,
Class
<?>
caller
)
throws
NoAccessException
{
assert
(!
method
.
isStatic
());
Class
<?>
defc
=
method
.
getDeclaringClass
();
// receiver type of mh is too wide
if
(
defc
.
isInterface
()
||
!
defc
.
isAssignableFrom
(
caller
))
{
...
...
@@ -898,11 +916,16 @@ public class MethodHandles {
* @return a method handle which always invokes the call site's target
*/
public
static
MethodHandle
dynamicInvoker
(
CallSite
site
)
{
MethodHandle
dynamicInvoker
(
CallSite
site
)
throws
NoAccessException
{
MethodHandle
getCSTarget
=
GET_TARGET
;
if
(
getCSTarget
==
null
)
GET_TARGET
=
getCSTarget
=
Lookup
.
IMPL_LOOKUP
.
findVirtual
(
CallSite
.
class
,
"getTarget"
,
MethodType
.
methodType
(
MethodHandle
.
class
));
if
(
getCSTarget
==
null
)
{
try
{
GET_TARGET
=
getCSTarget
=
Lookup
.
IMPL_LOOKUP
.
findVirtual
(
CallSite
.
class
,
"getTarget"
,
MethodType
.
methodType
(
MethodHandle
.
class
));
}
catch
(
NoAccessException
ex
)
{
throw
new
InternalError
();
}
}
MethodHandle
getTarget
=
MethodHandleImpl
.
bindReceiver
(
IMPL_TOKEN
,
getCSTarget
,
site
);
MethodHandle
invoker
=
exactInvoker
(
site
.
type
());
return
foldArguments
(
invoker
,
getTarget
);
...
...
@@ -1260,17 +1283,20 @@ public class MethodHandles {
* <p>
* <b>Example:</b>
* <p><blockquote><pre>
* MethodHandle cat = MethodHandles.lookup().
* findVirtual(String.class, "concat", String.class, String.class);
* System.out.println(cat.<String>invokeExact("x", "y")); // xy
* import static java.dyn.MethodHandles.*;
* import static java.dyn.MethodType.*;
* ...
* MethodHandle cat = lookup().findVirtual(String.class,
* "concat", methodType(String.class, String.class));
* System.out.println((String) cat.invokeExact("x", "y")); // xy
* MethodHandle d0 = dropArguments(cat, 0, String.class);
* System.out.println(
d0.<String>invokeExact("x", "y", "z")); // xy
* System.out.println(
(String) d0.invokeExact("x", "y", "z")); // yz
* MethodHandle d1 = dropArguments(cat, 1, String.class);
* System.out.println(
d1.<String>
invokeExact("x", "y", "z")); // xz
* System.out.println(
(String) d1.
invokeExact("x", "y", "z")); // xz
* MethodHandle d2 = dropArguments(cat, 2, String.class);
* System.out.println(
d2.<String>invokeExact("x", "y", "z")); // yz
* MethodHandle d12 = dropArguments(cat, 1,
String.class, String
.class);
* System.out.println(
d12.<String>invokeExact("w", "x", "y", "z")); // w
z
* System.out.println(
(String) d2.invokeExact("x", "y", "z")); // xy
* MethodHandle d12 = dropArguments(cat, 1,
int.class, boolean
.class);
* System.out.println(
(String) d12.invokeExact("x", 12, true, "z")); // x
z
* </pre></blockquote>
* @param target the method handle to invoke after the argument is dropped
* @param valueTypes the type(s) of the argument to drop
...
...
@@ -1562,4 +1588,107 @@ public class MethodHandles {
MethodHandle
throwException
(
Class
<?>
returnType
,
Class
<?
extends
Throwable
>
exType
)
{
return
MethodHandleImpl
.
throwException
(
IMPL_TOKEN
,
MethodType
.
methodType
(
returnType
,
exType
));
}
/**
* Produce a wrapper instance of the given "SAM" type which redirects its calls to the given method handle.
* A SAM type is a type which declares a single abstract method.
* Additionally, it must have either no constructor (as an interface)
* or have a public or protected constructor of zero arguments (as a class).
* <p>
* The resulting instance of the required SAM type will respond to
* invocation of the SAM type's single abstract method by calling
* the given {@code target} on the incoming arguments,
* and returning or throwing whatever the {@code target}
* returns or throws. The invocation will be as if by
* {@code target.invokeExact}.
* <p>
* The method handle may throw an <em>undeclared exception</em>,
* which means any checked exception (or other checked throwable)
* not declared by the SAM type's single abstract method.
* If this happens, the throwable will be wrapped in an instance
* of {@link UndeclaredThrowableException} and thrown in that
* wrapped form.
* <p>
* The wrapper instance is guaranteed to be of a non-public
* implementation class C in a package containing no classes
* or methods except system-defined classes and methods.
* The implementation class C will have no public supertypes
* or public methods beyond the following:
* <ul>
* <li>the SAM type itself and any methods in the SAM type
* <li>the supertypes of the SAM type (if any) and their methods
* <li>{@link Object} and its methods
* <li>{@link MethodHandleProvider} and its methods
* </ul>
* <p>
* No stable mapping is promised between the SAM type and
* the implementation class C. Over time, several implementation
* classes might be used for the same SAM type.
* <p>
* This method is not guaranteed to return a distinct
* wrapper object for each separate call. If the JVM is able
* to prove that a wrapper has already been created for a given
* method handle, or for another method handle with the
* same behavior, the JVM may return that wrapper in place of
* a new wrapper.
* @param target the method handle to invoke from the wrapper
* @param samType the desired type of the wrapper, a SAM type
* @return a correctly-typed wrapper for the given {@code target}
* @throws IllegalArgumentException if the {@code target} throws
* an undeclared exception
*/
// ISSUE: Should we delegate equals/hashCode to the targets?
// Not useful unless there is a stable equals/hashCode behavior
// for MethodHandle, and for MethodHandleProvider.asMethodHandle.
public
static
<
T
>
T
asInstance
(
MethodHandle
target
,
Class
<
T
>
samType
)
{
// POC implementation only; violates the above contract several ways
final
Method
sam
=
getSamMethod
(
samType
);
if
(
sam
==
null
)
throw
new
IllegalArgumentException
(
"not a SAM type: "
+
samType
.
getName
());
MethodType
samMT
=
MethodType
.
methodType
(
sam
.
getReturnType
(),
sam
.
getParameterTypes
());
if
(!
samMT
.
equals
(
target
.
type
()))
throw
new
IllegalArgumentException
(
"wrong method type"
);
final
MethodHandle
mh
=
target
;
return
samType
.
cast
(
Proxy
.
newProxyInstance
(
samType
.
getClassLoader
(),
new
Class
[]{
samType
,
MethodHandleProvider
.
class
},
new
InvocationHandler
()
{
public
Object
invoke
(
Object
proxy
,
Method
method
,
Object
[]
args
)
throws
Throwable
{
if
(
method
.
getDeclaringClass
()
==
MethodHandleProvider
.
class
)
{
return
method
.
invoke
(
mh
,
args
);
}
assert
method
.
equals
(
sam
)
:
method
;
return
mh
.
invokeVarargs
(
args
);
}
}));
}
private
static
Method
getSamMethod
(
Class
<?>
samType
)
{
Method
sam
=
null
;
for
(
Method
m
:
samType
.
getMethods
())
{
int
mod
=
m
.
getModifiers
();
if
(
Modifier
.
isAbstract
(
mod
))
{
if
(
sam
!=
null
)
return
null
;
// too many abstract methods
sam
=
m
;
}
}
if
(!
samType
.
isInterface
()
&&
getSamConstructor
(
samType
)
==
null
)
return
null
;
// wrong kind of constructor
return
sam
;
}
private
static
Constructor
getSamConstructor
(
Class
<?>
samType
)
{
for
(
Constructor
c
:
samType
.
getDeclaredConstructors
())
{
if
(
c
.
getParameterTypes
().
length
==
0
)
{
int
mod
=
c
.
getModifiers
();
if
(
Modifier
.
isPublic
(
mod
)
||
Modifier
.
isProtected
(
mod
))
return
c
;
}
}
return
null
;
}
}
src/share/classes/java/dyn/MethodType.java
浏览文件 @
9a560075
...
...
@@ -40,24 +40,37 @@ import static sun.dyn.MemberName.newIllegalArgumentException;
* returned by a method handle, or the arguments and return type passed
* and expected by a method handle caller. Method types must be properly
* matched between a method handle and all its callers,
* and the JVM's operations enforce this matching at all times.
* and the JVM's operations enforce this matching at, specifically
* during calls to {@link MethodHandle#invokeExact}
* and {@link MethodHandle#invokeGeneric}, and during execution
* of {@code invokedynamic} instructions.
* <p>
* The structure is a return type accompanied by any number of parameter types.
* The types (primitive, void, and reference) are represented by Class objects.
* The types (primitive, {@code void}, and reference) are represented by {@link Class} objects.
* (For ease of exposition, we treat {@code void} as if it were a type.
* In fact, it denotes the absence of a return type.)
* <p>
* All instances of
<code>MethodType</code>
are immutable.
* All instances of
{@code MethodType}
are immutable.
* Two instances are completely interchangeable if they compare equal.
* Equality depends on pairwise correspondence of the return and parameter types and on nothing else.
* <p>
* This type can be created only by factory methods.
* All factory methods may cache values, though caching is not guaranteed.
* <p>
* Note: Like classes and strings, method types can be represented directly
* as constants to be loaded by {@code ldc} bytecodes.
* {@code MethodType} objects are sometimes derived from bytecode instructions
* such as {@code invokedynamic}, specifically from the type descriptor strings associated
* with the instructions in a class file's constant pool.
* When this occurs, any classes named in the descriptor strings must be loaded.
* (But they need not be initialized.)
* This loading may occur at any time before the {@code MethodType} object is first derived.
* <p>
* Like classes and strings, method types can be represented directly
* in a class file's constant pool as constants to be loaded by {@code ldc} bytecodes.
* Loading such a constant causes its component classes to be loaded as necessary.
* @author John Rose, JSR 292 EG
*/
public
final
class
MethodType
{
class
MethodType
implements
java
.
lang
.
reflect
.
Type
{
private
final
Class
<?>
rtype
;
private
final
Class
<?>[]
ptypes
;
private
MethodTypeForm
form
;
// erased form, plus cached data about primitives
...
...
@@ -636,11 +649,11 @@ class MethodType {
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* Find or create an instance of the given method type.
* Any class or interface name embedded in the
signature
string
* Any class or interface name embedded in the
descriptor
string
* will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)}
* on the given loader (or if it is null, on the system class loader).
* <p>
* Note that it is possible to
build
method types which cannot be
* Note that it is possible to
encounter
method types which cannot be
* constructed by this method, because their component types are
* not all reachable from a common class loader.
* <p>
...
...
@@ -662,8 +675,11 @@ class MethodType {
}
/**
* Create a bytecode signature representation of the type.
* Note that this is not a strict inverse of
* Create a bytecode descriptor representation of the method type.
* <p>
* Note that this is not a strict inverse of {@link #fromMethodDescriptorString}.
* Two distinct classes which share a common name but have different class loaders
* will appear identical when viewed within descriptor strings.
* <p>
* This method is included for the benfit of applications that must
* generate bytecodes that process method handles and invokedynamic.
...
...
src/share/classes/java/dyn/NoAccessException.java
浏览文件 @
9a560075
...
...
@@ -37,7 +37,7 @@ package java.dyn;
* @author John Rose, JSR 292 EG
* @since 1.7
*/
public
class
NoAccessException
extends
R
untime
Exception
{
public
class
NoAccessException
extends
R
eflectiveOperation
Exception
{
private
static
final
long
serialVersionUID
=
292L
;
/**
...
...
src/share/classes/java/dyn/package-info.java
浏览文件 @
9a560075
...
...
@@ -40,20 +40,18 @@
* The JVM links any such call (regardless of signature) to a dynamically
* typed method handle invocation. In the case of {@code invokeGeneric},
* argument and return value conversions are applied.
* </li>
*
* <li>In source code, the class {@link java.dyn.InvokeDynamic} appears to accept
* <li>In source code, the class {@link java.dyn.InvokeDynamic
InvokeDynamic
} appears to accept
* any static method invocation, of any name and any signature.
* But instead of emitting
* an {@code invokestatic} instruction for such a call, the Java compiler emits
* an {@code invokedynamic} instruction with the given name and signature.
*
* <li>When the JVM links an {@code invokedynamic} instruction, it calls the
* {@linkplain java.dyn.Linkage#registerBootstrapMethod(Class, MethodHandle) bootstrap method}
* of the containing class to obtain a {@linkplain java.dyn.CallSite call site} object through which
* the call site will link its target {@linkplain java.dyn.MethodHandle method handle}.
* </li>
*
* <li>The JVM bytecode format supports immediate constants of
* the classes {@link java.dyn.MethodHandle} and {@link java.dyn.MethodType}.
* the classes {@link java.dyn.MethodHandle MethodHandle} and {@link java.dyn.MethodType MethodType}.
* </li>
* </ul>
*
* <h2><a name="jvm_mods"></a>Corresponding JVM bytecode format changes</h2>
...
...
@@ -65,18 +63,50 @@
* The first byte is the opcode 186 (hexadecimal {@code BA}).
* The next two bytes are a constant pool index (in the same format as for the other {@code invoke} instructions).
* The final two bytes are reserved for future use and required to be zero.
* The constant pool reference is to a entry with tag {@code CONSTANT_NameAndType}
* (decimal 12). It is thus not a method reference of any sort, but merely
* the method name, argument types, and return type of the dynamic call site.
* <em>(TBD: The EG is discussing the possibility of a special constant pool entry type,
* so that other information may be added, such as a per-instruction bootstrap
* method and/or annotations.)</em>
* The constant pool reference of an {@code invokedynamic} instruction is to a entry
* with tag {@code CONSTANT_InvokeDynamic} (decimal 17). See below for its format.
* The entry specifies the bootstrap method (a {@link java.dyn.MethodHandle MethodHandle} constant),
* the dynamic invocation name, and the argument types and return type of the call.
* <p>
* Each instance of an {@code invokedynamic} instruction is called a <em>dynamic call site</em>.
* Multiple instances of an {@code invokedynamic} instruction can share a single
* {@code CONSTANT_InvokeDynamic} entry.
* In any case, distinct call sites always have distinct linkage state.
* <p>
* Moreover, for the purpose of distinguishing dynamic call sites,
* the JVM is allowed (but not required) to make internal copies
* of {@code invokedynamic} instructions, each one
* constituting a separate dynamic call site with its own linkage state.
* Such copying, if it occurs, cannot be observed except indirectly via
* execution of bootstrap methods and target methods.
* <p>
* A dynamic call site is originally in an unlinked state. In this state, there is
* no target method for the call site to invoke.
* A dynamic call site is linked by means of a bootstrap method,
* as <a href="#bsm">described below</a>.
* <p>
* <em>(Historic Note: Some older JVMs may allow the index of a {@code CONSTANT_NameAndType}
* instead of a {@code CONSTANT_InvokeDynamic}. In earlier, obsolete versions of this API, the
* bootstrap method was specified dynamically, in a per-class basis, during class initialization.)</em>
*
* <h3>constant pool entries for {@code invokedynamic} instructions</h3>
* If a constant pool entry has the tag {@code CONSTANT_InvokeDynamic} (decimal 17),
* it must contain exactly four more bytes.
* The first two bytes after the tag must be an index to a {@code CONSTANT_MethodHandle}
* entry, and the second two bytes must be an index to a {@code CONSTANT_NameAndType}.
* The first index specifies a bootstrap method used by the associated dynamic call sites.
* The second index specifies the method name, argument types, and return type of the dynamic call site.
* The structure of such an entry is therefore analogous to a {@code CONSTANT_Methodref},
* except that the {@code CONSTANT_Class} reference in a {@code CONSTANT_Methodref} entry
* is replaced by a bootstrap method reference.
*
* <h3>constant pool entries for {@code MethodType}s</h3>
* If a constant pool entry has the tag {@code CONSTANT_MethodType} (decimal 16),
* it must contain exactly two more bytes, which are an index to a {@code CONSTANT_Utf8}
* entry which represents a method type signature. The JVM will ensure that on first
* execution of an {@code ldc} instruction for this entry, a {@link java.dyn.MethodType}
* it must contain exactly two more bytes, which must be an index to a {@code CONSTANT_Utf8}
* entry which represents a method type signature.
* <p>
* The JVM will ensure that on first
* execution of an {@code ldc} instruction for this entry, a {@link java.dyn.MethodType MethodType}
* will be created which represents the signature.
* Any classes mentioned in the {@code MethodType} will be loaded if necessary,
* but not initialized.
...
...
@@ -86,12 +116,15 @@
* <h3>constant pool entries for {@code MethodHandle}s</h3>
* If a constant pool entry has the tag {@code CONSTANT_MethodHandle} (decimal 15),
* it must contain exactly three more bytes. The first byte after the tag is a subtag
* value
in the range 1 through 9, and the last two ar
e an index to a
* value
which must be in the range 1 through 9, and the last two must b
e an index to a
* {@code CONSTANT_Fieldref}, {@code CONSTANT_Methodref}, or
* {@code CONSTANT_InterfaceMethodref} entry which represents a field or method
* for which a method handle is to be created.
* Furthermore, the subtag value and the type of the constant index value
* must agree according to the table below.
* <p>
* The JVM will ensure that on first execution of an {@code ldc} instruction
* for this entry, a {@link java.dyn.MethodHandle} will be created which represents
* for this entry, a {@link java.dyn.MethodHandle
MethodHandle
} will be created which represents
* the field or method reference, according to the specific mode implied by the subtag.
* <p>
* As with {@code CONSTANT_Class} and {@code CONSTANT_MethodType} constants,
...
...
@@ -126,6 +159,129 @@
* Method handles for subtags {@code REF_getStatic}, {@code REF_putStatic}, and {@code REF_invokeStatic}
* may force class initialization on their first invocation, just like the corresponding bytecodes.
*
* <h2><a name="bsm"></a>Bootstrap Methods</h2>
* Before the JVM can execute a dynamic call site (an {@code invokedynamic} instruction),
* the call site must first be <em>linked</em>.
* Linking is accomplished by calling a <em>bootstrap method</em>
* which is given the static information content of the call site,
* and which must produce a {@link java.dyn.MethodHandle method handle}
* that gives the behavior of the call site.
* <p>
* Each {@code invokedynamic} instruction statically specifies its own
* bootstrap method as a constant pool reference.
* The constant pool reference also specifies the call site's name and type signature,
* just like {@code invokevirtual} and the other invoke instructions.
* <p>
* Linking starts with resolving the constant pool entry for the
* bootstrap method, and resolving a {@link java.dyn.MethodType MethodType} object for
* the type signature of the dynamic call site.
* This resolution process may trigger class loading.
* It may therefore throw an error if a class fails to load.
* This error becomes the abnormal termination of the dynamic
* call site execution.
* Linkage does not trigger class initialization.
* <p>
* Next, the bootstrap method call is started, with four values being stacked:
* <ul>
* <li>a {@code MethodHandle}, the resolved bootstrap method itself </li>
* <li>a {@code Class}, the <em>caller class</em> in which dynamic call site occurs </li>
* <li>a {@code String}, the method name mentioned in the call site </li>
* <li>a {@code MethodType}, the resolved type signature of the call </li>
* </ul>
* The method handle is then applied to the other values as if by
* {@linkplain java.dyn.MethodHandle#invokeGeneric the <code>invokeGeneric</code> method}.
* The returned result must be a {@link java.dyn.CallSite CallSite}, a {@link java.dyn.MethodHandle MethodHandle},
* or another {@link java.dyn.MethodHandleProvider MethodHandleProvider} value.
* The method {@linkplain java.dyn.MethodHandleProvider#asMethodHandle asMethodHandle}
* is then called on the returned value. The result of that second
* call is the {@code MethodHandle} which becomes the
* permanent binding for the dynamic call site.
* That method handle's type must be exactly equal to the type
* derived from the dynamic call site signature and passed to
* the bootstrap method.
* <p>
* After resolution, the linkage process may fail in a variety of ways.
* All failures are reported by an {@link java.dyn.InvokeDynamicBootstrapError InvokeDynamicBootstrapError},
* which is thrown as the abnormal termination of the dynamic call
* site execution.
* The following circumstances will cause this:
* <ul>
* <li>the bootstrap method invocation completes abnormally </li>
* <li>the result from the bootstrap invocation is not a reference to
* an object of type {@link java.dyn.MethodHandleProvider MethodHandleProvider} </li>
* <li>the call to {@code asMethodHandle} completes abnormally </li>
* <li>the call to {@code asMethodHandle} fails to return a reference to
* an object of type {@link java.dyn.MethodHandle MethodHandle} </li>
* <li>the method handle produced by {@code asMethodHandle} does not have
* the expected {@code MethodType} </li>
* </ul>
* <h3>timing of linkage</h3>
* A dynamic call site is linked just before its first execution.
* The bootstrap method call implementing the linkage occurs within
* a thread that is attempting a first execution.
* <p>
* If there are several such threads, the JVM picks one thread
* and runs the bootstrap method while the others wait for the
* invocation to terminate normally or abnormally.
* <p>
* After a bootstrap method is called and a method handle target
* successfully extracted, the JVM attempts to link the instruction
* being executed to the target method handle.
* This may fail if there has been intervening linkage
* or invalidation event for the same instruction.
* If such a failure occurs, the dynamic call site must be
* re-executed from the beginning, either re-linking it
* (if it has been invalidated) or invoking the target
* (if it the instruction has been linked by some other means).
* <p>
* If the instruction is linked successfully, the target method
* handle is invoked to complete the instruction execution.
* The state of linkage continues until the method containing the
* dynamic call site is garbage collected, or the dynamic call site
* is invalidated by an explicit request,
* such as {@link java.dyn.Linkage#invalidateCallerClass Linkage.invalidateCallerClass}.
* <p>
* In an application which requires dynamic call sites with individually
* mutable behaviors, their bootstrap methods should produce distinct
* {@link java.dyn.CallSite CallSite} objects, one for each linkage request.
* <p>
* If a class containing {@code invokedynamic} instructions
* is {@linkplain java.dyn.Linkage#invalidateCallerClass(Class) invalidated},
* subsequent execution of those {@code invokedynamic} instructions
* will require linking.
* It is as if they had never been executed in the first place.
* (However, invalidation does not cause constant pool entries to be
* resolved a second time.)
* <p>
* Invalidation events and bootstrap method calls for a particular
* dynamic call site are globally ordered relative to each other.
* When an invokedynamic instruction is invalidated, if there is
* simultaneously a bootstrap method invocation in process
* (in the same thread or a different thread), the result
* eventually returned must not be used to link the call site.
* Put another way, when a call site is invalidated, its
* subsequent linkage (if any) must be performed by a bootstrap method
* call initiated after the invalidation occurred.
* <p>
* If several threads simultaneously execute a bootstrap method for a single dynamic
* call site, the JVM must choose one target object and installs it visibly to
* all threads. Any other bootstrap method calls are allowed to complete, but their
* results are ignored, and their dynamic call site invocations proceed with the originally
* chosen target object.
* <p>
* The JVM is free to duplicate dynamic call sites.
* This means that, even if a class contains just one {@code invokedynamic}
* instruction, its bootstrap method may be executed several times,
* once for each duplicate. Thus, bootstrap method code should not
* assume an exclusive one-to-one correspondence between particular occurrences
* of {@code invokedynamic} bytecodes in class files and linkage events.
* <p>
* In principle, each individual execution of an {@code invokedynamic}
* instruction could be deemed (by a conforming implementation) to be a separate
* duplicate, requiring its own execution of the bootstrap method.
* However, implementations are expected to perform code duplication
* (if at all) in order to improve performance, not make it worse.
*
* @author John Rose, JSR 292 EG
*/
...
...
src/share/classes/sun/dyn/BoundMethodHandle.java
浏览文件 @
9a560075
...
...
@@ -48,8 +48,6 @@ public class BoundMethodHandle extends MethodHandle {
private
static
final
MemberName
.
Factory
IMPL_NAMES
=
MemberName
.
getFactory
(
IMPL_TOKEN
);
// Constructors in this class *must* be package scoped or private.
// Exception: JavaMethodHandle constructors are protected.
// (The link between JMH and BMH is temporary.)
/** Bind a direct MH to its receiver (or first ref. argument).
* The JVM will pre-dispatch the MH if it is not already static.
...
...
@@ -122,55 +120,6 @@ public class BoundMethodHandle extends MethodHandle {
assert
(
this
instanceof
JavaMethodHandle
);
}
/** Initialize the current object as a Java method handle.
*/
protected
BoundMethodHandle
(
String
entryPointName
,
MethodType
type
,
boolean
matchArity
)
{
super
(
Access
.
TOKEN
,
null
);
MethodHandle
entryPoint
=
findJavaMethodHandleEntryPoint
(
this
.
getClass
(),
entryPointName
,
type
,
matchArity
);
MethodHandleImpl
.
initType
(
this
,
entryPoint
.
type
().
dropParameterTypes
(
0
,
1
));
this
.
argument
=
this
;
// kludge; get rid of
this
.
vmargslot
=
this
.
type
().
parameterSlotDepth
(
0
);
initTarget
(
entryPoint
,
0
);
assert
(
this
instanceof
JavaMethodHandle
);
}
private
static
MethodHandle
findJavaMethodHandleEntryPoint
(
Class
<?>
caller
,
String
name
,
MethodType
type
,
boolean
matchArity
)
{
if
(
matchArity
)
type
.
getClass
();
// elicit NPE
List
<
MemberName
>
methods
=
IMPL_NAMES
.
getMethods
(
caller
,
true
,
name
,
null
,
caller
);
MethodType
foundType
=
null
;
MemberName
foundMethod
=
null
;
for
(
MemberName
method
:
methods
)
{
if
(
method
.
getDeclaringClass
()
==
MethodHandle
.
class
)
continue
;
// ignore methods inherited from MH class itself
MethodType
mtype
=
method
.
getMethodType
();
if
(
type
!=
null
&&
type
.
parameterCount
()
!=
mtype
.
parameterCount
())
continue
;
else
if
(
foundType
==
null
)
foundType
=
mtype
;
else
if
(
foundType
!=
mtype
)
throw
newIllegalArgumentException
(
"more than one method named "
+
name
+
" in "
+
caller
.
getName
());
// discard overrides
if
(
foundMethod
==
null
)
foundMethod
=
method
;
else
if
(
foundMethod
.
getDeclaringClass
().
isAssignableFrom
(
method
.
getDeclaringClass
()))
foundMethod
=
method
;
}
if
(
foundMethod
==
null
)
throw
newIllegalArgumentException
(
"no method named "
+
name
+
" in "
+
caller
.
getName
());
MethodHandle
entryPoint
=
MethodHandleImpl
.
findMethod
(
IMPL_TOKEN
,
foundMethod
,
true
,
caller
);
if
(
type
!=
null
)
{
MethodType
epType
=
type
.
insertParameterTypes
(
0
,
entryPoint
.
type
().
parameterType
(
0
));
entryPoint
=
MethodHandles
.
convertArguments
(
entryPoint
,
epType
);
}
return
entryPoint
;
}
/** Make sure the given {@code argument} can be used as {@code argnum}-th
* parameter of the given method handle {@code mh}, which must be a reference.
* <p>
...
...
src/share/classes/sun/dyn/CallSiteImpl.java
浏览文件 @
9a560075
...
...
@@ -26,6 +26,7 @@
package
sun.dyn
;
import
java.dyn.*
;
import
static
sun
.
dyn
.
MemberName
.
uncaughtException
;
/**
* Parts of CallSite known to the JVM.
...
...
@@ -49,18 +50,21 @@ public class CallSiteImpl {
}
CallSite
site
;
try
{
if
(
bootstrapMethod
.
type
().
parameterCount
()
==
3
)
site
=
bootstrapMethod
.<
CallSite
>
invokeExact
(
caller
,
name
,
type
);
else
if
(
bootstrapMethod
.
type
().
parameterCount
()
==
4
)
site
=
bootstrapMethod
.<
CallSite
>
invokeExact
(
caller
,
name
,
type
,
!(
info
instanceof
java
.
lang
.
annotation
.
Annotation
[])
?
null
:
(
java
.
lang
.
annotation
.
Annotation
[])
info
);
Object
binding
;
if
(
false
)
// switch when invokeGeneric works
binding
=
bootstrapMethod
.
invokeGeneric
(
caller
,
name
,
type
);
else
throw
new
InternalError
(
"bad BSM: "
+
bootstrapMethod
);
if
(!(
site
instanceof
CallSite
))
throw
new
InvokeDynamicBootstrapError
(
"class bootstrap method failed to create a call site: "
+
caller
);
PRIVATE_INITIALIZE_CALL_SITE
.<
void
>
invokeExact
(
site
,
name
,
type
,
binding
=
bootstrapMethod
.
invokeVarargs
(
new
Object
[]{
caller
,
name
,
type
});
//System.out.println("BSM for "+name+type+" => "+binding);
if
(
binding
instanceof
CallSite
)
{
site
=
(
CallSite
)
binding
;
}
else
if
(
binding
instanceof
MethodHandleProvider
)
{
MethodHandle
target
=
((
MethodHandleProvider
)
binding
).
asMethodHandle
();
site
=
new
ConstantCallSite
(
target
);
}
else
{
throw
new
ClassCastException
(
"bootstrap method failed to produce a MethodHandle or CallSite"
);
}
PRIVATE_INITIALIZE_CALL_SITE
.<
void
>
invokeExact
(
site
,
name
,
type
,
callerMethod
,
callerBCI
);
assert
(
site
.
getTarget
()
!=
null
);
assert
(
site
.
getTarget
().
type
().
equals
(
type
));
...
...
@@ -77,11 +81,18 @@ public class CallSiteImpl {
// This method is private in CallSite because it touches private fields in CallSite.
// These private fields (vmmethod, vmindex) are specific to the JVM.
private
static
final
MethodHandle
PRIVATE_INITIALIZE_CALL_SITE
=
private
static
final
MethodHandle
PRIVATE_INITIALIZE_CALL_SITE
;
static
{
try
{
PRIVATE_INITIALIZE_CALL_SITE
=
MethodHandleImpl
.
IMPL_LOOKUP
.
findVirtual
(
CallSite
.
class
,
"initializeFromJVM"
,
MethodType
.
methodType
(
void
.
class
,
String
.
class
,
MethodType
.
class
,
MemberName
.
class
,
int
.
class
));
}
catch
(
NoAccessException
ex
)
{
throw
uncaughtException
(
ex
);
}
}
public
static
void
setCallSiteTarget
(
Access
token
,
CallSite
site
,
MethodHandle
target
)
{
Access
.
check
(
token
);
...
...
src/share/classes/sun/dyn/FilterGeneric.java
浏览文件 @
9a560075
...
...
@@ -25,12 +25,8 @@
package
sun.dyn
;
import
java.dyn.JavaMethodHandle
;
import
java.dyn.MethodHandle
;
import
java.dyn.MethodType
;
import
java.dyn.NoAccessException
;
import
java.lang.reflect.Constructor
;
import
java.lang.reflect.InvocationTargetException
;
import
java.dyn.*
;
import
java.lang.reflect.*
;
import
static
sun
.
dyn
.
MemberName
.
newIllegalArgumentException
;
/**
...
...
@@ -119,7 +115,7 @@ class FilterGeneric {
static
MethodHandle
make
(
Kind
kind
,
int
pos
,
MethodHandle
filter
,
MethodHandle
target
)
{
FilterGeneric
fgen
=
of
(
kind
,
pos
,
filter
.
type
(),
target
.
type
());
return
fgen
.
makeInstance
(
kind
,
pos
,
filter
,
target
);
return
fgen
.
makeInstance
(
kind
,
pos
,
filter
,
target
)
.
asMethodHandle
()
;
}
/** Return the adapter information for this target and filter type. */
...
...
src/share/classes/sun/dyn/FilterOneArgument.java
浏览文件 @
9a560075
...
...
@@ -25,9 +25,8 @@
package
sun.dyn
;
import
java.dyn.JavaMethodHandle
;
import
java.dyn.MethodHandle
;
import
java.dyn.MethodType
;
import
java.dyn.*
;
import
static
sun
.
dyn
.
MemberName
.
uncaughtException
;
/**
* Unary function composition, useful for many small plumbing jobs.
...
...
@@ -51,8 +50,16 @@ public class FilterOneArgument extends JavaMethodHandle {
return
target
.
invokeExact
(
filteredArgument
);
}
private
static
final
MethodHandle
INVOKE
=
MethodHandleImpl
.
IMPL_LOOKUP
.
findVirtual
(
FilterOneArgument
.
class
,
"invoke"
,
MethodType
.
genericMethodType
(
1
));
private
static
final
MethodHandle
INVOKE
;
static
{
try
{
INVOKE
=
MethodHandleImpl
.
IMPL_LOOKUP
.
findVirtual
(
FilterOneArgument
.
class
,
"invoke"
,
MethodType
.
genericMethodType
(
1
));
}
catch
(
NoAccessException
ex
)
{
throw
uncaughtException
(
ex
);
}
}
protected
FilterOneArgument
(
MethodHandle
filter
,
MethodHandle
target
)
{
super
(
INVOKE
);
...
...
src/share/classes/sun/dyn/FromGeneric.java
浏览文件 @
9a560075
...
...
@@ -25,15 +25,9 @@
package
sun.dyn
;
import
java.dyn.JavaMethodHandle
;
import
java.dyn.MethodHandle
;
import
java.dyn.MethodHandles
;
import
java.dyn.MethodType
;
import
java.dyn.NoAccessException
;
import
java.lang.reflect.Constructor
;
import
java.lang.reflect.InvocationTargetException
;
import
sun.dyn.util.ValueConversions
;
import
sun.dyn.util.Wrapper
;
import
java.dyn.*
;
import
java.lang.reflect.*
;
import
sun.dyn.util.*
;
/**
* Adapters which mediate between incoming calls which are generic
...
...
src/share/classes/sun/dyn/Invokers.java
浏览文件 @
9a560075
...
...
@@ -25,10 +25,7 @@
package
sun.dyn
;
import
java.dyn.MethodHandle
;
import
java.dyn.MethodHandles
;
import
java.dyn.MethodType
;
import
java.dyn.*
;
/**
* Construction and caching of often-used invokers.
...
...
@@ -63,8 +60,11 @@ public class Invokers {
public
MethodHandle
exactInvoker
()
{
MethodHandle
invoker
=
exactInvoker
;
if
(
invoker
!=
null
)
return
invoker
;
invoker
=
MethodHandleImpl
.
IMPL_LOOKUP
.
findVirtual
(
MethodHandle
.
class
,
"invoke"
,
targetType
);
if
(
invoker
==
null
)
throw
new
InternalError
(
"JVM cannot find invoker for "
+
targetType
);
try
{
invoker
=
MethodHandleImpl
.
IMPL_LOOKUP
.
findVirtual
(
MethodHandle
.
class
,
"invoke"
,
targetType
);
}
catch
(
NoAccessException
ex
)
{
throw
new
InternalError
(
"JVM cannot find invoker for "
+
targetType
);
}
assert
(
invokerType
(
targetType
)
==
invoker
.
type
());
exactInvoker
=
invoker
;
return
invoker
;
...
...
src/share/classes/
java
/dyn/JavaMethodHandle.java
→
src/share/classes/
sun
/dyn/JavaMethodHandle.java
浏览文件 @
9a560075
...
...
@@ -23,8 +23,9 @@
* questions.
*/
package
java
.dyn
;
package
sun
.dyn
;
import
java.dyn.*
;
import
sun.dyn.Access
;
/**
...
...
@@ -168,70 +169,4 @@ public abstract class JavaMethodHandle
protected
JavaMethodHandle
(
MethodHandle
entryPoint
)
{
super
(
entryPoint
);
}
/**
* Create a method handle whose entry point is a non-static method
* visible in the exact (most specific) class of
* the newly constructed object.
* <p>
* The method is specified by name and type, as if via this expression:
* {@code MethodHandles.lookup().findVirtual(this.getClass(), name, type)}.
* The class defining the method might be an anonymous inner class.
* <p>
* The method handle type of {@code this} (i.e, the fully constructed object)
* will be the given method handle type.
* A call to {@code this} will invoke the selected method.
* The receiver argument will be bound to {@code this} on every method
* handle invocation.
* <p>
* <i>Rationale:</i>
* Although this constructor may seem to be a mere luxury,
* it is not subsumed by the more general constructor which
* takes any {@code MethodHandle} as the entry point argument.
* In order to convert an entry point name to a method handle,
* the self-class of the object is required (in order to do
* the lookup). The self-class, in turn, is generally not
* available at the time of the constructor invocation,
* due to the rules of Java and the JVM verifier.
* One cannot call {@code this.getClass()}, because
* the value of {@code this} is inaccessible at the point
* of the constructor call. (Changing this would require
* change to the Java language, verifiers, and compilers.)
* In particular, this constructor allows {@code JavaMethodHandle}s
* to be created in combination with the anonymous inner class syntax.
* @param entryPointName the name of the entry point method
* @param type (optional) the desired type of the method handle
*/
protected
JavaMethodHandle
(
String
entryPointName
,
MethodType
type
)
{
super
(
entryPointName
,
type
,
true
);
}
/**
* Create a method handle whose entry point is a non-static method
* visible in the exact (most specific) class of
* the newly constructed object.
* <p>
* The method is specified only by name.
* There must be exactly one method of that name visible in the object class,
* either inherited or locally declared.
* (That is, the method must not be overloaded.)
* <p>
* The method handle type of {@code this} (i.e, the fully constructed object)
* will be the same as the type of the selected non-static method.
* The receiver argument will be bound to {@code this} on every method
* handle invocation.
* <p>ISSUE: This signature wildcarding feature does not correspond to
* any MethodHandles.Lookup API element. Can we eliminate it?
* Alternatively, it is useful for naming non-overloaded methods.
* Shall we make type arguments optional in the Lookup methods,
* throwing an error in cases of ambiguity?
* <p>
* For this method's rationale, see the documentation
* for {@link #JavaMethodHandle(String,MethodType)}.
* @param entryPointName the name of the entry point method
*/
protected
JavaMethodHandle
(
String
entryPointName
)
{
super
(
entryPointName
,
(
MethodType
)
null
,
false
);
}
}
src/share/classes/sun/dyn/MemberName.java
浏览文件 @
9a560075
...
...
@@ -521,6 +521,11 @@ public final class MemberName implements Member, Cloneable {
if
(
lookupClass
!=
null
)
message
+=
", from "
+
lookupClass
.
getName
();
return
new
NoAccessException
(
message
);
}
public
static
Error
uncaughtException
(
Exception
ex
)
{
Error
err
=
new
InternalError
(
"uncaught exception"
);
err
.
initCause
(
ex
);
return
err
;
}
/** Actually making a query requires an access check. */
public
static
Factory
getFactory
(
Access
token
)
{
...
...
@@ -641,7 +646,7 @@ public final class MemberName implements Member, Cloneable {
* If lookup fails or access is not permitted, a {@linkplain NoAccessException} is thrown.
* Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
*/
public
MemberName
resolveOrFail
(
MemberName
m
,
boolean
searchSupers
,
Class
<?>
lookupClass
)
{
public
MemberName
resolveOrFail
(
MemberName
m
,
boolean
searchSupers
,
Class
<?>
lookupClass
)
throws
NoAccessException
{
MemberName
result
=
resolveOrNull
(
m
,
searchSupers
,
lookupClass
);
if
(
result
!=
null
)
return
result
;
...
...
src/share/classes/sun/dyn/MethodHandleImpl.java
浏览文件 @
9a560075
...
...
@@ -25,11 +25,8 @@
package
sun.dyn
;
import
java.dyn.JavaMethodHandle
;
import
java.dyn.MethodHandle
;
import
java.dyn.MethodHandles
;
import
java.dyn.*
;
import
java.dyn.MethodHandles.Lookup
;
import
java.dyn.MethodType
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
sun.dyn.util.VerifyType
;
...
...
@@ -46,6 +43,7 @@ import sun.dyn.util.Wrapper;
import
sun.misc.Unsafe
;
import
static
sun
.
dyn
.
MemberName
.
newIllegalArgumentException
;
import
static
sun
.
dyn
.
MemberName
.
newNoAccessException
;
import
static
sun
.
dyn
.
MemberName
.
uncaughtException
;
/**
* Base class for method handles, containing JVM-specific fields and logic.
...
...
@@ -173,7 +171,7 @@ public abstract class MethodHandleImpl {
*/
public
static
MethodHandle
findMethod
(
Access
token
,
MemberName
method
,
boolean
doDispatch
,
Class
<?>
lookupClass
)
{
boolean
doDispatch
,
Class
<?>
lookupClass
)
throws
NoAccessException
{
Access
.
check
(
token
);
// only trusted calls
MethodType
mtype
=
method
.
getMethodType
();
if
(!
method
.
isStatic
())
{
...
...
@@ -320,7 +318,7 @@ public abstract class MethodHandleImpl {
try
{
VARARGS_INVOKE
=
IMPL_LOOKUP
.
findVirtual
(
AllocateObject
.
class
,
"invoke_V"
,
MethodType
.
genericMethodType
(
0
,
true
));
}
catch
(
NoAccessException
ex
)
{
throw
new
InternalError
(
""
);
throw
uncaughtException
(
ex
);
}
}
// Corresponding generic constructor types:
...
...
@@ -416,9 +414,7 @@ public abstract class MethodHandleImpl {
f
=
c
.
getDeclaredField
(
field
.
getName
());
return
unsafe
.
staticFieldBase
(
f
);
}
catch
(
Exception
ee
)
{
Error
e
=
new
InternalError
();
e
.
initCause
(
ee
);
throw
e
;
throw
uncaughtException
(
ee
);
}
}
...
...
@@ -473,10 +469,8 @@ public abstract class MethodHandleImpl {
MethodHandle
mh
;
try
{
mh
=
IMPL_LOOKUP
.
findVirtual
(
FieldAccessor
.
class
,
name
,
type
);
}
catch
(
NoAccessException
ee
)
{
Error
e
=
new
InternalError
(
"name,type="
+
name
+
type
);
e
.
initCause
(
ee
);
throw
e
;
}
catch
(
NoAccessException
ex
)
{
throw
uncaughtException
(
ex
);
}
if
(
evclass
!=
vclass
||
(!
isStatic
&&
ecclass
!=
cclass
))
{
MethodType
strongType
=
FieldAccessor
.
ftype
(
cclass
,
vclass
,
isSetter
,
isStatic
);
...
...
@@ -543,10 +537,8 @@ public abstract class MethodHandleImpl {
MethodHandle
mh
;
try
{
mh
=
IMPL_LOOKUP
.
findStatic
(
FieldAccessor
.
class
,
name
,
type
);
}
catch
(
NoAccessException
ee
)
{
Error
e
=
new
InternalError
(
"name,type="
+
name
+
type
);
e
.
initCause
(
ee
);
throw
e
;
}
catch
(
NoAccessException
ex
)
{
throw
uncaughtException
(
ex
);
}
if
(
caclass
!=
null
)
{
MethodType
strongType
=
FieldAccessor
.
atype
(
caclass
,
isSetter
);
...
...
@@ -1031,7 +1023,7 @@ public abstract class MethodHandleImpl {
try
{
VARARGS_INVOKE
=
IMPL_LOOKUP
.
findVirtual
(
GuardWithTest
.
class
,
"invoke_V"
,
MethodType
.
genericMethodType
(
0
,
true
));
}
catch
(
NoAccessException
ex
)
{
throw
new
InternalError
(
""
);
throw
uncaughtException
(
ex
);
}
}
}
...
...
@@ -1167,7 +1159,7 @@ public abstract class MethodHandleImpl {
try
{
VARARGS_INVOKE
=
IMPL_LOOKUP
.
findVirtual
(
GuardWithCatch
.
class
,
"invoke_V"
,
MethodType
.
genericMethodType
(
0
,
true
));
}
catch
(
NoAccessException
ex
)
{
throw
new
InternalError
(
""
);
throw
uncaughtException
(
ex
);
}
}
}
...
...
@@ -1207,9 +1199,16 @@ public abstract class MethodHandleImpl {
return
AdapterMethodHandle
.
makeRetypeRaw
(
token
,
type
,
THROW_EXCEPTION
);
}
static
final
MethodHandle
THROW_EXCEPTION
static
final
MethodHandle
THROW_EXCEPTION
;
static
{
try
{
THROW_EXCEPTION
=
IMPL_LOOKUP
.
findStatic
(
MethodHandleImpl
.
class
,
"throwException"
,
MethodType
.
methodType
(
Empty
.
class
,
Throwable
.
class
));
}
catch
(
NoAccessException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
static
<
T
extends
Throwable
>
Empty
throwException
(
T
t
)
throws
T
{
throw
t
;
}
public
static
String
getNameString
(
Access
token
,
MethodHandle
target
)
{
...
...
src/share/classes/sun/dyn/MethodHandleNatives.java
浏览文件 @
9a560075
...
...
@@ -25,9 +25,7 @@
package
sun.dyn
;
import
java.dyn.CallSite
;
import
java.dyn.MethodHandle
;
import
java.dyn.MethodType
;
import
java.dyn.*
;
import
java.dyn.MethodHandles.Lookup
;
import
java.lang.reflect.AccessibleObject
;
import
java.lang.reflect.Field
;
...
...
@@ -324,18 +322,24 @@ class MethodHandleNatives {
*/
static
MethodHandle
linkMethodHandleConstant
(
Class
<?>
callerClass
,
int
refKind
,
Class
<?>
defc
,
String
name
,
Object
type
)
{
Lookup
lookup
=
IMPL_LOOKUP
.
in
(
callerClass
);
switch
(
refKind
)
{
case
REF_getField:
return
lookup
.
findGetter
(
defc
,
name
,
(
Class
<?>)
type
);
case
REF_getStatic:
return
lookup
.
findStaticGetter
(
defc
,
name
,
(
Class
<?>)
type
);
case
REF_putField:
return
lookup
.
findSetter
(
defc
,
name
,
(
Class
<?>)
type
);
case
REF_putStatic:
return
lookup
.
findStaticSetter
(
defc
,
name
,
(
Class
<?>)
type
);
case
REF_invokeVirtual:
return
lookup
.
findVirtual
(
defc
,
name
,
(
MethodType
)
type
);
case
REF_invokeStatic:
return
lookup
.
findStatic
(
defc
,
name
,
(
MethodType
)
type
);
case
REF_invokeSpecial:
return
lookup
.
findSpecial
(
defc
,
name
,
(
MethodType
)
type
,
callerClass
);
case
REF_newInvokeSpecial:
return
lookup
.
findConstructor
(
defc
,
(
MethodType
)
type
);
case
REF_invokeInterface:
return
lookup
.
findVirtual
(
defc
,
name
,
(
MethodType
)
type
);
try
{
Lookup
lookup
=
IMPL_LOOKUP
.
in
(
callerClass
);
switch
(
refKind
)
{
case
REF_getField:
return
lookup
.
findGetter
(
defc
,
name
,
(
Class
<?>)
type
);
case
REF_getStatic:
return
lookup
.
findStaticGetter
(
defc
,
name
,
(
Class
<?>)
type
);
case
REF_putField:
return
lookup
.
findSetter
(
defc
,
name
,
(
Class
<?>)
type
);
case
REF_putStatic:
return
lookup
.
findStaticSetter
(
defc
,
name
,
(
Class
<?>)
type
);
case
REF_invokeVirtual:
return
lookup
.
findVirtual
(
defc
,
name
,
(
MethodType
)
type
);
case
REF_invokeStatic:
return
lookup
.
findStatic
(
defc
,
name
,
(
MethodType
)
type
);
case
REF_invokeSpecial:
return
lookup
.
findSpecial
(
defc
,
name
,
(
MethodType
)
type
,
callerClass
);
case
REF_newInvokeSpecial:
return
lookup
.
findConstructor
(
defc
,
(
MethodType
)
type
);
case
REF_invokeInterface:
return
lookup
.
findVirtual
(
defc
,
name
,
(
MethodType
)
type
);
}
throw
new
IllegalArgumentException
(
"bad MethodHandle constant "
+
name
+
" : "
+
type
);
}
catch
(
NoAccessException
ex
)
{
Error
err
=
new
IncompatibleClassChangeError
();
err
.
initCause
(
ex
);
throw
err
;
}
throw
new
IllegalArgumentException
(
"bad MethodHandle constant "
+
name
+
" : "
+
type
);
}
}
src/share/classes/sun/dyn/SpreadGeneric.java
浏览文件 @
9a560075
...
...
@@ -25,11 +25,7 @@
package
sun.dyn
;
import
java.dyn.JavaMethodHandle
;
import
java.dyn.MethodHandle
;
import
java.dyn.MethodHandles
;
import
java.dyn.MethodType
;
import
java.dyn.NoAccessException
;
import
java.dyn.*
;
import
java.lang.reflect.Constructor
;
import
java.lang.reflect.InvocationTargetException
;
import
java.util.ArrayList
;
...
...
src/share/classes/sun/dyn/ToGeneric.java
浏览文件 @
9a560075
...
...
@@ -25,11 +25,7 @@
package
sun.dyn
;
import
java.dyn.JavaMethodHandle
;
import
java.dyn.MethodHandle
;
import
java.dyn.MethodHandles
;
import
java.dyn.MethodType
;
import
java.dyn.NoAccessException
;
import
java.dyn.*
;
import
java.lang.reflect.Constructor
;
import
java.lang.reflect.InvocationTargetException
;
import
sun.dyn.util.ValueConversions
;
...
...
src/share/classes/sun/dyn/util/ValueConversions.java
浏览文件 @
9a560075
...
...
@@ -34,6 +34,7 @@ import java.util.List;
import
sun.dyn.Access
;
import
sun.dyn.AdapterMethodHandle
;
import
sun.dyn.MethodHandleImpl
;
import
static
sun
.
dyn
.
MemberName
.
uncaughtException
;
public
class
ValueConversions
{
private
static
final
Access
IMPL_TOKEN
=
Access
.
getToken
();
...
...
@@ -148,11 +149,16 @@ public class ValueConversions {
// look up the method
String
name
=
"unbox"
+
wrap
.
simpleName
()
+
(
raw
?
"Raw"
:
""
);
MethodType
type
=
unboxType
(
wrap
,
raw
);
if
(!
exact
)
// actually, type is wrong; the Java method takes Object
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
name
,
type
.
erase
());
else
if
(!
exact
)
{
try
{
// actually, type is wrong; the Java method takes Object
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
name
,
type
.
erase
());
}
catch
(
NoAccessException
ex
)
{
mh
=
null
;
}
}
else
{
mh
=
retype
(
type
,
unbox
(
wrap
,
!
exact
,
raw
));
}
if
(
mh
!=
null
)
{
cache
.
put
(
wrap
,
mh
);
return
mh
;
...
...
@@ -280,10 +286,15 @@ public class ValueConversions {
// look up the method
String
name
=
"box"
+
wrap
.
simpleName
()
+
(
raw
?
"Raw"
:
""
);
MethodType
type
=
boxType
(
wrap
,
raw
);
if
(
exact
)
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
name
,
type
);
else
if
(
exact
)
{
try
{
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
name
,
type
);
}
catch
(
NoAccessException
ex
)
{
mh
=
null
;
}
}
else
{
mh
=
retype
(
type
.
erase
(),
box
(
wrap
,
!
exact
,
raw
));
}
if
(
mh
!=
null
)
{
cache
.
put
(
wrap
,
mh
);
return
mh
;
...
...
@@ -394,10 +405,15 @@ public class ValueConversions {
// look up the method
String
name
=
"reboxRaw"
+
wrap
.
simpleName
();
MethodType
type
=
reboxType
(
wrap
);
if
(
exact
)
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
name
,
type
);
else
if
(
exact
)
{
try
{
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
name
,
type
);
}
catch
(
NoAccessException
ex
)
{
mh
=
null
;
}
}
else
{
mh
=
retype
(
IDENTITY
.
type
(),
rebox
(
wrap
,
!
exact
));
}
if
(
mh
!=
null
)
{
cache
.
put
(
wrap
,
mh
);
return
mh
;
...
...
@@ -474,7 +490,11 @@ public class ValueConversions {
mh
=
EMPTY
;
break
;
case
INT:
case
LONG:
case
FLOAT:
case
DOUBLE:
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"zero"
+
wrap
.
simpleName
(),
type
);
try
{
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"zero"
+
wrap
.
simpleName
(),
type
);
}
catch
(
NoAccessException
ex
)
{
mh
=
null
;
}
break
;
}
if
(
mh
!=
null
)
{
...
...
@@ -549,8 +569,8 @@ public class ValueConversions {
ZERO_OBJECT
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"zeroObject"
,
zeroObjectType
);
IGNORE
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"ignore"
,
ignoreType
);
EMPTY
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"empty"
,
ignoreType
.
dropParameterTypes
(
0
,
1
));
}
catch
(
Runtime
Exception
ex
)
{
throw
ex
;
}
catch
(
Exception
ex
)
{
throw
uncaughtException
(
ex
)
;
}
}
...
...
test/java/dyn/ClassValueTest.java
0 → 100644
浏览文件 @
9a560075
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @summary tests for class-specific values
* @compile ClassValueTest.java
* @run junit/othervm test.java.dyn.ClassValueTest
*/
/*
Manually:
$ $JAVA7X_HOME/bin/javac -d foo -cp $JUNIT4_JAR test/java/dyn/ClassValueTest.java
$ $JAVA7X_HOME/bin/java -cp foo:$JUNIT4_JAR org.junit.runner.JUnitCore test.java.dyn.ClassValueTest
Output: .testAdd => 1000 : Integer
*/
package
test.java.dyn
;
import
java.util.*
;
import
java.dyn.*
;
import
org.junit.*
;
import
static
org
.
junit
.
Assert
.*;
/**
* @author jrose
*/
public
class
ClassValueTest
{
static
String
nameForCV1
(
Class
<?>
type
)
{
return
"CV1:"
+
type
.
getName
();
}
static
int
countForCV1
;
static
final
ClassValue
<
String
>
CV1
=
new
ClassValue
<
String
>()
{
protected
String
computeValue
(
Class
<?>
type
)
{
countForCV1
++;
return
nameForCV1
(
type
);
}
};
static
final
Class
[]
CLASSES
=
{
String
.
class
,
Integer
.
class
,
int
.
class
,
boolean
[].
class
,
char
[][].
class
,
ClassValueTest
.
class
};
@Test
public
void
testGet
()
{
countForCV1
=
0
;
for
(
Class
c
:
CLASSES
)
{
assertEquals
(
nameForCV1
(
c
),
CV1
.
get
(
c
));
}
assertEquals
(
CLASSES
.
length
,
countForCV1
);
for
(
Class
c
:
CLASSES
)
{
assertEquals
(
nameForCV1
(
c
),
CV1
.
get
(
c
));
}
assertEquals
(
CLASSES
.
length
,
countForCV1
);
}
@Test
public
void
testRemove
()
{
for
(
Class
c
:
CLASSES
)
{
CV1
.
get
(
c
);
}
countForCV1
=
0
;
int
REMCOUNT
=
3
;
for
(
int
i
=
0
;
i
<
REMCOUNT
;
i
++)
{
CV1
.
remove
(
CLASSES
[
i
]);
}
assertEquals
(
0
,
countForCV1
);
// no change
for
(
Class
c
:
CLASSES
)
{
assertEquals
(
nameForCV1
(
c
),
CV1
.
get
(
c
));
}
assertEquals
(
REMCOUNT
,
countForCV1
);
}
static
String
nameForCVN
(
Class
<?>
type
,
int
n
)
{
return
"CV["
+
n
+
"]"
+
type
.
getName
();
}
static
int
countForCVN
;
static
class
CVN
extends
ClassValue
<
String
>
{
final
int
n
;
CVN
(
int
n
)
{
this
.
n
=
n
;
}
protected
String
computeValue
(
Class
<?>
type
)
{
countForCVN
++;
return
nameForCVN
(
type
,
n
);
}
};
@Test
public
void
testGetMany
()
{
int
CVN_COUNT1
=
100
,
CVN_COUNT2
=
100
;
CVN
cvns
[]
=
new
CVN
[
CVN_COUNT1
*
CVN_COUNT2
];
for
(
int
n
=
0
;
n
<
cvns
.
length
;
n
++)
{
cvns
[
n
]
=
new
CVN
(
n
);
}
countForCVN
=
0
;
for
(
int
pass
=
0
;
pass
<=
2
;
pass
++)
{
for
(
int
i1
=
0
;
i1
<
CVN_COUNT1
;
i1
++)
{
eachClass:
for
(
Class
c
:
CLASSES
)
{
for
(
int
i2
=
0
;
i2
<
CVN_COUNT2
;
i2
++)
{
int
n
=
i1
*
CVN_COUNT2
+
i2
;
assertEquals
(
0
,
countForCVN
);
assertEquals
(
nameForCVN
(
c
,
n
),
cvns
[
n
].
get
(
c
));
cvns
[
n
].
get
(
c
);
//get it again
//System.out.println("getting "+n+":"+cvns[n].get(c));
boolean
doremove
=
(((
i1
+
i2
)
&
3
)
==
0
);
switch
(
pass
)
{
case
0
:
assertEquals
(
1
,
countForCVN
);
break
;
case
1
:
// remove on middle pass
assertEquals
(
0
,
countForCVN
);
if
(
doremove
)
{
//System.out.println("removing "+n+":"+cvns[n].get(c));
cvns
[
n
].
remove
(
c
);
assertEquals
(
0
,
countForCVN
);
}
break
;
case
2
:
assertEquals
(
doremove
?
1
:
0
,
countForCVN
);
break
;
}
countForCVN
=
0
;
if
(
i1
>
i2
&&
i1
<
i2
+
5
)
continue
eachClass
;
// leave diagonal gap
}
}
}
}
assertEquals
(
countForCVN
,
0
);
for
(
int
n
=
0
;
n
<
cvns
.
length
;
n
++)
{
for
(
Class
c
:
CLASSES
)
{
assertEquals
(
nameForCVN
(
c
,
n
),
cvns
[
n
].
get
(
c
));
}
}
}
}
test/java/dyn/JavaDocExamples.java
0 → 100644
浏览文件 @
9a560075
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @summary example code used in javadoc for java.dyn API
* @compile -XDallowTransitionalJSR292=no JavaDocExamples.java
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.JavaDocExamples
*/
/*
---- To run outside jtreg:
$ $JAVA7X_HOME/bin/javac -cp $JUNIT4_JAR -d /tmp/Classes \
$DAVINCI/sources/jdk/test/java/dyn/JavaDocExamples.java
$ $JAVA7X_HOME/bin/java -cp $JUNIT4_JAR:/tmp/Classes \
-XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles \
-Dtest.java.dyn.JavaDocExamples.verbosity=1 \
test.java.dyn.JavaDocExamples
----
*/
package
test.java.dyn
;
import
java.dyn.*
;
import
static
java
.
dyn
.
MethodHandles
.*;
import
static
java
.
dyn
.
MethodType
.*;
import
java.lang.reflect.*
;
import
java.util.*
;
import
org.junit.*
;
import
static
org
.
junit
.
Assert
.*;
import
static
org
.
junit
.
Assume
.*;
/**
* @author jrose
*/
public
class
JavaDocExamples
{
/** Wrapper for running the JUnit tests in this module.
* Put JUnit on the classpath!
*/
public
static
void
main
(
String
...
ignore
)
{
org
.
junit
.
runner
.
JUnitCore
.
runClasses
(
JavaDocExamples
.
class
);
}
// How much output?
static
int
verbosity
=
Integer
.
getInteger
(
"test.java.dyn.JavaDocExamples.verbosity"
,
0
);
{}
static
final
private
Lookup
LOOKUP
=
lookup
();
// static final private MethodHandle CONCAT_1 = LOOKUP.findVirtual(String.class,
// "concat", methodType(String.class, String.class));
// static final private MethodHandle HASHCODE_1 = LOOKUP.findVirtual(Object.class,
// "hashCode", methodType(int.class));
// form required if NoAccessException is intercepted:
static
final
private
MethodHandle
CONCAT_2
,
HASHCODE_2
;
static
{
try
{
CONCAT_2
=
LOOKUP
.
findVirtual
(
String
.
class
,
"concat"
,
methodType
(
String
.
class
,
String
.
class
));
HASHCODE_2
=
LOOKUP
.
findVirtual
(
Object
.
class
,
"hashCode"
,
methodType
(
int
.
class
));
}
catch
(
NoAccessException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
{}
@Test
public
void
testFindVirtual
()
throws
Throwable
{
{}
MethodHandle
CONCAT_3
=
LOOKUP
.
findVirtual
(
String
.
class
,
"concat"
,
methodType
(
String
.
class
,
String
.
class
));
MethodHandle
HASHCODE_3
=
LOOKUP
.
findVirtual
(
Object
.
class
,
"hashCode"
,
methodType
(
int
.
class
));
//assertEquals("xy", (String) CONCAT_1.invokeExact("x", "y"));
assertEquals
(
"xy"
,
(
String
)
CONCAT_2
.<
String
>
invokeExact
(
"x"
,
"y"
));
assertEquals
(
"xy"
,
(
String
)
CONCAT_3
.<
String
>
invokeExact
(
"x"
,
"y"
));
//assertEquals("xy".hashCode(), (int) HASHCODE_1.<int>invokeExact((Object)"xy"));
assertEquals
(
"xy"
.
hashCode
(),
(
int
)
HASHCODE_2
.<
int
>
invokeExact
((
Object
)
"xy"
));
assertEquals
(
"xy"
.
hashCode
(),
(
int
)
HASHCODE_3
.<
int
>
invokeExact
((
Object
)
"xy"
));
{}
}
@Test
public
void
testDropArguments
()
throws
Throwable
{
{{
{}
/// JAVADOC
MethodHandle
cat
=
lookup
().
findVirtual
(
String
.
class
,
"concat"
,
methodType
(
String
.
class
,
String
.
class
));
cat
=
cat
.
asType
(
methodType
(
Object
.
class
,
String
.
class
,
String
.
class
));
/*(String)*/
assertEquals
(
"xy"
,
/*(String)*/
cat
.
invokeExact
(
"x"
,
"y"
));
MethodHandle
d0
=
dropArguments
(
cat
,
0
,
String
.
class
);
assertEquals
(
"yz"
,
/*(String)*/
d0
.
invokeExact
(
"x"
,
"y"
,
"z"
));
MethodHandle
d1
=
dropArguments
(
cat
,
1
,
String
.
class
);
assertEquals
(
"xz"
,
/*(String)*/
d1
.
invokeExact
(
"x"
,
"y"
,
"z"
));
MethodHandle
d2
=
dropArguments
(
cat
,
2
,
String
.
class
);
assertEquals
(
"xy"
,
/*(String)*/
d2
.
invokeExact
(
"x"
,
"y"
,
"z"
));
MethodHandle
d12
=
dropArguments
(
cat
,
1
,
int
.
class
,
boolean
.
class
);
assertEquals
(
"xz"
,
/*(String)*/
d12
.
invokeExact
(
"x"
,
12
,
true
,
"z"
));
}}
}
static
void
assertEquals
(
Object
exp
,
Object
act
)
{
if
(
verbosity
>
0
)
System
.
out
.
println
(
"result: "
+
act
);
Assert
.
assertEquals
(
exp
,
act
);
}
}
test/java/dyn/MethodHandlesTest.java
浏览文件 @
9a560075
...
...
@@ -265,6 +265,12 @@ public class MethodHandlesTest {
// wrap = Wrapper.forWrapperType(dst);
// if (wrap != Wrapper.OBJECT)
// return wrap.wrap(nextArg++);
if
(
param
.
isInterface
())
{
for
(
Class
<?>
c
:
param
.
getClasses
())
{
if
(
param
.
isAssignableFrom
(
c
)
&&
!
c
.
isInterface
())
{
param
=
c
;
break
;
}
}
}
if
(
param
.
isInterface
()
||
param
.
isAssignableFrom
(
String
.
class
))
return
"#"
+
nextArg
();
else
...
...
@@ -380,7 +386,7 @@ public class MethodHandlesTest {
}
public
static
interface
IntExample
{
public
void
v0
();
static
class
Impl
implements
IntExample
{
public
static
class
Impl
implements
IntExample
{
public
void
v0
()
{
called
(
"Int/v0"
,
this
);
}
final
String
name
;
public
Impl
()
{
name
=
"Impl#"
+
nextArg
();
}
...
...
@@ -449,7 +455,7 @@ public class MethodHandlesTest {
countTest
(
positive
);
MethodType
type
=
MethodType
.
methodType
(
ret
,
params
);
MethodHandle
target
=
null
;
Runtime
Exception
noAccess
=
null
;
Exception
noAccess
=
null
;
try
{
if
(
verbosity
>=
4
)
System
.
out
.
println
(
"lookup via "
+
lookup
+
" of "
+
defc
+
" "
+
name
+
type
);
target
=
lookup
.
findStatic
(
defc
,
name
,
type
);
...
...
@@ -513,7 +519,7 @@ public class MethodHandlesTest {
String
methodName
=
name
.
substring
(
1
+
name
.
indexOf
(
'/'
));
// foo/bar => foo
MethodType
type
=
MethodType
.
methodType
(
ret
,
params
);
MethodHandle
target
=
null
;
Runtime
Exception
noAccess
=
null
;
Exception
noAccess
=
null
;
try
{
if
(
verbosity
>=
4
)
System
.
out
.
println
(
"lookup via "
+
lookup
+
" of "
+
defc
+
" "
+
name
+
type
);
target
=
lookup
.
findVirtual
(
defc
,
methodName
,
type
);
...
...
@@ -567,7 +573,7 @@ public class MethodHandlesTest {
countTest
(
positive
);
MethodType
type
=
MethodType
.
methodType
(
ret
,
params
);
MethodHandle
target
=
null
;
Runtime
Exception
noAccess
=
null
;
Exception
noAccess
=
null
;
try
{
if
(
verbosity
>=
4
)
System
.
out
.
println
(
"lookup via "
+
lookup
+
" of "
+
defc
+
" "
+
name
+
type
);
target
=
lookup
.
findSpecial
(
defc
,
name
,
type
,
specialCaller
);
...
...
@@ -623,7 +629,7 @@ public class MethodHandlesTest {
MethodType
type
=
MethodType
.
methodType
(
ret
,
params
);
Object
receiver
=
randomArg
(
defc
);
MethodHandle
target
=
null
;
Runtime
Exception
noAccess
=
null
;
Exception
noAccess
=
null
;
try
{
if
(
verbosity
>=
4
)
System
.
out
.
println
(
"lookup via "
+
lookup
+
" of "
+
defc
+
" "
+
name
+
type
);
target
=
lookup
.
bind
(
receiver
,
methodName
,
type
);
...
...
@@ -688,7 +694,7 @@ public class MethodHandlesTest {
MethodType
type
=
MethodType
.
methodType
(
ret
,
params
);
Method
rmethod
=
null
;
MethodHandle
target
=
null
;
Runtime
Exception
noAccess
=
null
;
Exception
noAccess
=
null
;
try
{
rmethod
=
defc
.
getDeclaredMethod
(
name
,
params
);
}
catch
(
NoSuchMethodException
ex
)
{
...
...
@@ -1088,7 +1094,11 @@ public class MethodHandlesTest {
if
(
rtype
!=
Object
.
class
)
pfx
=
rtype
.
getSimpleName
().
substring
(
0
,
1
).
toLowerCase
();
String
name
=
pfx
+
"id"
;
return
PRIVATE
.
findStatic
(
Callee
.
class
,
name
,
type
);
try
{
return
PRIVATE
.
findStatic
(
Callee
.
class
,
name
,
type
);
}
catch
(
Exception
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
}
...
...
@@ -1327,7 +1337,8 @@ public class MethodHandlesTest {
MethodHandle
result
=
MethodHandles
.
spreadArguments
(
target2
,
newType
);
Object
[]
returnValue
;
if
(
pos
==
0
)
{
returnValue
=
(
Object
[])
result
.
invokeExact
(
args
);
Object
rawRetVal
=
result
.
invokeExact
(
args
);
returnValue
=
(
Object
[])
rawRetVal
;
}
else
{
Object
[]
args1
=
Arrays
.
copyOfRange
(
args
,
0
,
pos
+
1
);
args1
[
pos
]
=
Arrays
.
copyOfRange
(
args
,
pos
,
args
.
length
);
...
...
@@ -1817,8 +1828,13 @@ public class MethodHandlesTest {
testCastFailure
(
"unbox/return"
,
11000
);
}
static
class
Surprise
extends
JavaMethodHandle
{
Surprise
()
{
super
(
"value"
);
}
static
class
Surprise
implements
MethodHandleProvider
{
public
MethodHandle
asMethodHandle
()
{
return
VALUE
.
bindTo
(
this
);
}
public
MethodHandle
asMethodHandle
(
MethodType
type
)
{
return
asMethodHandle
().
asType
(
type
);
}
Object
value
(
Object
x
)
{
trace
(
"value"
,
x
);
if
(
boo
!=
null
)
return
boo
;
...
...
@@ -1833,22 +1849,32 @@ public class MethodHandlesTest {
static
Object
refIdentity
(
Object
x
)
{
trace
(
"ref.x"
,
x
);
return
x
;
}
static
Integer
boxIdentity
(
Integer
x
)
{
trace
(
"box.x"
,
x
);
return
x
;
}
static
int
intIdentity
(
int
x
)
{
trace
(
"int.x"
,
x
);
return
x
;
}
static
MethodHandle
REF_IDENTITY
=
PRIVATE
.
findStatic
(
Surprise
.
class
,
"refIdentity"
,
MethodType
.
methodType
(
Object
.
class
,
Object
.
class
));
static
MethodHandle
BOX_IDENTITY
=
PRIVATE
.
findStatic
(
Surprise
.
class
,
"boxIdentity"
,
MethodType
.
methodType
(
Integer
.
class
,
Integer
.
class
));
static
MethodHandle
INT_IDENTITY
=
PRIVATE
.
findStatic
(
Surprise
.
class
,
"intIdentity"
,
MethodType
.
methodType
(
int
.
class
,
int
.
class
));
static
MethodHandle
VALUE
,
REF_IDENTITY
,
BOX_IDENTITY
,
INT_IDENTITY
;
static
{
try
{
VALUE
=
PRIVATE
.
findVirtual
(
Surprise
.
class
,
"value"
,
MethodType
.
methodType
(
Object
.
class
,
Object
.
class
));
REF_IDENTITY
=
PRIVATE
.
findStatic
(
Surprise
.
class
,
"refIdentity"
,
MethodType
.
methodType
(
Object
.
class
,
Object
.
class
));
BOX_IDENTITY
=
PRIVATE
.
findStatic
(
Surprise
.
class
,
"boxIdentity"
,
MethodType
.
methodType
(
Integer
.
class
,
Integer
.
class
));
INT_IDENTITY
=
PRIVATE
.
findStatic
(
Surprise
.
class
,
"intIdentity"
,
MethodType
.
methodType
(
int
.
class
,
int
.
class
));
}
catch
(
Exception
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
}
void
testCastFailure
(
String
mode
,
int
okCount
)
throws
Throwable
{
countTest
(
false
);
if
(
verbosity
>
2
)
System
.
out
.
println
(
"mode="
+
mode
);
Surprise
boo
=
new
Surprise
();
MethodHandle
identity
=
Surprise
.
REF_IDENTITY
,
surprise
=
boo
;
MethodHandle
identity
=
Surprise
.
REF_IDENTITY
,
surprise
0
=
boo
.
asMethodHandle
(),
surprise
=
surprise0
;
if
(
mode
.
endsWith
(
"/return"
))
{
if
(
mode
.
equals
(
"unbox/return"
))
{
// fail on return to ((Integer)surprise).intValue
...
...
@@ -1874,7 +1900,7 @@ public class MethodHandlesTest {
identity
=
MethodHandles
.
filterArguments
(
callee
,
identity
);
}
}
assertNotSame
(
mode
,
surprise
,
boo
);
assertNotSame
(
mode
,
surprise
,
surprise0
);
identity
=
MethodHandles
.
convertArguments
(
identity
,
MethodType
.
genericMethodType
(
1
));
surprise
=
MethodHandles
.
convertArguments
(
surprise
,
MethodType
.
genericMethodType
(
1
));
Object
x
=
42
;
...
...
@@ -1936,6 +1962,107 @@ public class MethodHandlesTest {
mh
.
invokeVarargs
(
args
);
assertCalled
(
name
,
args
);
}
static
void
runForRunnable
()
{
called
(
"runForRunnable"
);
}
private
interface
Fooable
{
Object
foo
(
Fooable
x
,
Object
y
);
// this is for randomArg:
public
class
Impl
implements
Fooable
{
public
Object
foo
(
Fooable
x
,
Object
y
)
{
throw
new
RuntimeException
(
"do not call"
);
}
final
String
name
;
public
Impl
()
{
name
=
"Fooable#"
+
nextArg
();
}
@Override
public
String
toString
()
{
return
name
;
}
}
}
static
Object
fooForFooable
(
Fooable
x
,
Object
y
)
{
return
called
(
"fooForFooable"
,
x
,
y
);
}
private
static
class
MyCheckedException
extends
Exception
{
}
private
interface
WillThrow
{
void
willThrow
()
throws
MyCheckedException
;
}
@Test
public
void
testAsInstance
()
throws
Throwable
{
if
(
CAN_SKIP_WORKING
)
return
;
Lookup
lookup
=
MethodHandles
.
lookup
();
{
MethodType
mt
=
MethodType
.
methodType
(
void
.
class
);
MethodHandle
mh
=
lookup
.
findStatic
(
MethodHandlesTest
.
class
,
"runForRunnable"
,
mt
);
Runnable
proxy
=
MethodHandles
.
asInstance
(
mh
,
Runnable
.
class
);
proxy
.
run
();
assertCalled
(
"runForRunnable"
);
}
{
MethodType
mt
=
MethodType
.
methodType
(
Object
.
class
,
Fooable
.
class
,
Object
.
class
);
MethodHandle
mh
=
lookup
.
findStatic
(
MethodHandlesTest
.
class
,
"fooForFooable"
,
mt
);
Fooable
proxy
=
MethodHandles
.
asInstance
(
mh
,
Fooable
.
class
);
Object
[]
args
=
randomArgs
(
mt
.
parameterArray
());
Object
result
=
proxy
.
foo
((
Fooable
)
args
[
0
],
args
[
1
]);
assertCalled
(
"fooForFooable"
,
args
);
assertEquals
(
result
,
logEntry
(
"fooForFooable"
,
args
));
}
for
(
Throwable
ex
:
new
Throwable
[]
{
new
NullPointerException
(
"ok"
),
new
InternalError
(
"ok"
),
new
Throwable
(
"fail"
),
new
Exception
(
"fail"
),
new
MyCheckedException
()
})
{
MethodHandle
mh
=
MethodHandles
.
throwException
(
void
.
class
,
Throwable
.
class
);
mh
=
MethodHandles
.
insertArguments
(
mh
,
0
,
ex
);
WillThrow
proxy
=
MethodHandles
.
asInstance
(
mh
,
WillThrow
.
class
);
try
{
proxy
.
willThrow
();
System
.
out
.
println
(
"Failed to throw: "
+
ex
);
assertTrue
(
false
);
}
catch
(
Throwable
ex1
)
{
if
(
verbosity
>
2
)
{
System
.
out
.
println
(
"throw "
+
ex
);
System
.
out
.
println
(
"catch "
+(
ex
==
ex1
?
"UNWRAPPED"
:
ex1
));
}
if
(
ex
instanceof
RuntimeException
||
ex
instanceof
Error
)
{
assertSame
(
"must pass unchecked exception out without wrapping"
,
ex
,
ex1
);
}
else
if
(
ex
instanceof
MyCheckedException
)
{
assertSame
(
"must pass declared exception out without wrapping"
,
ex
,
ex1
);
}
else
{
assertNotSame
(
"must pass undeclared checked exception with wrapping"
,
ex
,
ex1
);
UndeclaredThrowableException
utex
=
(
UndeclaredThrowableException
)
ex1
;
assertSame
(
ex
,
utex
.
getCause
());
}
}
}
// Test error checking:
MethodHandle
genericMH
=
ValueConversions
.
varargsArray
(
0
);
genericMH
=
MethodHandles
.
convertArguments
(
genericMH
,
genericMH
.
type
().
generic
());
for
(
Class
<?>
sam
:
new
Class
[]
{
Runnable
.
class
,
Fooable
.
class
,
Iterable
.
class
})
{
try
{
// Must throw, because none of these guys has generic type.
MethodHandles
.
asInstance
(
genericMH
,
sam
);
System
.
out
.
println
(
"Failed to throw"
);
assertTrue
(
false
);
}
catch
(
IllegalArgumentException
ex
)
{
}
}
for
(
Class
<?>
nonSAM
:
new
Class
[]
{
Object
.
class
,
String
.
class
,
CharSequence
.
class
,
Example
.
class
})
{
try
{
MethodHandles
.
asInstance
(
ValueConversions
.
varargsArray
(
0
),
nonSAM
);
System
.
out
.
println
(
"Failed to throw"
);
assertTrue
(
false
);
}
catch
(
IllegalArgumentException
ex
)
{
}
}
}
}
// Local abbreviated copy of sun.dyn.util.ValueConversions
class
ValueConversions
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录