Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
5150d263
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看板
提交
5150d263
编写于
10月 30, 2010
作者:
J
jrose
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
6981777: implement JSR 292 EG adjustments from summer 2010
Reviewed-by: twisti
上级
70e0218c
变更
29
隐藏空白更改
内联
并排
Showing
29 changed file
with
1571 addition
and
1471 deletion
+1571
-1471
src/share/classes/java/dyn/BootstrapMethod.java
src/share/classes/java/dyn/BootstrapMethod.java
+0
-82
src/share/classes/java/dyn/CallSite.java
src/share/classes/java/dyn/CallSite.java
+116
-122
src/share/classes/java/dyn/ConstantCallSite.java
src/share/classes/java/dyn/ConstantCallSite.java
+5
-3
src/share/classes/java/dyn/InvokeDynamic.java
src/share/classes/java/dyn/InvokeDynamic.java
+0
-80
src/share/classes/java/dyn/Linkage.java
src/share/classes/java/dyn/Linkage.java
+22
-120
src/share/classes/java/dyn/LinkagePermission.java
src/share/classes/java/dyn/LinkagePermission.java
+0
-102
src/share/classes/java/dyn/MethodHandle.java
src/share/classes/java/dyn/MethodHandle.java
+248
-160
src/share/classes/java/dyn/MethodHandleProvider.java
src/share/classes/java/dyn/MethodHandleProvider.java
+0
-80
src/share/classes/java/dyn/MethodHandles.java
src/share/classes/java/dyn/MethodHandles.java
+442
-244
src/share/classes/java/dyn/MethodType.java
src/share/classes/java/dyn/MethodType.java
+9
-63
src/share/classes/java/dyn/VolatileCallSite.java
src/share/classes/java/dyn/VolatileCallSite.java
+144
-0
src/share/classes/java/dyn/package-info.java
src/share/classes/java/dyn/package-info.java
+192
-97
src/share/classes/sun/dyn/AdapterMethodHandle.java
src/share/classes/sun/dyn/AdapterMethodHandle.java
+1
-1
src/share/classes/sun/dyn/BoundMethodHandle.java
src/share/classes/sun/dyn/BoundMethodHandle.java
+16
-8
src/share/classes/sun/dyn/CallSiteImpl.java
src/share/classes/sun/dyn/CallSiteImpl.java
+40
-8
src/share/classes/sun/dyn/FilterGeneric.java
src/share/classes/sun/dyn/FilterGeneric.java
+4
-4
src/share/classes/sun/dyn/FilterOneArgument.java
src/share/classes/sun/dyn/FilterOneArgument.java
+2
-2
src/share/classes/sun/dyn/FromGeneric.java
src/share/classes/sun/dyn/FromGeneric.java
+3
-3
src/share/classes/sun/dyn/Invokers.java
src/share/classes/sun/dyn/Invokers.java
+33
-0
src/share/classes/sun/dyn/JavaMethodHandle.java
src/share/classes/sun/dyn/JavaMethodHandle.java
+0
-172
src/share/classes/sun/dyn/MethodHandleImpl.java
src/share/classes/sun/dyn/MethodHandleImpl.java
+22
-19
src/share/classes/sun/dyn/SpreadGeneric.java
src/share/classes/sun/dyn/SpreadGeneric.java
+4
-4
src/share/classes/sun/dyn/ToGeneric.java
src/share/classes/sun/dyn/ToGeneric.java
+4
-4
src/share/classes/sun/dyn/util/ValueConversions.java
src/share/classes/sun/dyn/util/ValueConversions.java
+4
-2
src/share/classes/sun/dyn/util/VerifyAccess.java
src/share/classes/sun/dyn/util/VerifyAccess.java
+5
-22
src/share/classes/sun/dyn/util/Wrapper.java
src/share/classes/sun/dyn/util/Wrapper.java
+80
-11
test/java/dyn/InvokeGenericTest.java
test/java/dyn/InvokeGenericTest.java
+1
-1
test/java/dyn/JavaDocExamplesTest.java
test/java/dyn/JavaDocExamplesTest.java
+78
-8
test/java/dyn/MethodHandlesTest.java
test/java/dyn/MethodHandlesTest.java
+96
-49
未找到文件。
src/share/classes/java/dyn/BootstrapMethod.java
已删除
100644 → 0
浏览文件 @
70e0218c
/*
* 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
浏览文件 @
5150d263
...
@@ -26,40 +26,34 @@
...
@@ -26,40 +26,34 @@
package
java.dyn
;
package
java.dyn
;
import
sun.dyn.*
;
import
sun.dyn.*
;
import
sun.dyn.empty.Empty
;
import
sun.misc.Unsafe
;
import
java.util.Collection
;
import
java.util.Collection
;
/**
/**
* A {@code CallSite} is a holder for a variable {@link MethodHandle},
* A {@code CallSite} is a holder for a variable {@link MethodHandle},
* which is called its {@code target}.
* which is called its {@code target}.
* Every call to a {@code CallSite} is delegated to the site's current target.
* An {@code invokedynamic} instruction linked to a {@code CallSite} delegates
* all calls to the site's current target.
* <p>
* <p>
*
A call site is initially created in an <em>unlinked</em> state,
*
If a mutable target is not required, the {@code invokedynamic} instruction
*
which is distinguished by a null target variable
.
*
should be linked to a {@linkplain ConstantCallSite constant call site}
.
*
Before the call site may be invoked (and before certain other
*
If a volatile target is required, because updates to the target must be
*
operations are attempted), the call site must be linked to
*
reliably witnessed by other threads, the {@code invokedynamic} instruction
*
a non-null target
.
*
should be linked to a {@linkplain VolatileCallSite volatile call site}
.
* <p>
* <p>
* A call site may be <em>relinked</em> by changing its target.
* A call site may be <em>relinked</em> by changing its target.
* The new target must be non-null and must have the same
* The new target must have the same {@linkplain MethodHandle#type() type}
* {@linkplain MethodHandle#type() type}
* as the previous target.
* as the previous target.
* Thus, though a call site can be relinked to a series of
* Thus, though a call site can be relinked to a series of
* successive targets, it cannot change its type.
* successive targets, it cannot change its type.
* <p>
* <p>
* Linkage happens once in the lifetime of any given {@code CallSite} object.
* Because of call site invalidation, this linkage can be repeated for
* a single {@code invokedynamic} instruction, with multiple {@code CallSite} objects.
* When a {@code CallSite} is unlinked from an {@code invokedynamic} instruction,
* the instruction is reset so that it is no longer associated with
* the {@code CallSite} object, but the {@code CallSite} does not change
* state.
* <p>
* Here is a sample use of call sites and bootstrap methods which links every
* Here is a sample use of call sites and bootstrap methods which links every
* dynamic call site to print its arguments:
* dynamic call site to print its arguments:
<blockquote><pre><!-- see indy-demo/src/PrintArgsDemo.java -->
<blockquote><pre><!-- see indy-demo/src/PrintArgsDemo.java -->
@BootstrapMethod(value=PrintArgsDemo.class, name="bootstrapDynamic")
static void test() throws Throwable {
static void test() throws Throwable {
InvokeDynamic.baz("baz arg", 2, 3.14);
// THE FOLLOWING LINE IS PSEUDOCODE FOR A JVM INSTRUCTION
InvokeDynamic[#bootstrapDynamic].baz("baz arg", 2, 3.14);
}
}
private static void printArgs(Object... args) {
private static void printArgs(Object... args) {
System.out.println(java.util.Arrays.deepToString(args));
System.out.println(java.util.Arrays.deepToString(args));
...
@@ -71,16 +65,14 @@ static {
...
@@ -71,16 +65,14 @@ static {
printArgs = lookup.findStatic(thisClass,
printArgs = lookup.findStatic(thisClass,
"printArgs", MethodType.methodType(void.class, Object[].class));
"printArgs", MethodType.methodType(void.class, Object[].class));
}
}
private static CallSite bootstrapDynamic(
Class
caller, String name, MethodType type) {
private static CallSite bootstrapDynamic(
MethodHandles.Lookup
caller, String name, MethodType type) {
// ignore caller and name, but match the type:
// ignore caller and name, but match the type:
return new CallSite(MethodHandles.collectArguments(printArgs, type));
return new C
onstantC
allSite(MethodHandles.collectArguments(printArgs, type));
}
}
</pre></blockquote>
</pre></blockquote>
* @author John Rose, JSR 292 EG
* @author John Rose, JSR 292 EG
*/
*/
public
class
CallSite
public
class
CallSite
{
implements
MethodHandleProvider
{
private
static
final
Access
IMPL_TOKEN
=
Access
.
getToken
();
private
static
final
Access
IMPL_TOKEN
=
Access
.
getToken
();
// Fields used only by the JVM. Do not use or change.
// Fields used only by the JVM. Do not use or change.
...
@@ -88,61 +80,44 @@ public class CallSite
...
@@ -88,61 +80,44 @@ public class CallSite
private
int
vmindex
;
// supplied by the JVM (BCI within calling method)
private
int
vmindex
;
// supplied by the JVM (BCI within calling method)
// The actual payload of this call site:
// The actual payload of this call site:
private
MethodHandle
target
;
/*package-private*/
MethodHandle
target
;
// Remove this field for PFD and delete deprecated methods:
// Remove this field for PFD and delete deprecated methods:
private
MemberName
calleeNameRemoveForPFD
;
private
MemberName
calleeNameRemoveForPFD
;
/**
/**
* Make a blank call site object.
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Before it is returned from a bootstrap method, this {@code CallSite} object
* Make a blank call site object with the given method type.
* must be provided with
* An initial target method is supplied which will throw
* a target method via a call to {@link CallSite#setTarget(MethodHandle) setTarget},
* an {@link IllegalStateException} if called.
* or by a subclass override of {@link CallSite#initialTarget(Class,String,MethodType) initialTarget}.
* <p>
* Before this {@code CallSite} object is returned from a bootstrap method,
* it is usually provided with a more useful target method,
* via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
*/
*/
public
CallSite
()
{
public
CallSite
(
MethodType
type
)
{
target
=
MethodHandles
.
invokers
(
type
).
uninitializedCallSite
();
}
}
/**
/**
* Make a blank call site object, possibly equipped with an initial target method handle.
* Make a blank call site object, possibly equipped with an initial target method handle.
* The initial target reference may be null, in which case the {@code CallSite} object
* @param target the method handle which will be the initial target of the call site
* must be provided with a target method via a call to {@link CallSite#setTarget},
* or by a subclass override of {@link CallSite#initialTarget}.
* @param target the method handle which will be the initial target of the call site, or null if there is none yet
*/
*/
public
CallSite
(
MethodHandle
target
)
{
public
CallSite
(
MethodHandle
target
)
{
target
.
type
();
// null check
this
.
target
=
target
;
this
.
target
=
target
;
}
}
/** @deprecated transitional form defined in EDR but removed in PFD */
/**
public
CallSite
(
Class
<?>
caller
,
String
name
,
MethodType
type
)
{
* Report the type of this call site's target.
this
.
calleeNameRemoveForPFD
=
new
MemberName
(
caller
,
name
,
type
);
* Although targets may change, the call site's type can never change.
}
* The {@code setTarget} method enforces this invariant by refusing any new target that does
/** @deprecated transitional form defined in EDR but removed in PFD */
* not have the previous target's type.
public
Class
<?>
callerClass
()
{
* @return the type of the current target, which is also the type of any future target
MemberName
callee
=
this
.
calleeNameRemoveForPFD
;
return
callee
==
null
?
null
:
callee
.
getDeclaringClass
();
}
/** @deprecated transitional form defined in EDR but removed in PFD */
public
String
name
()
{
MemberName
callee
=
this
.
calleeNameRemoveForPFD
;
return
callee
==
null
?
null
:
callee
.
getName
();
}
/** @deprecated transitional form defined in EDR but removed in PFD */
public
MethodType
type
()
{
MemberName
callee
=
this
.
calleeNameRemoveForPFD
;
return
callee
==
null
?
(
target
==
null
?
null
:
target
.
type
())
:
callee
.
getMethodType
();
}
/** @deprecated transitional form defined in EDR but removed in PFD */
protected
MethodHandle
initialTarget
()
{
return
initialTarget
(
callerClass
(),
name
(),
type
());
}
/** Report if the JVM has linked this {@code CallSite} object to a dynamic call site instruction.
* Once it is linked, it is never unlinked.
*/
*/
p
rivate
boolean
isLinked
()
{
p
ublic
MethodType
type
()
{
return
vmmethod
!=
null
;
return
target
.
type
()
;
}
}
/** Called from JVM (or low-level Java code) after the BSM returns the newly created CallSite.
/** Called from JVM (or low-level Java code) after the BSM returns the newly created CallSite.
...
@@ -152,68 +127,66 @@ public class CallSite
...
@@ -152,68 +127,66 @@ public class CallSite
MethodType
type
,
MethodType
type
,
MemberName
callerMethod
,
MemberName
callerMethod
,
int
callerBCI
)
{
int
callerBCI
)
{
if
(
this
.
isLinked
())
{
if
(
this
.
vmmethod
!=
null
)
{
// FIXME
throw
new
InvokeDynamicBootstrapError
(
"call site has already been linked to an invokedynamic instruction"
);
throw
new
InvokeDynamicBootstrapError
(
"call site has already been linked to an invokedynamic instruction"
);
}
}
MethodHandle
target
=
this
.
target
;
if
(!
this
.
type
().
equals
(
type
))
{
if
(
target
==
null
)
{
this
.
target
=
target
=
this
.
initialTarget
(
callerMethod
.
getDeclaringClass
(),
name
,
type
);
}
if
(!
target
.
type
().
equals
(
type
))
{
throw
wrongTargetType
(
target
,
type
);
throw
wrongTargetType
(
target
,
type
);
}
}
this
.
vmindex
=
callerBCI
;
this
.
vmindex
=
callerBCI
;
this
.
vmmethod
=
callerMethod
;
this
.
vmmethod
=
callerMethod
;
assert
(
this
.
isLinked
());
}
}
/**
/**
* Just after a call site is created by a bootstrap method handle,
* Report the current linkage state of the call site, a value which may change over time.
* if the target has not been initialized by the factory method itself,
* the method {@code initialTarget} is called to produce an initial
* non-null target. (Live call sites must never have null targets.)
* <p>
* The arguments are the same as those passed to the bootstrap method.
* Thus, a bootstrap method is free to ignore the arguments and simply
* create a "blank" {@code CallSite} object of an appropriate subclass.
* <p>
* <p>
* If the bootstrap method itself does not initialize the call site,
* If a {@code CallSite} object is returned
* this method must be overridden, because it just raises an
* from the bootstrap method of the {@code invokedynamic} instruction,
* {@code InvokeDynamicBootstrapError}, which in turn causes the
* the {@code CallSite} is permanently bound to that instruction.
* linkage of the {@code invokedynamic} instruction to terminate
* When the {@code invokedynamic} instruction is executed, the target method
* abnormally.
* of its associated call site object is invoked directly.
* @deprecated transitional form defined in EDR but removed in PFD
* It is as if the instruction calls {@code getTarget} and then
*/
* calls {@link MethodHandle#invokeExact invokeExact} on the result.
protected
MethodHandle
initialTarget
(
Class
<?>
callerClass
,
String
name
,
MethodType
type
)
{
throw
new
InvokeDynamicBootstrapError
(
"target must be initialized before call site is linked: "
+
name
+
type
);
}
/**
* Report the current linkage state of the call site. (This is mutable.)
* The value may not be null after the {@code CallSite} object is returned
* from the bootstrap method of the {@code invokedynamic} instruction.
* When an {@code invokedynamic} instruction is executed, the target method
* of its associated {@code call site} object is invoked directly,
* as if via {@link MethodHandle}{@code .invoke}.
* <p>
* <p>
* The interactions of {@code getTarget} with memory are the same
* Unless specified differently by a subclass,
* the interactions of {@code getTarget} with memory are the same
* as of a read from an ordinary variable, such as an array element or a
* as of a read from an ordinary variable, such as an array element or a
* non-volatile, non-final field.
* non-volatile, non-final field.
* <p>
* <p>
* In particular, the current thread may choose to reuse the result
* In particular, the current thread may choose to reuse the result
* of a previous read of the target from memory, and may fail to see
* of a previous read of the target from memory, and may fail to see
* a recent update to the target by another thread.
* a recent update to the target by another thread.
* @return the current linkage state of the call site
* <p>
* In a {@linkplain ConstantCallSite constant call site}, the {@code getTarget} method behaves
* like a read from a {@code final} field of the {@code CallSite}.
* <p>
* In a {@linkplain VolatileCallSite volatile call site}, the {@code getTarget} method behaves
* like a read from a {@code volatile} field of the {@code CallSite}.
* <p>
* This method may not be overridden by application code.
* @return the current linkage state of the call site, its target method handle
* @see ConstantCallSite
* @see VolatileCallSite
* @see #setTarget
* @see #setTarget
*/
*/
public
MethodHandle
getTarget
()
{
public
final
MethodHandle
getTarget
()
{
return
getTarget0
();
}
/**
* Privileged implementations can override this to force final or volatile semantics on getTarget.
*/
/*package-private*/
MethodHandle
getTarget0
()
{
return
target
;
return
target
;
}
}
/**
/**
* Set the target method of this call site.
* Set the target method of this call site.
* <p>
* <p>
* The interactions of {@code setTarget} with memory are the same
* Unless a subclass of CallSite documents otherwise,
* the interactions of {@code setTarget} with memory are the same
* as of a write to an ordinary variable, such as an array element or a
* as of a write to an ordinary variable, such as an array element or a
* non-volatile, non-final field.
* non-volatile, non-final field.
* <p>
* <p>
...
@@ -224,27 +197,23 @@ public class CallSite
...
@@ -224,27 +197,23 @@ public class CallSite
* at any given call site.
* at any given call site.
* @param newTarget the new target
* @param newTarget the new target
* @throws NullPointerException if the proposed new target is null
* @throws NullPointerException if the proposed new target is null
* @throws WrongMethodTypeException if the
call site is linked and the
proposed new target
* @throws WrongMethodTypeException if the proposed new target
* has a method type that differs from the previous target
* has a method type that differs from the previous target
*/
*/
public
void
setTarget
(
MethodHandle
newTarget
)
{
public
void
setTarget
(
MethodHandle
newTarget
)
{
MethodType
newType
=
newTarget
.
type
();
// null check!
checkTargetChange
(
this
.
target
,
newTarget
);
MethodHandle
oldTarget
=
this
.
target
;
setTargetNormal
(
newTarget
);
if
(
oldTarget
==
null
)
{
}
// CallSite is not yet linked.
assert
(!
isLinked
());
void
checkTargetChange
(
MethodHandle
oldTarget
,
MethodHandle
newTarget
)
{
this
.
target
=
newTarget
;
// might be null!
return
;
}
MethodType
oldType
=
oldTarget
.
type
();
MethodType
oldType
=
oldTarget
.
type
();
if
(!
newTarget
.
type
().
equals
(
oldType
))
MethodType
newType
=
newTarget
.
type
();
// null check!
if
(!
newType
.
equals
(
oldType
))
throw
wrongTargetType
(
newTarget
,
oldType
);
throw
wrongTargetType
(
newTarget
,
oldType
);
if
(
oldTarget
!=
newTarget
)
CallSiteImpl
.
setCallSiteTarget
(
IMPL_TOKEN
,
this
,
newTarget
);
}
}
private
static
WrongMethodTypeException
wrongTargetType
(
MethodHandle
target
,
MethodType
type
)
{
private
static
WrongMethodTypeException
wrongTargetType
(
MethodHandle
target
,
MethodType
type
)
{
return
new
WrongMethodTypeException
(
String
.
valueOf
(
target
)+
target
.
type
()+
" should be of type "
+
type
);
return
new
WrongMethodTypeException
(
String
.
valueOf
(
target
)+
" should be of type "
+
type
);
}
}
/** Produce a printed representation that displays information about this call site
/** Produce a printed representation that displays information about this call site
...
@@ -252,15 +221,14 @@ public class CallSite
...
@@ -252,15 +221,14 @@ public class CallSite
*/
*/
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
return
"CallSite"
+(
target
==
null
?
""
:
target
.
type
()
);
return
super
.
toString
()
+
type
(
);
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle equivalent to an invokedynamic instruction
* Produce a method handle equivalent to an invokedynamic instruction
* which has been linked to this call site.
* which has been linked to this call site.
* <p>If this call site is a {@link
ConstantCallSite}, this method
* <p>If this call site is a {@link
plain ConstantCallSite constant call site},
*
simply returns the call site's target, since that will not
change.
*
this method simply returns the call site's target, since that will never
change.
* <p>Otherwise, this method is equivalent to the following code:
* <p>Otherwise, this method is equivalent to the following code:
* <p><blockquote><pre>
* <p><blockquote><pre>
* MethodHandle getTarget, invoker, result;
* MethodHandle getTarget, invoker, result;
...
@@ -271,8 +239,9 @@ public class CallSite
...
@@ -271,8 +239,9 @@ public class CallSite
* @return a method handle which always invokes this call site's current target
* @return a method handle which always invokes this call site's current target
*/
*/
public
final
MethodHandle
dynamicInvoker
()
{
public
final
MethodHandle
dynamicInvoker
()
{
if
(
this
instanceof
ConstantCallSite
)
if
(
this
instanceof
ConstantCallSite
)
{
return
getTarget
();
// will not change dynamically
return
target
;
// will not change dynamically
}
MethodHandle
getTarget
=
MethodHandleImpl
.
bindReceiver
(
IMPL_TOKEN
,
GET_TARGET
,
this
);
MethodHandle
getTarget
=
MethodHandleImpl
.
bindReceiver
(
IMPL_TOKEN
,
GET_TARGET
,
this
);
MethodHandle
invoker
=
MethodHandles
.
exactInvoker
(
this
.
type
());
MethodHandle
invoker
=
MethodHandles
.
exactInvoker
(
this
.
type
());
return
MethodHandles
.
foldArguments
(
invoker
,
getTarget
);
return
MethodHandles
.
foldArguments
(
invoker
,
getTarget
);
...
@@ -287,9 +256,34 @@ public class CallSite
...
@@ -287,9 +256,34 @@ public class CallSite
}
}
}
}
/** Implementation of {@link MethodHandleProvider} which returns {@code this.dynamicInvoker()}. */
/** This guy is rolled into the default target if a MethodType is supplied to the constructor. */
public
final
MethodHandle
asMethodHandle
()
{
return
dynamicInvoker
();
}
/*package-private*/
static
Empty
uninitializedCallSite
()
{
throw
new
IllegalStateException
(
"uninitialized call site"
);
}
// unsafe stuff:
private
static
final
Unsafe
unsafe
=
Unsafe
.
getUnsafe
();
private
static
final
long
TARGET_OFFSET
;
static
{
try
{
TARGET_OFFSET
=
unsafe
.
objectFieldOffset
(
CallSite
.
class
.
getDeclaredField
(
"target"
));
}
catch
(
Exception
ex
)
{
throw
new
Error
(
ex
);
}
}
/** Implementation of {@link MethodHandleProvider}, which returns {@code this.dynamicInvoker().asType(type)}. */
/*package-private*/
public
final
MethodHandle
asMethodHandle
(
MethodType
type
)
{
return
dynamicInvoker
().
asType
(
type
);
}
void
setTargetNormal
(
MethodHandle
newTarget
)
{
target
=
newTarget
;
//CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget);
}
/*package-private*/
MethodHandle
getTargetVolatile
()
{
return
(
MethodHandle
)
unsafe
.
getObjectVolatile
(
this
,
TARGET_OFFSET
);
}
/*package-private*/
void
setTargetVolatile
(
MethodHandle
newTarget
)
{
unsafe
.
putObjectVolatile
(
this
,
TARGET_OFFSET
,
newTarget
);
//CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget);
}
}
}
src/share/classes/java/dyn/ConstantCallSite.java
浏览文件 @
5150d263
...
@@ -27,8 +27,8 @@ package java.dyn;
...
@@ -27,8 +27,8 @@ package java.dyn;
/**
/**
* A {@code ConstantCallSite} is a {@link CallSite} whose target is permanent, and can never be changed.
* 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
*
An {@code invokedynamic} instruction linked to a {@code ConstantCallSite} is permanently
*
to invalidate the instruction as a whole
.
*
bound to the call site's target
.
* @author John Rose, JSR 292 EG
* @author John Rose, JSR 292 EG
*/
*/
public
class
ConstantCallSite
extends
CallSite
{
public
class
ConstantCallSite
extends
CallSite
{
...
@@ -36,7 +36,9 @@ public class ConstantCallSite extends CallSite {
...
@@ -36,7 +36,9 @@ public class ConstantCallSite extends CallSite {
public
ConstantCallSite
(
MethodHandle
target
)
{
public
ConstantCallSite
(
MethodHandle
target
)
{
super
(
target
);
super
(
target
);
}
}
/** Throw an {@link IllegalArgumentException}, because this kind of call site cannot change its target. */
/**
* Throw an {@link IllegalArgumentException}, because this kind of call site cannot change its target.
*/
@Override
public
final
void
setTarget
(
MethodHandle
ignore
)
{
@Override
public
final
void
setTarget
(
MethodHandle
ignore
)
{
throw
new
IllegalArgumentException
(
"ConstantCallSite"
);
throw
new
IllegalArgumentException
(
"ConstantCallSite"
);
}
}
...
...
src/share/classes/java/dyn/InvokeDynamic.java
已删除
100644 → 0
浏览文件 @
70e0218c
/*
* Copyright (c) 2008, 2009, 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
;
/**
* {@code InvokeDynamic} is a class with neither methods nor instances,
* which serves only as a syntactic marker in Java source code for
* an {@code invokedynamic} instruction.
* (See <a href="package-summary.html#jvm_mods">the package information</a> for specifics on this instruction.)
* <p>
* The {@code invokedynamic} instruction is incomplete without a target method.
* 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 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
* class or interface supertype, or an object type; it can never be instantiated.
* Logically, it denotes a source of all dynamically typed methods.
* It may be viewed as a pure syntactic marker of static calls.
* It may be imported for ease of use.
* <p>
* Here are some examples:
<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 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 declared for the enclosing class or method.
* @author John Rose, JSR 292 EG
*/
@MethodHandle
.
PolymorphicSignature
public
final
class
InvokeDynamic
{
private
InvokeDynamic
()
{
throw
new
InternalError
();
}
// do not instantiate
// no statically defined static methods
}
src/share/classes/java/dyn/Linkage.java
浏览文件 @
5150d263
...
@@ -29,15 +29,16 @@ import java.dyn.MethodHandles.Lookup;
...
@@ -29,15 +29,16 @@ import java.dyn.MethodHandles.Lookup;
import
java.util.WeakHashMap
;
import
java.util.WeakHashMap
;
import
sun.dyn.Access
;
import
sun.dyn.Access
;
import
sun.dyn.MethodHandleImpl
;
import
sun.dyn.MethodHandleImpl
;
import
sun.dyn.util.VerifyAccess
;
import
sun.reflect.Reflection
;
import
sun.reflect.Reflection
;
import
static
sun
.
dyn
.
util
.
VerifyAccess
.
checkBootstrapPrivilege
;
import
static
sun
.
dyn
.
MemberName
.
newIllegalArgumentException
;
import
static
sun
.
dyn
.
MemberName
.
newIllegalArgumentException
;
/**
/**
*
This class consists exclusively of static methods that control
*
<em>CLASS WILL BE REMOVED FOR PFD:</em>
*
the linkage of {@code invokedynamic} instructions, and specifically
*
Static routines for controlling invokedynamic behavior.
*
their reification as {@link CallSite} object
s.
*
Replaced by non-static API
s.
* @author John Rose, JSR 292 EG
* @author John Rose, JSR 292 EG
* @deprecated This class will be removed in the Public Final Draft.
*/
*/
public
class
Linkage
{
public
class
Linkage
{
private
static
final
Access
IMPL_TOKEN
=
Access
.
getToken
();
private
static
final
Access
IMPL_TOKEN
=
Access
.
getToken
();
...
@@ -45,68 +46,24 @@ public class Linkage {
...
@@ -45,68 +46,24 @@ public class Linkage {
private
Linkage
()
{}
// do not instantiate
private
Linkage
()
{}
// do not instantiate
/**
/**
* <em>
PROVISIONAL API, WORK IN PROGRESS
:</em>
* <em>
METHOD WILL BE REMOVED FOR PFD
:</em>
* Register a <em>bootstrap method</em> to use when linking dynamic call sites within
* Register a <em>bootstrap method</em> to use when linking dynamic call sites within
* a given caller class.
* a given caller class.
* <p>
* @deprecated Use @{@link BootstrapMethod} annotations instead.
* A bootstrap method must be a method handle with a return type of {@link CallSite}
* and the following arguments:
* <ul>
* <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})
* </ul>
* 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>
* The registration must take place exactly once, either before the class has begun
* being initialized, or from within the class's static initializer.
* Registration will fail with an exception if any of the following conditions hold:
* <ul>
* <li>The immediate caller of this method is in a different package than the given caller class,
* and there is a security manager, and its {@code checkPermission} call throws
* when passed {@link LinkagePermission}("registerBootstrapMethod",callerClass).
* <li>The given caller class already has a bootstrap method registered.
* <li>The given caller class is already fully initialized.
* <li>The given caller class is in the process of initialization, in another thread.
* </ul>
* Because of these rules, a class may install its own bootstrap method in
* a static initializer.
* @param callerClass a class that may have {@code invokedynamic} sites
* @param bootstrapMethod the method to use to bootstrap all such sites
* @exception IllegalArgumentException if the class argument is null or
* a primitive class, or if the bootstrap method is the wrong type
* @exception IllegalStateException if the class already has a bootstrap
* method, or if the its static initializer has already run
* 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
public
static
void
registerBootstrapMethod
(
Class
callerClass
,
MethodHandle
bootstrapMethod
)
{
void
registerBootstrapMethod
(
Class
callerClass
,
MethodHandle
bootstrapMethod
)
{
Class
callc
=
Reflection
.
getCallerClass
(
2
);
Class
callc
=
Reflection
.
getCallerClass
(
2
);
checkBootstrapPrivilege
(
callc
,
callerClass
,
"registerBootstrapMethod"
);
if
(
callc
!=
null
&&
!
VerifyAccess
.
isSamePackage
(
callerClass
,
callc
))
checkBSM
(
bootstrapMethod
);
throw
new
IllegalArgumentException
(
"cannot set bootstrap method on "
+
callerClass
);
MethodHandleImpl
.
registerBootstrap
(
IMPL_TOKEN
,
callerClass
,
bootstrapMethod
);
MethodHandleImpl
.
registerBootstrap
(
IMPL_TOKEN
,
callerClass
,
bootstrapMethod
);
}
}
static
private
void
checkBSM
(
MethodHandle
mh
)
{
if
(
mh
==
null
)
throw
newIllegalArgumentException
(
"null bootstrap method"
);
if
(
mh
.
type
()
==
BOOTSTRAP_METHOD_TYPE
)
return
;
throw
new
WrongMethodTypeException
(
mh
.
toString
());
}
/**
/**
* <em>
PROVISIONAL API, WORK IN PROGRESS
:</em>
* <em>
METHOD WILL BE REMOVED FOR PFD
:</em>
* Simplified version of {@code registerBootstrapMethod} for self-registration,
* Simplified version of {@code registerBootstrapMethod} for self-registration,
* to be called from a static initializer.
* to be called from a static initializer.
* Finds a static method of the required type in the
* @deprecated Use @{@link BootstrapMethod} annotations instead.
* given runtime class, and installs it on the caller class.
* @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
public
static
void
registerBootstrapMethod
(
Class
<?>
runtime
,
String
name
)
{
void
registerBootstrapMethod
(
Class
<?>
runtime
,
String
name
)
{
...
@@ -115,15 +72,9 @@ public class Linkage {
...
@@ -115,15 +72,9 @@ public class Linkage {
}
}
/**
/**
* <em>
PROVISIONAL API, WORK IN PROGRESS
:</em>
* <em>
METHOD WILL BE REMOVED FOR PFD
:</em>
* Simplified version of {@code registerBootstrapMethod} for self-registration,
* Simplified version of {@code registerBootstrapMethod} for self-registration,
* to be called from a static initializer.
* @deprecated Use @{@link BootstrapMethod} annotations instead.
* Finds a static method of the required type in the
* caller class itself, and installs it on the caller class.
* @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
public
static
void
registerBootstrapMethod
(
String
name
)
{
void
registerBootstrapMethod
(
String
name
)
{
...
@@ -140,82 +91,33 @@ public class Linkage {
...
@@ -140,82 +91,33 @@ public class Linkage {
}
catch
(
NoAccessException
ex
)
{
}
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
);
MethodHandleImpl
.
registerBootstrap
(
IMPL_TOKEN
,
callerClass
,
bootstrapMethod
);
}
}
/**
private
static
final
MethodType
BOOTSTRAP_METHOD_TYPE
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Report the bootstrap method registered for a given caller class.
* Returns null if the class has never yet registered a bootstrap method.
* Only callers privileged to set the bootstrap method may inquire
* about it, because a bootstrap method is potentially a back-door entry
* point into its class.
* @exception IllegalArgumentException if the argument is null or
* a primitive class
* @exception SecurityException if there is a security manager installed,
* 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
)
{
Class
callc
=
Reflection
.
getCallerClass
(
2
);
checkBootstrapPrivilege
(
callc
,
callerClass
,
"getBootstrapMethod"
);
return
MethodHandleImpl
.
getBootstrap
(
IMPL_TOKEN
,
callerClass
);
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* The type of any bootstrap method is a three-argument method
* {@code (Class, String, MethodType)} returning a {@code CallSite}.
*/
public
static
final
MethodType
BOOTSTRAP_METHOD_TYPE
=
MethodType
.
methodType
(
CallSite
.
class
,
=
MethodType
.
methodType
(
CallSite
.
class
,
Class
.
class
,
String
.
class
,
MethodType
.
class
);
Class
.
class
,
String
.
class
,
MethodType
.
class
);
/**
/**
* <em>
PROVISIONAL API, WORK IN PROGRESS
:</em>
* <em>
METHOD WILL BE REMOVED FOR PFD
:</em>
* Invalidate all <code>invokedynamic</code> call sites everywhere.
* Invalidate all <code>invokedynamic</code> call sites everywhere.
* <p>
* @deprecated Use {@linkplain CallSite#setTarget call site target setting}
* When this method returns, every <code>invokedynamic</code> instruction
* and {@link VolatileCallSite#invalidateAll call site invalidation} instead.
* will invoke its bootstrap method on next call.
* <p>
* It is unspecified whether call sites already known to the Java
* code will continue to be associated with <code>invokedynamic</code>
* instructions. If any call site is still so associated, its
* {@link CallSite#getTarget()} method is guaranteed to return null
* the invalidation operation completes.
* <p>
* Invalidation operations are likely to be slow. Use them sparingly.
*/
*/
public
static
public
static
Object
invalidateAll
()
{
Object
invalidateAll
()
{
SecurityManager
security
=
System
.
getSecurityManager
();
throw
new
UnsupportedOperationException
();
if
(
security
!=
null
)
{
security
.
checkPermission
(
new
LinkagePermission
(
"invalidateAll"
));
}
throw
new
UnsupportedOperationException
(
"NYI"
);
}
}
/**
/**
* <em>
PROVISIONAL API, WORK IN PROGRESS
:</em>
* <em>
METHOD WILL BE REMOVED FOR PFD
:</em>
* Invalidate all {@code invokedynamic} call sites in the bytecodes
* Invalidate all {@code invokedynamic} call sites in the bytecodes
* of any methods of the given class.
* of any methods of the given class.
* <p>
* @deprecated Use {@linkplain CallSite#setTarget call site target setting}
* When this method returns, every matching <code>invokedynamic</code>
* and {@link VolatileCallSite#invalidateAll call site invalidation} instead.
* instruction will invoke its bootstrap method on next call.
* <p>
* For additional semantics of call site invalidation,
* see {@link #invalidateAll()}.
*/
*/
public
static
public
static
Object
invalidateCallerClass
(
Class
<?>
callerClass
)
{
Object
invalidateCallerClass
(
Class
<?>
callerClass
)
{
SecurityManager
security
=
System
.
getSecurityManager
();
throw
new
UnsupportedOperationException
();
if
(
security
!=
null
)
{
security
.
checkPermission
(
new
LinkagePermission
(
"invalidateAll"
,
callerClass
));
}
throw
new
UnsupportedOperationException
(
"NYI"
);
}
}
}
}
src/share/classes/java/dyn/LinkagePermission.java
已删除
100644 → 0
浏览文件 @
70e0218c
/*
* Copyright (c) 2008, 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.security.*
;
import
java.util.Enumeration
;
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,
* a {@code LinkagePermission} contains a target name but
* no actions list; you either have the named permission
* or you don't.
* <p>
* The following table lists all the possible {@code LinkagePermission} target names,
* and for each provides a description of what the permission allows
* and a discussion of the risks of granting code the permission.
* <p>
*
* <table border=1 cellpadding=5 summary="permission target name,
* what the target allows,and associated risks">
* <tr>
* <th>Permission Target Name</th>
* <th>What the Permission Allows</th>
* <th>Risks of Allowing this Permission</th>
* </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,
* or perhaps expose timing bugs in a dynamic language implementations,
* by forcing redundant relinking operations.</td>
* </tr>
*
*
* <tr>
* <td>invalidateCallerClass.{class name}</td>
* <td>Force the relinking of invokedynamic call sites in the given class.</td>
* <td>See {@code invalidateAll}.</td>
* </tr>
* </table>
* <p>ISSUE: Is this still needed?
*
* @see java.lang.RuntimePermission
* @see java.lang.SecurityManager
*
* @author John Rose, JSR 292 EG
*/
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
* "invalidateCallerClass.*", etc. An asterisk
* may appear at the end of the name, following a ".", or by itself, to
* signify a wildcard match.
*
* @param name the name of the LinkagePermission
*/
public
LinkagePermission
(
String
name
)
{
super
(
name
);
}
/**
* Create a new LinkagePermission with the given name on the given class.
* Equivalent to {@code LinkagePermission(name+"."+clazz.getName())}.
*
* @param name the name of the LinkagePermission
* @param clazz the class affected by the permission
*/
public
LinkagePermission
(
String
name
,
Class
<?>
clazz
)
{
super
(
name
+
"."
+
clazz
.
getName
());
}
}
src/share/classes/java/dyn/MethodHandle.java
浏览文件 @
5150d263
...
@@ -37,20 +37,29 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
...
@@ -37,20 +37,29 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
* A method handle is a typed, directly executable reference to a method,
* A method handle is a typed, directly executable reference to a method,
* constructor, field, or similar low-level operation, with optional
* constructor, field, or similar low-level operation, with optional
* transformations of arguments or return values.
* transformations of arguments or return values.
* (These transformations include conversion, insertion, deletion,
* These transformations are quite general, and include such patterns as
* substitution. See the methods of this class and of {@link MethodHandles}.)
* {@linkplain #asType conversion},
* {@linkplain #bindTo insertion},
* {@linkplain java.dyn.MethodHandles#dropArguments deletion},
* and {@linkplain java.dyn.MethodHandles#filterArguments substitution}.
* <p>
* <em>Note: The super-class of MethodHandle is Object.
* Any other super-class visible in the Reference Implementation
* will be removed before the Proposed Final Draft.
* Also, the final version will not include any public or
* protected constructors.</em>
* <p>
* <p>
* Method handles are strongly typed according to signature.
* Method handles are strongly typed according to signature.
* They are not distinguished by method name or enclosing class.
* They are not distinguished by method name or enclosing class.
* A method handle must be invoked under a signature which matches
* A method handle must be invoked under a signature which matches
* the method handle's own {@link MethodType method type}.
* the method handle's own {@link
plain
MethodType method type}.
* <p>
* <p>
* Every method handle
confesses its type via the {@cod
e type} accessor.
* Every method handle
reports its type via the {@link #typ
e type} accessor.
* The structure of this type is a series of classes, one of which is
* The structure of this type is a series of classes, one of which is
* the return type of the method (or {@code void.class} if none).
* the return type of the method (or {@code void.class} if none).
* <p>
* <p>
* Every method handle appears as an object containing a method named
* Every method handle appears as an object containing a method named
* {@
code invoke
}, whose signature exactly matches
* {@
link #invokeExact invokeExact
}, whose signature exactly matches
* the method handle's type.
* the method handle's type.
* A Java method call expression, which compiles to an
* A Java method call expression, which compiles to an
* {@code invokevirtual} instruction,
* {@code invokevirtual} instruction,
...
@@ -61,15 +70,29 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
...
@@ -61,15 +70,29 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
* (The type is specified in the {@code invokevirtual} instruction,
* (The type is specified in the {@code invokevirtual} instruction,
* via a {@code CONSTANT_NameAndType} constant pool entry.)
* via a {@code CONSTANT_NameAndType} constant pool entry.)
* The call looks within the receiver object for a method
* The call looks within the receiver object for a method
* named {@code invoke} of the intended method type.
* named {@code invoke
Exact
} of the intended method type.
* The call fails with a {@link WrongMethodTypeException}
* The call fails with a {@link WrongMethodTypeException}
* if the method does not exist, even if there is an {@code invoke}
* if the method does not exist, even if there is an {@code invoke
Exact
}
* method of a closely similar signature.
* method of a closely similar signature.
* As with other kinds
* As with other kinds
* of methods in the JVM, signature matching during method linkage
* of methods in the JVM, signature matching during method linkage
* is exact, and does not allow for language-level implicit conversions
* is exact, and does not allow for language-level implicit conversions
* such as {@code String} to {@code Object} or {@code short} to {@code int}.
* such as {@code String} to {@code Object} or {@code short} to {@code int}.
* <p>
* <p>
* Each individual method handle also contains a method named
* {@link #invokeGeneric invokeGeneric}, whose type is the same
* as {@code invokeExact}, and is therefore also reported by
* the {@link #type type} accessor.
* A call to {@code invokeGeneric} works the same as a call to
* {@code invokeExact}, if the signature specified by the caller
* exactly matches the method handle's own type.
* If there is a type mismatch, {@code invokeGeneric} attempts
* to adjust the type of the target method handle
* (as if by a call to {@link #asType asType})
* to obtain an exactly invokable target.
* This allows a more powerful negotiation of method type
* between caller and callee.
* <p>
* A method handle is an unrestricted capability to call a method.
* A method handle is an unrestricted capability to call a method.
* A method handle can be formed on a non-public method by a class
* A method handle can be formed on a non-public method by a class
* that has access to that method; the resulting handle can be used
* that has access to that method; the resulting handle can be used
...
@@ -77,31 +100,44 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
...
@@ -77,31 +100,44 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
* checking is performed when the method handle is created, not
* checking is performed when the method handle is created, not
* (as in reflection) every time it is called. Handles to non-public
* (as in reflection) every time it is called. Handles to non-public
* methods, or in non-public classes, should generally be kept secret.
* methods, or in non-public classes, should generally be kept secret.
* They should not be passed to untrusted code.
* They should not be passed to untrusted code unless their use from
* the untrusted code would be harmless.
* <p>
* <p>
* Bytecode in
an extended
JVM can directly call a method handle's
* Bytecode in
the
JVM can directly call a method handle's
* {@code invoke
}
from an {@code invokevirtual} instruction.
* {@code invoke
Exact} method
from an {@code invokevirtual} instruction.
* The receiver class type must be {@code MethodHandle} and the method name
* The receiver class type must be {@code MethodHandle} and the method name
* must be {@code invoke}. The signature of the invocation
* must be {@code invoke
Exact
}. The signature of the invocation
* (after resolving symbolic type names) must exactly match the method type
* (after resolving symbolic type names) must exactly match the method type
* of the target method.
* of the target method.
* Similarly, bytecode can directly call a method handle's {@code invokeGeneric}
* method. The signature of the invocation (after resolving symbolic type names)
* must either exactly match the method type or be a valid argument to
* the target's {@link #asType asType} method.
* <p>
* <p>
* Every {@code invoke} method always throws {@link Exception},
* Every {@code invokeExact} and {@code invokeGeneric} method always
* throws {@link java.lang.Throwable Throwable},
* which is to say that there is no static restriction on what a method handle
* which is to say that there is no static restriction on what a method handle
* can throw. Since the JVM does not distinguish between checked
* can throw. Since the JVM does not distinguish between checked
* and unchecked exceptions (other than by their class, of course),
* and unchecked exceptions (other than by their class, of course),
* there is no particular effect on bytecode shape from ascribing
* there is no particular effect on bytecode shape from ascribing
* checked exceptions to method handle invocations. But in Java source
* checked exceptions to method handle invocations. But in Java source
* code, methods which perform method handle calls must either explicitly
* code, methods which perform method handle calls must either explicitly
* throw {@code Exception}, or else must catch all checked exceptions locally.
* throw {@code java.lang.Throwable Throwable}, or else must catch all
* throwables locally, rethrowing only those which are legal in the context,
* and wrapping ones which are illegal.
* <p>
* <p>
* Bytecode in
an extended
JVM can directly obtain a method handle
* Bytecode in
the
JVM can directly obtain a method handle
* for any accessible method from a {@code ldc} instruction
* for any accessible method from a {@code ldc} instruction
* which refers to a {@code CONSTANT_Methodref} or
* which refers to a {@code CONSTANT_Methodref} or
* {@code CONSTANT_InterfaceMethodref} constant pool entry.
* {@code CONSTANT_InterfaceMethodref} constant pool entry.
* <p>
* <p>
* All JVMs can also use a reflective API called {@code MethodHandles}
* Java code can also use a reflective API called
* {@link java.dyn.MethodHandles.Lookup MethodHandles.Lookup}
* for creating and calling method handles.
* for creating and calling method handles.
* For example, a static method handle can be obtained
* from {@link java.dyn.MethodHandles.Lookup#findStatic Lookup.findStatic}.
* There are also bridge methods from Core Reflection API objects,
* such as {@link java.dyn.MethodHandles.Lookup#unreflect Lookup.ureflect}.
* <p>
* <p>
* A method reference may refer either to a static or non-static method.
* A method reference may refer either to a static or non-static method.
* In the non-static case, the method handle type includes an explicit
* In the non-static case, the method handle type includes an explicit
...
@@ -131,7 +167,7 @@ mh = lookup.findVirtual(String.class, "replace", mt);
...
@@ -131,7 +167,7 @@ mh = lookup.findVirtual(String.class, "replace", mt);
s = mh.<String>invokeExact("daddy",'d','n');
s = mh.<String>invokeExact("daddy",'d','n');
assert(s.equals("nanny"));
assert(s.equals("nanny"));
// weakly typed invocation (using MHs.invoke)
// weakly typed invocation (using MHs.invoke)
s = (String) mh.invoke
Vararg
s("sappy", 'p', 'v');
s = (String) mh.invoke
WithArgument
s("sappy", 'p', 'v');
assert(s.equals("savvy"));
assert(s.equals("savvy"));
// mt is {Object[] => List}
// mt is {Object[] => List}
mt = MethodType.methodType(java.util.List.class, Object[].class);
mt = MethodType.methodType(java.util.List.class, Object[].class);
...
@@ -162,7 +198,7 @@ assert(i == 3);
...
@@ -162,7 +198,7 @@ assert(i == 3);
* Java types.
* Java types.
* <ol>
* <ol>
* <li>Method types range over all possible arities,
* <li>Method types range over all possible arities,
* from no arguments to
an arbitrary number of arguments
.
* from no arguments to
up to 255 of arguments (a limit imposed by the JVM)
.
* Generics are not variadic, and so cannot represent this.</li>
* Generics are not variadic, and so cannot represent this.</li>
* <li>Method types can specify arguments of primitive types,
* <li>Method types can specify arguments of primitive types,
* which Java generic types cannot range over.</li>
* which Java generic types cannot range over.</li>
...
@@ -189,7 +225,6 @@ public abstract class MethodHandle
...
@@ -189,7 +225,6 @@ public abstract class MethodHandle
// Note: This is an implementation inheritance hack, and will be removed
// Note: This is an implementation inheritance hack, and will be removed
// with a JVM change which moves the required hidden state onto this class.
// with a JVM change which moves the required hidden state onto this class.
extends
MethodHandleImpl
extends
MethodHandleImpl
implements
MethodHandleProvider
{
{
private
static
Access
IMPL_TOKEN
=
Access
.
getToken
();
private
static
Access
IMPL_TOKEN
=
Access
.
getToken
();
...
@@ -208,7 +243,7 @@ public abstract class MethodHandle
...
@@ -208,7 +243,7 @@ public abstract class MethodHandle
/**
/**
* Report the type of this method handle.
* Report the type of this method handle.
* Every invocation of this method handle must exactly match this type.
* Every invocation of this method handle
via {@code invokeExact}
must exactly match this type.
* @return the method handle type
* @return the method handle type
*/
*/
public
final
MethodType
type
()
{
public
final
MethodType
type
()
{
...
@@ -216,12 +251,16 @@ public abstract class MethodHandle
...
@@ -216,12 +251,16 @@ public abstract class MethodHandle
}
}
/**
/**
* The constructor for MethodHandle may only be called by privileged code.
* <em>CONSTRUCTOR WILL BE REMOVED FOR PFD:</em>
* Subclasses may be in other packages, but must possess
* Temporary constructor in early versions of the Reference Implementation.
* a token which they obtained from MH with a security check.
* Method handle inheritance (if any) will be contained completely within
* @param token non-null object which proves access permission
* the {@code java.dyn} package.
* @param type type (permanently assigned) of the new method handle
*/
*/
// The constructor for MethodHandle may only be called by privileged code.
// Subclasses may be in other packages, but must possess
// a token which they obtained from MH with a security check.
// @param token non-null object which proves access permission
// @param type type (permanently assigned) of the new method handle
protected
MethodHandle
(
Access
token
,
MethodType
type
)
{
protected
MethodHandle
(
Access
token
,
MethodType
type
)
{
super
(
token
);
super
(
token
);
Access
.
check
(
token
);
Access
.
check
(
token
);
...
@@ -243,93 +282,104 @@ public abstract class MethodHandle
...
@@ -243,93 +282,104 @@ public abstract class MethodHandle
});
});
}
}
/** The string of a direct method handle is the simple name of its target method.
/** Produce a printed representation that displays information about this call site
* The string of an adapter or bound method handle is the string of its
* that may be useful to the human reader.
* target method handle.
* The string of a Java method handle is the string of its entry point method,
* unless the Java method handle overrides the toString method.
*/
*/
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
return
MethodHandleImpl
.
getNameString
(
IMPL_TOKEN
,
this
);
return
MethodHandleImpl
.
getNameString
(
IMPL_TOKEN
,
this
);
}
}
//// This is the "Method Handle Kernel API" discussed at the JVM Language Summit, 9/2009.
//// Implementations here currently delegate to statics in MethodHandles. Some of those statics
//// will be deprecated. Others will be kept as "algorithms" to supply degrees of freedom
//// not present in the Kernel API.
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Invoke the method handle, allowing any caller signature, but requiring an exact signature match.
* Invoke the method handle, allowing any caller signature, but requiring an exact signature match.
* The signature at the call site of {@code invokeExact} must
* The signature at the call site of {@code invokeExact} must
* exactly match this method handle's {@
cod
e type}.
* exactly match this method handle's {@
link #typ
e type}.
* No conversions are allowed on arguments or return values.
* No conversions are allowed on arguments or return values.
* @throws WrongMethodTypeException if the target's type is not identical with the caller's type signature
* @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call
*/
*/
public
final
native
@PolymorphicSignature
<
R
,
A
>
R
invokeExact
(
A
...
args
)
throws
Throwable
;
public
final
native
@PolymorphicSignature
<
R
,
A
>
R
invokeExact
(
A
...
args
)
throws
Throwable
;
// FIXME: remove this transitional form
/** @deprecated transitional form defined in EDR but removed in PFD */
public
final
native
@PolymorphicSignature
<
R
,
A
>
R
invoke
(
A
...
args
)
throws
Throwable
;
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Invoke the method handle, allowing any caller signature,
* Invoke the method handle, allowing any caller signature,
* and performing simple conversions for arguments and return types.
* and optionally performing 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}.
* <p>
* <p>
* If the call site signature exactly matches this method handle's {@
cod
e type},
* If the call site signature exactly matches this method handle's {@
link #typ
e type},
* the call proceeds as if by {@link #invokeExact}.
* the call proceeds as if by {@link #invokeExact
invokeExact
}.
* <p>
* <p>
* Otherwise, the call proceeds as if this method handle were first
* Otherwise, the call proceeds as if this method handle were first
* adjusted by calling {@link #asType} to adjust this method handle
* adjusted by calling {@link #asType
asType
} to adjust this method handle
* to the required type, and then the call proceeds as if by
* to the required type, and then the call proceeds as if by
* {@link #invokeExact} on the adjusted method handle.
* {@link #invokeExact invokeExact} on the adjusted method handle.
* <p>
* There is no guarantee that the {@code asType} call is actually made.
* If the JVM can predict the results of making the call, it may perform
* adaptations directly on the caller's arguments,
* and call the target method handle according to its own exact type.
* <p>
* If the method handle is equipped with a
* {@linkplain #withTypeHandler type handler}, the handler must produce
* an entry point of the call site's exact type.
* Otherwise, the signature at the call site of {@code invokeGeneric} must
* be a valid argument to the standard {@code asType} method.
* In particular, the caller must specify the same argument arity
* as the callee's type.
* @throws WrongMethodTypeException if the target's type cannot be adjusted to the caller's type signature
* @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call
*/
*/
public
final
native
@PolymorphicSignature
<
R
,
A
>
R
invokeGeneric
(
A
...
args
)
throws
Throwable
;
public
final
native
@PolymorphicSignature
<
R
,
A
>
R
invokeGeneric
(
A
...
args
)
throws
Throwable
;
// ?? public final native @PolymorphicSignature <R,A,V> R invokeVarargs(A args, V[] varargs) throws Throwable;
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Perform a varargs invocation, passing the arguments in the given array
* Perform a varargs invocation, passing the arguments in the given array
* to the method handle, as if via {@link #invokeGeneric} from a call site
* to the method handle, as if via {@link #invokeGeneric
invokeGeneric
} from a call site
* which mentions only the type {@code Object}, and whose arity is the length
* which mentions only the type {@code Object}, and whose arity is the length
* of the argument array.
* of the argument array.
* <p>
* <p>
* The length of the arguments array must equal the parameter count
* Specifically, execution proceeds as if by the following steps,
* of the target's type.
* although the methods are not guaranteed to be called if the JVM
* The arguments array is spread into separate arguments.
* can predict their effects.
* <ul>
* <li>Determine the length of the argument array as {@code N}.
* For a null reference, {@code N=0}. </li>
* <li>Determine the generic type {@code TN} of {@code N} arguments as
* as {@code TN=MethodType.genericMethodType(N)}.</li>
* <li>Force the original target method handle {@code MH0} to the
* required type, as {@code MH1 = MH0.asType(TN)}. </li>
* <li>Spread the array into {@code N} separate arguments {@code A0, ...}. </li>
* <li>Invoke the type-adjusted method handle on the unpacked arguments:
* MH1.invokeExact(A0, ...). </li>
* <li>Take the return value as an {@code Object} reference. </li>
* </ul>
* <p>
* <p>
*
In order to match the type of the target
, the following argument
*
Because of the action of the {@code asType} step
, the following argument
* conversions are applied as necessary:
* conversions are applied as necessary:
* <ul>
* <ul>
* <li>reference casting
* <li>reference casting
* <li>unboxing
* <li>unboxing
* <li>widening primitive conversions
* </ul>
* </ul>
* The following conversions are not applied:
* <p>
* <ul>
* <li>primitive conversions (e.g., {@code byte} to {@code int}
* <li>varargs conversions other than the initial spread
* <li>any application-specific conversions (e.g., string to number)
* </ul>
* The result returned by the call is boxed if it is a primitive,
* The result returned by the call is boxed if it is a primitive,
* or forced to null if the return type is void.
* or forced to null if the return type is void.
* <p>
* <p>
* This call is equivalent to the following code:
* This call is equivalent to the following code:
* <p><blockquote><pre>
* <p><blockquote><pre>
*
MethodHandle invoker = MethodHandles.genericInvoker(this.type(), 0, true
);
*
MethodHandle invoker = MethodHandles.varargsInvoker(this.type(), 0
);
*
Object result = invoker.invokeExact(this, arguments);
* Object result = invoker.invokeExact(this, arguments);
* </pre></blockquote>
* </pre></blockquote>
* @param arguments the arguments to pass to the target
* @param arguments the arguments to pass to the target
* @return the result returned by the target
* @return the result returned by the target
* @see MethodHandles#genericInvoker
* @throws WrongMethodTypeException if the target's type cannot be adjusted to take the arguments
* @throws Throwable anything thrown by the target method invocation
* @see MethodHandles#varargsInvoker
*/
*/
public
final
Object
invoke
Vararg
s
(
Object
...
arguments
)
throws
Throwable
{
public
final
Object
invoke
WithArgument
s
(
Object
...
arguments
)
throws
Throwable
{
int
argc
=
arguments
==
null
?
0
:
arguments
.
length
;
int
argc
=
arguments
==
null
?
0
:
arguments
.
length
;
MethodType
type
=
type
();
MethodType
type
=
type
();
if
(
type
.
parameterCount
()
!=
argc
)
throw
badParameterCount
(
type
,
argc
);
if
(
type
.
parameterCount
()
!=
argc
)
{
// simulate invokeGeneric
return
asType
(
MethodType
.
genericMethodType
(
argc
)).
invokeWithArguments
(
arguments
);
}
if
(
argc
<=
10
)
{
if
(
argc
<=
10
)
{
MethodHandle
invoker
=
MethodHandles
.
invokers
(
type
).
genericInvoker
();
MethodHandle
invoker
=
MethodHandles
.
invokers
(
type
).
genericInvoker
();
switch
(
argc
)
{
switch
(
argc
)
{
...
@@ -373,82 +423,48 @@ public abstract class MethodHandle
...
@@ -373,82 +423,48 @@ public abstract class MethodHandle
MethodHandle
invoker
=
MethodHandles
.
invokers
(
type
).
varargsInvoker
(
0
);
MethodHandle
invoker
=
MethodHandles
.
invokers
(
type
).
varargsInvoker
(
0
);
return
invoker
.
invokeExact
(
this
,
arguments
);
return
invoker
.
invokeExact
(
this
,
arguments
);
}
}
/** Equivalent to {@code invoke
Vararg
s(arguments.toArray())}. */
/** Equivalent to {@code invoke
WithArgument
s(arguments.toArray())}. */
public
final
Object
invoke
Vararg
s
(
java
.
util
.
List
<?>
arguments
)
throws
Throwable
{
public
final
Object
invoke
WithArgument
s
(
java
.
util
.
List
<?>
arguments
)
throws
Throwable
{
return
invoke
Vararg
s
(
arguments
.
toArray
());
return
invoke
WithArgument
s
(
arguments
.
toArray
());
}
}
@Deprecated
private
static
WrongMethodTypeException
badParameterCount
(
MethodType
type
,
int
argc
)
{
public
final
Object
invokeVarargs
(
Object
...
arguments
)
throws
Throwable
{
return
new
WrongMethodTypeException
(
type
+
" does not take "
+
argc
+
" parameters"
);
return
invokeWithArguments
(
arguments
);
}
@Deprecated
public
final
Object
invokeVarargs
(
java
.
util
.
List
<?>
arguments
)
throws
Throwable
{
return
invokeWithArguments
(
arguments
.
toArray
());
}
}
/* --- this is intentionally NOT a javadoc yet ---
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce an adapter method handle which adapts the type of the
* Produce an adapter method handle which adapts the type of the
* current method handle to a new type by pairwise argument conversion.
* current method handle to a new type
* The original type and new type must have the same number of arguments.
* The resulting method handle is guaranteed to report a type
* The resulting method handle is guaranteed to confess a type
* which is equal to the desired new type.
* which is equal to the desired new type.
* <p>
* <p>
* If the original type and new type are equal, returns {@code this}.
* If the original type and new type are equal, returns {@code this}.
* <p>
* <p>
* The following conversions are applied as needed both to
* This method provides the crucial behavioral difference between
* arguments and return types. Let T0 and T1 be the differing
* {@link #invokeExact invokeExact} and {@link #invokeGeneric invokeGeneric}. The two methods
* new and old parameter types (or old and new return types)
* perform the same steps when the caller's type descriptor is identical
* for corresponding values passed by the new and old method types.
* with the callee's, but when the types differ, {@link #invokeGeneric invokeGeneric}
* Given those types T0, T1, one of the following conversions is applied
* also calls {@code asType} (or some internal equivalent) in order
* if possible:
* to match up the caller's and callee's types.
* <ul>
* <li>If T0 and T1 are references, and T1 is not an interface type,
* then a cast to T1 is applied.
* (The types do not need to be related in any particular way.)
* <li>If T0 and T1 are references, and T1 is an interface type,
* then the value of type T0 is passed as a T1 without a cast.
* (This treatment of interfaces follows the usage of the bytecode verifier.)
* <li>If T0 and T1 are primitives, then a Java casting
* conversion (JLS 5.5) is applied, if one exists.
* <li>If T0 and T1 are primitives and one is boolean,
* the boolean is treated as a one-bit unsigned integer.
* (This treatment follows the usage of the bytecode verifier.)
* A conversion from another primitive type behaves as if
* it first converts to byte, and then masks all but the low bit.
* <li>If T0 is a primitive and T1 a reference, a boxing
* conversion is applied if one exists, possibly followed by
* an reference conversion to a superclass.
* T1 must be a wrapper class or a supertype of one.
* If T1 is a wrapper class, T0 is converted if necessary
* to T1's primitive type by one of the preceding conversions.
* Otherwise, T0 is boxed, and its wrapper converted to T1.
* <li>If T0 is a reference and T1 a primitive, an unboxing
* conversion is applied if one exists, possibly preceded by
* a reference conversion to a wrapper class.
* T0 must be a wrapper class or a supertype of one.
* If T0 is a wrapper class, its primitive value is converted
* if necessary to T1 by one of the preceding conversions.
* Otherwise, T0 is converted directly to the wrapper type for T1,
* which is then unboxed.
* <li>If the return type T1 is void, any returned value is discarded
* <li>If the return type T0 is void and T1 a reference, a null value is introduced.
* <li>If the return type T0 is void and T1 a primitive, a zero value is introduced.
* </ul>
* <p>
*/
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce an adapter method handle which adapts the type of the
* current method handle to a new type by pairwise argument conversion.
* The original type and new type must have the same number of arguments.
* The resulting method handle is guaranteed to confess a type
* which is equal to the desired new type.
* <p>
* <p>
* If the original type and new type are equal, returns {@code this}.
* This method is equivalent to {@link MethodHandles#convertArguments convertArguments},
* except for method handles produced by {@link #withTypeHandler withTypeHandler},
* in which case the specified type handler is used for calls to {@code asType}.
* <p>
* <p>
* This method is equivalent to {@link MethodHandles#convertArguments}.
* Note that the default behavior of {@code asType} only performs
* pairwise argument conversion and return value conversion.
* Because of this, unless the method handle has a type handler,
* the original type and new type must have the same number of arguments.
*
* @param newType the expected type of the new method handle
* @param newType the expected type of the new method handle
* @return a method handle which delegates to {@code this} after performing
* @return a method handle which delegates to {@code this} after performing
* any necessary argument conversions, and arranges for any
* any necessary argument conversions, and arranges for any
* necessary return value conversions
* necessary return value conversions
* @throws
IllegalArgument
Exception if the conversion cannot be made
* @throws
WrongMethodType
Exception if the conversion cannot be made
* @see MethodHandles#convertArguments
* @see MethodHandles#convertArguments
*/
*/
public
MethodHandle
asType
(
MethodType
newType
)
{
public
MethodHandle
asType
(
MethodType
newType
)
{
...
@@ -456,20 +472,21 @@ public abstract class MethodHandle
...
@@ -456,20 +472,21 @@ public abstract class MethodHandle
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle which adapts, as its <i>target</i>,
* Produce a method handle which adapts, as its <i>target</i>,
* the current method handle. The type of the adapter will be
* the current method handle. The type of the adapter will be
* the same as the type of the target, except that all but the first
* the same as the type of the target, except that the final
* {@code keepPosArgs} parameters of the target's type are replaced
* {@code arrayLength} parameters of the target's type are replaced
* by a single array parameter of type {@code Object[]}.
* by a single array parameter of type {@code arrayType}.
* Thus, if {@code keepPosArgs} is zero, the adapter will take all
* <p>
* arguments in a single object array.
* If the array element type differs from any of the corresponding
* argument types on original target,
* the original target is adapted to take the array elements directly,
* as if by a call to {@link #asType asType}.
* <p>
* <p>
* When called, the adapter replaces a trailing array argument
* When called, the adapter replaces a trailing array argument
* by the array's elements, each as its own argument to the target.
* by the array's elements, each as its own argument to the target.
* (The order of the arguments is preserved.)
* (The order of the arguments is preserved.)
* They are converted pairwise by casting and/or unboxing
* They are converted pairwise by casting and/or unboxing
* (as if by {@link MethodHandles#convertArguments})
* to the types of the trailing parameters of the target.
* to the types of the trailing parameters of the target.
* Finally the target is called.
* Finally the target is called.
* What the target eventually returns is returned unchanged by the adapter.
* What the target eventually returns is returned unchanged by the adapter.
...
@@ -478,54 +495,67 @@ public abstract class MethodHandle
...
@@ -478,54 +495,67 @@ public abstract class MethodHandle
* contains exactly enough elements to provide a correct argument count
* contains exactly enough elements to provide a correct argument count
* to the target method handle.
* to the target method handle.
* (The array may also be null when zero elements are required.)
* (The array may also be null when zero elements are required.)
* @param keepPosArgs the number of leading positional arguments to preserve
* @param arrayType usually {@code Object[]}, the type of the array argument from which to extract the spread arguments
* @return a new method handle which spreads its final argument,
* @param arrayLength the number of arguments to spread from an incoming array argument
* @return a new method handle which spreads its final array argument,
* before calling the original method handle
* before calling the original method handle
* @throws IllegalArgumentException if {@code arrayType} is not an array type
* @throws IllegalArgumentException if target does not have at least
* @throws IllegalArgumentException if target does not have at least
* {@code keepPosArgs} parameter types
* {@code arrayLength} parameter types
* @throws WrongMethodTypeException if the implied {@code asType} call fails
*/
*/
public
final
MethodHandle
asSpreader
(
int
keepPosArgs
)
{
public
final
MethodHandle
asSpreader
(
Class
<?>
arrayType
,
int
arrayLength
)
{
Class
<?>
arrayElement
=
arrayType
.
getComponentType
();
if
(
arrayElement
==
null
)
throw
newIllegalArgumentException
(
"not an array type"
);
MethodType
oldType
=
type
();
MethodType
oldType
=
type
();
int
nargs
=
oldType
.
parameterCount
();
int
nargs
=
oldType
.
parameterCount
();
if
(
nargs
<
arrayLength
)
throw
newIllegalArgumentException
(
"bad spread array length"
);
int
keepPosArgs
=
nargs
-
arrayLength
;
MethodType
newType
=
oldType
.
dropParameterTypes
(
keepPosArgs
,
nargs
);
MethodType
newType
=
oldType
.
dropParameterTypes
(
keepPosArgs
,
nargs
);
newType
=
newType
.
insertParameterTypes
(
keepPosArgs
,
Object
[].
class
);
newType
=
newType
.
insertParameterTypes
(
keepPosArgs
,
arrayElement
);
return
MethodHandles
.
spreadArguments
(
this
,
newType
);
return
MethodHandles
.
spreadArguments
(
this
,
newType
);
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle which adapts, as its <i>target</i>,
* Produce a method handle which adapts, as its <i>target</i>,
* the current method handle. The type of the adapter will be
* the current method handle. The type of the adapter will be
* the same as the type of the target, except that a single trailing
* the same as the type of the target, except that a single trailing
* array parameter of type {@code Object[]} is replaced by
* parameter (usually of type {@code arrayType}) is replaced by
* {@code spreadArrayArgs} parameters of type {@code Object}.
* {@code arrayLength} parameters whose type is element type of {@code arrayType}.
* <p>
* If the array type differs from the final argument type on original target,
* the original target is adapted to take the array type directly,
* as if by a call to {@link #asType asType}.
* <p>
* <p>
* When called, the adapter replaces its trailing {@code
spreadArrayArgs
}
* When called, the adapter replaces its trailing {@code
arrayLength
}
* arguments by a single new
{@code Object} array
, whose elements
* arguments by a single new
array of type {@code arrayType}
, whose elements
* comprise (in order) the replaced arguments.
* comprise (in order) the replaced arguments.
* Finally the target is called.
* Finally the target is called.
* What the target eventually returns is returned unchanged by the adapter.
* What the target eventually returns is returned unchanged by the adapter.
* <p>
* <p>
* (The array may also be a shared constant when {@code spreadArrayArgs} is zero.)
* (The array may also be a shared constant when {@code arrayLength} is zero.)
* @param spreadArrayArgs the number of arguments to spread from the trailing array
* @param arrayType usually {@code Object[]}, the type of the array argument which will collect the arguments
* @param arrayLength the number of arguments to collect into a new array argument
* @return a new method handle which collects some trailing argument
* @return a new method handle which collects some trailing argument
* into an array, before calling the original method handle
* into an array, before calling the original method handle
* @throws IllegalArgumentException if
the last argument of the target
* @throws IllegalArgumentException if
{@code arrayType} is not an array type
* is not {@code Object[]}
or {@code arrayType} is not assignable to this method handle's trailing parameter type
* @throws IllegalArgumentException if {@code
spreadArrayArgs
} is not
* @throws IllegalArgumentException if {@code
arrayLength
} is not
* a legal array size
* a legal array size
* @
deprecated Provisional and unstable; use {@link MethodHandles#collectArguments}.
* @
throws WrongMethodTypeException if the implied {@code asType} call fails
*/
*/
public
final
MethodHandle
asCollector
(
int
spreadArrayArgs
)
{
public
final
MethodHandle
asCollector
(
Class
<?>
arrayType
,
int
arrayLength
)
{
Class
<?>
arrayElement
=
arrayType
.
getComponentType
();
if
(
arrayElement
==
null
)
throw
newIllegalArgumentException
(
"not an array type"
);
MethodType
oldType
=
type
();
MethodType
oldType
=
type
();
int
nargs
=
oldType
.
parameterCount
();
int
nargs
=
oldType
.
parameterCount
();
MethodType
newType
=
oldType
.
dropParameterTypes
(
nargs
-
1
,
nargs
);
MethodType
newType
=
oldType
.
dropParameterTypes
(
nargs
-
1
,
nargs
);
newType
=
newType
.
insertParameterTypes
(
nargs
-
1
,
MethodType
.
genericMethodType
(
spreadArrayArgs
).
parameterArray
());
newType
=
newType
.
insertParameterTypes
(
nargs
-
1
,
java
.
util
.
Collections
.<
Class
<?>>
nCopies
(
arrayLength
,
arrayElement
));
return
MethodHandles
.
collectArguments
(
this
,
newType
);
return
MethodHandles
.
collectArguments
(
this
,
newType
);
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle which binds the given argument
* Produce a method handle which binds the given argument
* to the current method handle as <i>target</i>.
* to the current method handle as <i>target</i>.
* The type of the bound handle will be
* The type of the bound handle will be
...
@@ -546,15 +576,73 @@ public abstract class MethodHandle
...
@@ -546,15 +576,73 @@ public abstract class MethodHandle
* leading parameter type that is a reference type
* leading parameter type that is a reference type
* @throws ClassCastException if {@code x} cannot be converted
* @throws ClassCastException if {@code x} cannot be converted
* to the leading parameter type of the target
* to the leading parameter type of the target
* @
deprecated Provisional and unstable; use {@link MethodHandles#insertArguments}.
* @
see MethodHandles#insertArguments
*/
*/
public
final
MethodHandle
bindTo
(
Object
x
)
{
public
final
MethodHandle
bindTo
(
Object
x
)
{
return
MethodHandles
.
insertArguments
(
this
,
0
,
x
);
return
MethodHandles
.
insertArguments
(
this
,
0
,
x
);
}
}
/** Implementation of {@link MethodHandleProvider}, which returns {@code this}. */
/**
public
final
MethodHandle
asMethodHandle
()
{
return
this
;
}
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Create a new method handle with the same type as this one,
* but whose {@code asType} method invokes the given
* {@code typeHandler} on this method handle,
* instead of the standard {@code MethodHandles.convertArguments}.
* <p>
* The new method handle will have the same behavior as the
* old one when invoked by {@code invokeExact}.
* For {@code invokeGeneric} calls which exactly match
* the method type, the two method handles will also
* have the same behavior.
* For other {@code invokeGeneric} calls, the {@code typeHandler}
* will control the behavior of the new method handle.
* <p>
* Thus, a method handle with an {@code asType} handler can
* be configured to accept more than one arity of {@code invokeGeneric}
* call, and potentially every possible arity.
* It can also be configured to supply default values for
* optional arguments, when the caller does not specify them.
* <p>
* The given method handle must take two arguments and return
* one result. The result it returns must be a method handle
* of exactly the requested type. If the result returned by
* the target is null, a {@link NullPointerException} is thrown,
* else if the type of the target does not exactly match
* the requested type, a {@link WrongMethodTypeException} is thrown.
* <p>
* Therefore, the type handler is invoked as if by this code:
* <blockquote><pre>
* MethodHandle target = this; // original method handle
* MethodHandle adapter = ...; // adapted method handle
* MethodType requestedType = ...; // argument to asType()
* if (type().equals(requestedType))
* return adapter;
* MethodHandle result = (MethodHandle)
* typeHandler.invokeGeneric(target, requestedType);
* if (!result.type().equals(requestedType))
* throw new WrongMethodTypeException();
* return result;
* </pre></blockquote>
* <p>
* For example, here is a list-making variable-arity method handle:
* <blockquote><pre>
MethodHandle makeEmptyList = MethodHandles.constant(List.class, Arrays.asList());
MethodHandle asList = lookup()
.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class));
static MethodHandle collectingTypeHandler(MethodHandle base, MethodType newType) {
return asList.asCollector(Object[].class, newType.parameterCount()).asType(newType);
}
MethodHandle collectingTypeHandler = lookup()
.findStatic(lookup().lookupClass(), "collectingTypeHandler",
methodType(MethodHandle.class, MethodHandle.class, MethodType.class));
MethodHandle makeAnyList = makeEmptyList.withTypeHandler(collectingTypeHandler);
/** Implementation of {@link MethodHandleProvider}, which returns {@code this.asType(type)}. */
System.out.println(makeAnyList.invokeGeneric()); // prints []
public
final
MethodHandle
asMethodHandle
(
MethodType
type
)
{
return
this
.
asType
(
type
);
}
System.out.println(makeAnyList.invokeGeneric(1)); // prints [1]
System.out.println(makeAnyList.invokeGeneric("two", "too")); // prints [two, too]
* <pre><blockquote>
*/
public
MethodHandle
withTypeHandler
(
MethodHandle
typeHandler
)
{
return
MethodHandles
.
withTypeHandler
(
this
,
typeHandler
);
}
}
}
src/share/classes/java/dyn/MethodHandleProvider.java
已删除
100644 → 0
浏览文件 @
70e0218c
/*
* 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
浏览文件 @
5150d263
...
@@ -29,6 +29,7 @@ import java.lang.reflect.*;
...
@@ -29,6 +29,7 @@ import java.lang.reflect.*;
import
sun.dyn.Access
;
import
sun.dyn.Access
;
import
sun.dyn.MemberName
;
import
sun.dyn.MemberName
;
import
sun.dyn.MethodHandleImpl
;
import
sun.dyn.MethodHandleImpl
;
import
sun.dyn.util.ValueConversions
;
import
sun.dyn.util.VerifyAccess
;
import
sun.dyn.util.VerifyAccess
;
import
sun.dyn.util.Wrapper
;
import
sun.dyn.util.Wrapper
;
import
java.util.List
;
import
java.util.List
;
...
@@ -135,12 +136,19 @@ public class MethodHandles {
...
@@ -135,12 +136,19 @@ public class MethodHandles {
* In general, the conditions under which a method handle may be
* In general, the conditions under which a method handle may be
* created for a method {@code M} are exactly as restrictive as the conditions
* 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}.
* under which the lookup class could have compiled a call to {@code M}.
* This rule is applied even if the Java compiler might have created
* <p>
* In some cases, this access is obtained by the Java compiler by creating
* an wrapper method to access a private method of another class
* an wrapper method to access a private method of another class
* in the same top-level declaration.
* in the same top-level declaration.
* For example, a
lookup object created for a
nested class {@code C.D}
* For example, a nested class {@code C.D}
* can access private members within other related classes such as
* can access private members within other related classes such as
* {@code C}, {@code C.D.E}, or {@code C.B}.
* {@code C}, {@code C.D.E}, or {@code C.B},
* but the Java compiler may need to generate wrapper methods in
* those related classes. In such cases, a {@code Lookup} object on
* {@code C.E} would be unable to those private members.
* A workaround for this limitation is the {@link Lookup#in Lookup.in} method,
* which can transform a lookup on {@code C.E} into one on any of those other
* classes, without special elevation of privilege.
*/
*/
public
static
final
public
static
final
class
Lookup
{
class
Lookup
{
...
@@ -181,13 +189,23 @@ public class MethodHandles {
...
@@ -181,13 +189,23 @@ public class MethodHandles {
}
}
/** Which types of members can this lookup object produce?
/** Which types of members can this lookup object produce?
* The result is a bit-mask of the {@link Modifier} bits
* The result is a bit-mask of the {@link
java.lang.reflect.Modifier
Modifier} bits
* {@linkplain Modifier#PUBLIC PUBLIC (0x01)},
* {@linkplain
java.lang.reflect.
Modifier#PUBLIC PUBLIC (0x01)},
* {@linkplain Modifier#PROTECTED PROTECTED (0x02)},
* {@linkplain
java.lang.reflect.
Modifier#PROTECTED PROTECTED (0x02)},
* {@linkplain Modifier#PRIVATE PRIVATE (0x04)},
* {@linkplain
java.lang.reflect.
Modifier#PRIVATE PRIVATE (0x04)},
* and {@linkplain Modifier#STATIC STATIC (0x08)}.
* and {@linkplain
java.lang.reflect.
Modifier#STATIC STATIC (0x08)}.
* The modifier bit {@code STATIC} stands in for the package protection mode,
* The modifier bit {@code STATIC} stands in for the package protection mode,
* which does not have an explicit modifier bit.
* which does not have an explicit modifier bit.
* <p>
* A freshly-created lookup object
* on the {@linkplain java.dyn.MethodHandles#lookup() caller's class}
* has all possible bits set, since the caller class can access all its own members.
* A lookup object on a new lookup class
* {@linkplain java.dyn.MethodHandles.Lookup#in created from a previous lookup object}
* may have some mode bits set to zero.
* The purpose of this is to restrict access via the new lookup object,
* so that it can access only names which can be reached by the original
* lookup object, and also by the new lookup class.
*/
*/
public
int
lookupModes
()
{
public
int
lookupModes
()
{
return
allowedModes
&
ALL_MODES
;
return
allowedModes
&
ALL_MODES
;
...
@@ -224,14 +242,17 @@ public class MethodHandles {
...
@@ -224,14 +242,17 @@ public class MethodHandles {
* <p>
* <p>
* However, the resulting {@code Lookup} object is guaranteed
* However, the resulting {@code Lookup} object is guaranteed
* to have no more access capabilities than the original.
* to have no more access capabilities than the original.
* In particular:<ul>
* In particular
, access capabilities can be lost as follows
:<ul>
* <li>If the new lookup class differs from the old one,
* <li>If the new lookup class differs from the old one,
* protected members will not be accessible by virtue of inheritance.
* protected members will not be accessible by virtue of inheritance.
* (Protected members may continue to be accessible because of package sharing.)
* <li>If the new lookup class is in a different package
* <li>If the new lookup class is in a different package
* than the old one, protected and default (package) members will not be accessible.
* than the old one, protected and default (package) members will not be accessible.
* <li>If the new lookup class is not within the same package member
* <li>If the new lookup class is not within the same package member
* as the old one, private members will not be accessible.
* as the old one, private members will not be accessible.
* <li>In all cases, public members will continue to be accessible.
* <li>If the new lookup class is not accessible to the old lookup class,
* then no members, not even public members, will be accessible.
* (In all other cases, public members will continue to be accessible.)
* </ul>
* </ul>
*/
*/
public
Lookup
in
(
Class
<?>
requestedLookupClass
)
{
public
Lookup
in
(
Class
<?>
requestedLookupClass
)
{
...
@@ -245,10 +266,17 @@ public class MethodHandles {
...
@@ -245,10 +266,17 @@ public class MethodHandles {
&&
!
VerifyAccess
.
isSamePackage
(
this
.
lookupClass
,
requestedLookupClass
))
{
&&
!
VerifyAccess
.
isSamePackage
(
this
.
lookupClass
,
requestedLookupClass
))
{
newModes
&=
~(
PACKAGE
|
PRIVATE
);
newModes
&=
~(
PACKAGE
|
PRIVATE
);
}
}
// Allow nestmate lookups to be created without special privilege:
if
((
newModes
&
PRIVATE
)
!=
0
if
((
newModes
&
PRIVATE
)
!=
0
&&
!
VerifyAccess
.
isSamePackageMember
(
this
.
lookupClass
,
requestedLookupClass
))
{
&&
!
VerifyAccess
.
isSamePackageMember
(
this
.
lookupClass
,
requestedLookupClass
))
{
newModes
&=
~
PRIVATE
;
newModes
&=
~
PRIVATE
;
}
}
if
(
newModes
==
PUBLIC
&&
!
VerifyAccess
.
isClassAccessible
(
requestedLookupClass
,
this
.
lookupClass
))
{
// The requested class it not accessible from the lookup class.
// No permissions.
newModes
=
0
;
}
checkUnprivilegedlookupClass
(
requestedLookupClass
);
checkUnprivilegedlookupClass
(
requestedLookupClass
);
return
new
Lookup
(
requestedLookupClass
,
newModes
);
return
new
Lookup
(
requestedLookupClass
,
newModes
);
}
}
...
@@ -290,8 +318,8 @@ public class MethodHandles {
...
@@ -290,8 +318,8 @@ public class MethodHandles {
break
;
break
;
case
PUBLIC
|
PACKAGE:
case
PUBLIC
|
PACKAGE:
return
cname
+
"/package"
;
return
cname
+
"/package"
;
case
0
:
//
should not happen
case
0
:
//
no privileges
return
cname
+
"/
empty
"
;
return
cname
+
"/
noaccess
"
;
case
ALL_MODES:
case
ALL_MODES:
return
cname
;
return
cname
;
}
}
...
@@ -326,7 +354,6 @@ public class MethodHandles {
...
@@ -326,7 +354,6 @@ public class MethodHandles {
* @param name the name of the method
* @param name the name of the method
* @param type the type of the method
* @param type the type of the method
* @return the desired method handle
* @return the desired method handle
* @exception SecurityException <em>TBD</em>
* @exception NoAccessException if the method does not exist or access checking fails
* @exception NoAccessException if the method does not exist or access checking fails
*/
*/
public
public
...
@@ -358,7 +385,6 @@ public class MethodHandles {
...
@@ -358,7 +385,6 @@ public class MethodHandles {
* @param name the name of the method
* @param name the name of the method
* @param type the type of the method, with the receiver argument omitted
* @param type the type of the method, with the receiver argument omitted
* @return the desired method handle
* @return the desired method handle
* @exception SecurityException <em>TBD</em>
* @exception NoAccessException if the method does not exist or access checking fails
* @exception NoAccessException if the method does not exist or access checking fails
*/
*/
public
MethodHandle
findVirtual
(
Class
<?>
refc
,
String
name
,
MethodType
type
)
throws
NoAccessException
{
public
MethodHandle
findVirtual
(
Class
<?>
refc
,
String
name
,
MethodType
type
)
throws
NoAccessException
{
...
@@ -382,7 +408,6 @@ public class MethodHandles {
...
@@ -382,7 +408,6 @@ public class MethodHandles {
* @param refc the class or interface from which the method is accessed
* @param refc the class or interface from which the method is accessed
* @param type the type of the method, with the receiver argument omitted, and a void return type
* @param type the type of the method, with the receiver argument omitted, and a void return type
* @return the desired method handle
* @return the desired method handle
* @exception SecurityException <em>TBD</em>
* @exception NoAccessException if the method does not exist or access checking fails
* @exception NoAccessException if the method does not exist or access checking fails
*/
*/
public
MethodHandle
findConstructor
(
Class
<?>
refc
,
MethodType
type
)
throws
NoAccessException
{
public
MethodHandle
findConstructor
(
Class
<?>
refc
,
MethodType
type
)
throws
NoAccessException
{
...
@@ -409,13 +434,13 @@ public class MethodHandles {
...
@@ -409,13 +434,13 @@ public class MethodHandles {
* {@code invokespecial} instruction.)
* {@code invokespecial} instruction.)
* <p>
* <p>
* If the explicitly specified caller class is not identical with the
* If the explicitly specified caller class is not identical with the
* lookup class, a security check TBD is performed.
* lookup class, or if this lookup object does not have private access
* privileges, the access fails.
* @param refc the class or interface from which the method is accessed
* @param refc the class or interface from which the method is accessed
* @param name the name of the method (which must not be "<init>")
* @param name the name of the method (which must not be "<init>")
* @param type the type of the method, with the receiver argument omitted
* @param type the type of the method, with the receiver argument omitted
* @param specialCaller the proposed calling class to perform the {@code invokespecial}
* @param specialCaller the proposed calling class to perform the {@code invokespecial}
* @return the desired method handle
* @return the desired method handle
* @exception SecurityException <em>TBD</em>
* @exception NoAccessException if the method does not exist or access checking fails
* @exception NoAccessException if the method does not exist or access checking fails
*/
*/
public
MethodHandle
findSpecial
(
Class
<?>
refc
,
String
name
,
MethodType
type
,
public
MethodHandle
findSpecial
(
Class
<?>
refc
,
String
name
,
MethodType
type
,
...
@@ -428,7 +453,6 @@ public class MethodHandles {
...
@@ -428,7 +453,6 @@ public class MethodHandles {
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle giving read access to a non-static field.
* Produce a method handle giving read access to a non-static field.
* The type of the method handle will have a return type of the field's
* The type of the method handle will have a return type of the field's
* value type.
* value type.
...
@@ -445,7 +469,6 @@ public class MethodHandles {
...
@@ -445,7 +469,6 @@ public class MethodHandles {
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle giving write access to a non-static field.
* Produce a method handle giving write access to a non-static field.
* The type of the method handle will have a void return type.
* The type of the method handle will have a void return type.
* The method handle will take two arguments, the instance containing
* The method handle will take two arguments, the instance containing
...
@@ -462,7 +485,6 @@ public class MethodHandles {
...
@@ -462,7 +485,6 @@ public class MethodHandles {
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle giving read access to a static field.
* Produce a method handle giving read access to a static field.
* The type of the method handle will have a return type of the field's
* The type of the method handle will have a return type of the field's
* value type.
* value type.
...
@@ -478,7 +500,6 @@ public class MethodHandles {
...
@@ -478,7 +500,6 @@ public class MethodHandles {
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle giving write access to a static field.
* Produce a method handle giving write access to a static field.
* The type of the method handle will have a void return type.
* The type of the method handle will have a void return type.
* The method handle will take a single
* The method handle will take a single
...
@@ -515,7 +536,6 @@ public class MethodHandles {
...
@@ -515,7 +536,6 @@ public class MethodHandles {
* @param name the name of the method
* @param name the name of the method
* @param type the type of the method, with the receiver argument omitted
* @param type the type of the method, with the receiver argument omitted
* @return the desired method handle
* @return the desired method handle
* @exception SecurityException <em>TBD</em>
* @exception NoAccessException if the method does not exist or access checking fails
* @exception NoAccessException if the method does not exist or access checking fails
*/
*/
public
MethodHandle
bind
(
Object
receiver
,
String
name
,
MethodType
type
)
throws
NoAccessException
{
public
MethodHandle
bind
(
Object
receiver
,
String
name
,
MethodType
type
)
throws
NoAccessException
{
...
@@ -530,7 +550,6 @@ public class MethodHandles {
...
@@ -530,7 +550,6 @@ public class MethodHandles {
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Make a direct method handle to <i>m</i>, if the lookup class has permission.
* Make a direct method handle to <i>m</i>, if the lookup class has permission.
* If <i>m</i> is non-static, the receiver argument is treated as an initial argument.
* If <i>m</i> is non-static, the receiver argument is treated as an initial argument.
* If <i>m</i> is virtual, overriding is respected on every call.
* If <i>m</i> is virtual, overriding is respected on every call.
...
@@ -554,7 +573,6 @@ public class MethodHandles {
...
@@ -554,7 +573,6 @@ public class MethodHandles {
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle for a reflected method.
* Produce a method handle for a reflected method.
* It will bypass checks for overriding methods on the receiver,
* It will bypass checks for overriding methods on the receiver,
* as if by a {@code invokespecial} instruction from within the {@code specialCaller}.
* as if by a {@code invokespecial} instruction from within the {@code specialCaller}.
...
@@ -579,7 +597,6 @@ public class MethodHandles {
...
@@ -579,7 +597,6 @@ public class MethodHandles {
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle for a reflected constructor.
* Produce a method handle for a reflected constructor.
* The type of the method handle will be that of the constructor,
* The type of the method handle will be that of the constructor,
* with the return type changed to the declaring class.
* with the return type changed to the declaring class.
...
@@ -602,7 +619,6 @@ public class MethodHandles {
...
@@ -602,7 +619,6 @@ public class MethodHandles {
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle giving read access to a reflected field.
* Produce a method handle giving read access to a reflected field.
* The type of the method handle will have a return type of the field's
* The type of the method handle will have a return type of the field's
* value type.
* value type.
...
@@ -620,7 +636,6 @@ public class MethodHandles {
...
@@ -620,7 +636,6 @@ public class MethodHandles {
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle giving write access to a reflected field.
* Produce a method handle giving write access to a reflected field.
* The type of the method handle will have a void return type.
* The type of the method handle will have a void return type.
* If the field is static, the method handle will take a single
* If the field is static, the method handle will take a single
...
@@ -681,7 +696,7 @@ public class MethodHandles {
...
@@ -681,7 +696,7 @@ public class MethodHandles {
int
allowedModes
=
this
.
allowedModes
;
int
allowedModes
=
this
.
allowedModes
;
if
(
allowedModes
==
TRUSTED
)
return
;
if
(
allowedModes
==
TRUSTED
)
return
;
int
mods
=
m
.
getModifiers
();
int
mods
=
m
.
getModifiers
();
if
(
Modifier
.
isPublic
(
mods
)
&&
Modifier
.
isPublic
(
refc
.
getModifiers
()))
if
(
Modifier
.
isPublic
(
mods
)
&&
Modifier
.
isPublic
(
refc
.
getModifiers
())
&&
allowedModes
!=
0
)
return
;
// common case
return
;
// common case
int
requestedModes
=
fixmods
(
mods
);
// adjust 0 => PACKAGE
int
requestedModes
=
fixmods
(
mods
);
// adjust 0 => PACKAGE
if
((
requestedModes
&
allowedModes
)
!=
0
if
((
requestedModes
&
allowedModes
)
!=
0
...
@@ -706,6 +721,8 @@ public class MethodHandles {
...
@@ -706,6 +721,8 @@ public class MethodHandles {
return
"access to public member failed"
;
// (how?)
return
"access to public member failed"
;
// (how?)
else
if
(
allowedModes
==
PUBLIC
)
else
if
(
allowedModes
==
PUBLIC
)
return
"member is not public"
;
return
"member is not public"
;
else
if
(
allowedModes
==
0
)
return
"attempted member access through a non-public class"
;
if
(
Modifier
.
isPrivate
(
mods
))
if
(
Modifier
.
isPrivate
(
mods
))
return
"member is private"
;
return
"member is private"
;
if
(
Modifier
.
isProtected
(
mods
))
if
(
Modifier
.
isProtected
(
mods
))
...
@@ -713,9 +730,14 @@ public class MethodHandles {
...
@@ -713,9 +730,14 @@ public class MethodHandles {
return
"member is private to package"
;
return
"member is private to package"
;
}
}
private
static
final
boolean
ALLOW_NESTMATE_ACCESS
=
false
;
void
checkSpecialCaller
(
Class
<?>
specialCaller
)
throws
NoAccessException
{
void
checkSpecialCaller
(
Class
<?>
specialCaller
)
throws
NoAccessException
{
if
(
allowedModes
==
TRUSTED
)
return
;
if
(
allowedModes
==
TRUSTED
)
return
;
if
(!
VerifyAccess
.
isSamePackageMember
(
specialCaller
,
lookupClass
()))
if
((
allowedModes
&
PRIVATE
)
==
0
||
(
specialCaller
!=
lookupClass
()
&&
!(
ALLOW_NESTMATE_ACCESS
&&
VerifyAccess
.
isSamePackageMember
(
specialCaller
,
lookupClass
()))))
throw
newNoAccessException
(
"no private access for invokespecial"
,
throw
newNoAccessException
(
"no private access for invokespecial"
,
new
MemberName
(
specialCaller
),
lookupClass
());
new
MemberName
(
specialCaller
),
lookupClass
());
}
}
...
@@ -725,7 +747,9 @@ public class MethodHandles {
...
@@ -725,7 +747,9 @@ public class MethodHandles {
// on itself or a subclass. Enforce that restriction, from JVMS 5.4.4, etc.
// on itself or a subclass. Enforce that restriction, from JVMS 5.4.4, etc.
if
(!
method
.
isProtected
()
||
method
.
isStatic
()
if
(!
method
.
isProtected
()
||
method
.
isStatic
()
||
allowedModes
==
TRUSTED
||
allowedModes
==
TRUSTED
||
VerifyAccess
.
isSamePackageMember
(
method
.
getDeclaringClass
(),
lookupClass
()))
||
method
.
getDeclaringClass
()
==
lookupClass
()
||
(
ALLOW_NESTMATE_ACCESS
&&
VerifyAccess
.
isSamePackageMember
(
method
.
getDeclaringClass
(),
lookupClass
())))
return
mh
;
return
mh
;
else
else
return
restrictReceiver
(
method
,
mh
,
lookupClass
());
return
restrictReceiver
(
method
,
mh
,
lookupClass
());
...
@@ -765,7 +789,6 @@ public class MethodHandles {
...
@@ -765,7 +789,6 @@ public class MethodHandles {
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle giving read access to elements of an array.
* Produce a method handle giving read access to elements of an array.
* The type of the method handle will have a return type of the array's
* The type of the method handle will have a return type of the array's
* element type. Its first argument will be the array type,
* element type. Its first argument will be the array type,
...
@@ -780,7 +803,6 @@ public class MethodHandles {
...
@@ -780,7 +803,6 @@ public class MethodHandles {
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle giving write access to elements of an array.
* Produce a method handle giving write access to elements of an array.
* The type of the method handle will have a void return type.
* The type of the method handle will have a void return type.
* Its last argument will be the array's element type.
* Its last argument will be the array's element type.
...
@@ -796,25 +818,6 @@ public class MethodHandles {
...
@@ -796,25 +818,6 @@ public class MethodHandles {
/// method handle invocation (reflective style)
/// method handle invocation (reflective style)
/**
/**
* @deprecated Alias for MethodHandle.invokeVarargs.
*/
@Deprecated
public
static
Object
invokeVarargs
(
MethodHandle
target
,
Object
...
arguments
)
throws
Throwable
{
return
target
.
invokeVarargs
(
arguments
);
}
/**
* @deprecated Alias for MethodHandle.invokeVarargs.
*/
@Deprecated
public
static
Object
invoke
(
MethodHandle
target
,
Object
...
arguments
)
throws
Throwable
{
return
target
.
invokeVarargs
(
arguments
);
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle which will invoke any method handle of the
* Produce a method handle which will invoke any method handle of the
* given type on a standard set of {@code Object} type arguments.
* given type on a standard set of {@code Object} type arguments.
* The resulting invoker will be a method handle with the following
* The resulting invoker will be a method handle with the following
...
@@ -823,18 +826,28 @@ public class MethodHandles {
...
@@ -823,18 +826,28 @@ public class MethodHandles {
* <li>a single {@code MethodHandle} target
* <li>a single {@code MethodHandle} target
* <li>zero or more {@code Object} values (one for each argument in {@code type})
* <li>zero or more {@code Object} values (one for each argument in {@code type})
* </ul>
* </ul>
* The invoker will apply reference casts as necessary and unbox primitive arguments,
* <p>
* as if by {@link #convertArguments}.
* The invoker will behave like a call to {@link MethodHandle.invokeGeneric} with
* the indicated {@code type}.
* That is, if the target is exactly of the given {@code type}, it will behave
* like {@code invokeExact}; otherwise it behave as if {@link MethodHandle.asType}
* is used to convert the target to the required {@code type}.
* <p>
* The type of the returned invoker will not be the given {@code type}, but rather
* will have all parameter and return types replaced by {@code Object}.
* <p>
* Before invoking its target, the invoker will apply reference casts as
* necessary and unbox and widen primitive arguments, as if by {@link #convertArguments}.
* The return value of the invoker will be an {@code Object} reference,
* The return value of the invoker will be an {@code Object} reference,
* boxing a primitive value if the original type returns a primitive,
* boxing a primitive value if the original type returns a primitive,
* and always null if the original type returns void.
* and always null if the original type returns void.
* <p>
* <p>
* This method is equivalent to the following code (though it may be more efficient):
* This method is equivalent to the following code (though it may be more efficient):
* <p><blockquote><pre>
* <p><blockquote><pre>
* MethodHandle invoker =
exactInvoker(
type);
* MethodHandle invoker =
lookup().findVirtual(MethodHandle.class, "invokeGeneric",
type);
* MethodType genericType = type.generic();
* MethodType genericType = type.generic();
* genericType = genericType.insertParameterType(0, MethodHandle.class);
* genericType = genericType.insertParameterType(0, MethodHandle.class);
* return
convertArguments(invoker,
genericType);
* return
invoker.asType(
genericType);
* </pre></blockquote>
* </pre></blockquote>
* @param type the type of target methods which the invoker will apply to
* @param type the type of target methods which the invoker will apply to
* @return a method handle suitable for invoking any method handle of the given type
* @return a method handle suitable for invoking any method handle of the given type
...
@@ -845,9 +858,8 @@ public class MethodHandles {
...
@@ -845,9 +858,8 @@ public class MethodHandles {
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle which will invoke any method handle of the
* Produce a method handle which will invoke any method handle of the
* given
type
on a standard set of {@code Object} type arguments
* given
{@code type}
on a standard set of {@code Object} type arguments
* and a single trailing {@code Object[]} array.
* and a single trailing {@code Object[]} array.
* The resulting invoker will be a method handle with the following
* The resulting invoker will be a method handle with the following
* arguments:
* arguments:
...
@@ -856,18 +868,31 @@ public class MethodHandles {
...
@@ -856,18 +868,31 @@ public class MethodHandles {
* <li>zero or more {@code Object} values (counted by {@code objectArgCount})
* <li>zero or more {@code Object} values (counted by {@code objectArgCount})
* <li>an {@code Object[]} array containing more arguments
* <li>an {@code Object[]} array containing more arguments
* </ul>
* </ul>
* The invoker will spread the varargs array, apply
* <p>
* reference casts as necessary, and unbox primitive arguments.
* The invoker will behave like a call to {@link MethodHandle.invokeGeneric} with
* the indicated {@code type}.
* That is, if the target is exactly of the given {@code type}, it will behave
* like {@code invokeExact}; otherwise it behave as if {@link MethodHandle.asType}
* is used to convert the target to the required {@code type}.
* <p>
* The type of the returned invoker will not be the given {@code type}, but rather
* will have all parameter and return types replaced by {@code Object}, except for
* the last parameter type, which will be the array type {@code Object[]}.
* <p>
* Before invoking its target, the invoker will spread the varargs array, apply
* reference casts as necessary, and unbox and widen primitive arguments.
* The return value of the invoker will be an {@code Object} reference,
* The return value of the invoker will be an {@code Object} reference,
* boxing a primitive value if the original type returns a primitive,
* boxing a primitive value if the original type returns a primitive,
* and always null if the original type returns void.
* and always null if the original type returns void.
* <p>
* <p>
* This method is equivalent to the following code (though it may be more efficient):
* This method is equivalent to the following code (though it may be more efficient):
* <p><blockquote><pre>
* <p><blockquote><pre>
* MethodHandle invoker =
exactInvoker(
type);
* MethodHandle invoker =
lookup().findVirtual(MethodHandle.class, "invokeGeneric",
type);
* MethodType vaType = MethodType.
makeGeneric
(objectArgCount, true);
* MethodType vaType = MethodType.
genericMethodType
(objectArgCount, true);
* vaType = vaType.insertParameterType(0, MethodHandle.class);
* vaType = vaType.insertParameterType(0, MethodHandle.class);
* return spreadArguments(invoker, vaType);
* int spreadArgCount = type.parameterCount - objectArgCount;
* invoker = invoker.asSpreader(Object.class, spreadArgCount);
* return invoker.asType(vaType);
* </pre></blockquote>
* </pre></blockquote>
* @param type the desired target type
* @param type the desired target type
* @param objectArgCount number of fixed (non-varargs) {@code Object} arguments
* @param objectArgCount number of fixed (non-varargs) {@code Object} arguments
...
@@ -881,7 +906,6 @@ public class MethodHandles {
...
@@ -881,7 +906,6 @@ public class MethodHandles {
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle which will take a invoke any method handle of the
* Produce a method handle which will take a invoke any method handle of the
* given type. The resulting invoker will have a type which is
* given type. The resulting invoker will have a type which is
* exactly equal to the desired type, except that it will accept
* exactly equal to the desired type, except that it will accept
...
@@ -889,7 +913,7 @@ public class MethodHandles {
...
@@ -889,7 +913,7 @@ public class MethodHandles {
* <p>
* <p>
* This method is equivalent to the following code (though it may be more efficient):
* This method is equivalent to the following code (though it may be more efficient):
* <p><blockquote><pre>
* <p><blockquote><pre>
* lookup().findVirtual(MethodHandle.class, "invoke", type);
* lookup().findVirtual(MethodHandle.class, "invoke
Exact
", type);
* </pre></blockquote>
* </pre></blockquote>
* @param type the desired target type
* @param type the desired target type
* @return a method handle suitable for invoking any method handle of the given type
* @return a method handle suitable for invoking any method handle of the given type
...
@@ -900,37 +924,16 @@ public class MethodHandles {
...
@@ -900,37 +924,16 @@ public class MethodHandles {
}
}
/**
/**
* <em>
PROVISIONAL API, WORK IN PROGRESS
:</em>
* <em>
METHOD WILL BE REMOVED FOR PFD
:</em>
* Produce a method handle equivalent to an invokedynamic instruction
* Produce a method handle equivalent to an invokedynamic instruction
* which has been linked to the given call site.
* which has been linked to the given call site.
* Along with {@link Lookup#findVirtual}, {@link Lookup#findStatic},
* and {@link Lookup#findSpecial}, this completes the emulation
* of the JVM's {@code invoke} instructions.
* <p>This method is equivalent to the following code:
* <p><blockquote><pre>
* MethodHandle getTarget, invoker, result;
* getTarget = lookup().bind(site, "getTarget", methodType(MethodHandle.class));
* invoker = exactInvoker(site.type());
* result = foldArguments(invoker, getTarget)
* </pre></blockquote>
* @return a method handle which always invokes the call site's target
* @return a method handle which always invokes the call site's target
* @deprecated Use {@link CallSite#dynamicInvoker} instead.
*/
*/
public
static
public
static
MethodHandle
dynamicInvoker
(
CallSite
site
)
throws
NoAccessException
{
MethodHandle
dynamicInvoker
(
CallSite
site
)
throws
NoAccessException
{
MethodHandle
getCSTarget
=
GET_TARGET
;
return
site
.
dynamicInvoker
();
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
);
}
}
private
static
MethodHandle
GET_TARGET
=
null
;
// link this lazily, not eagerly
static
Invokers
invokers
(
MethodType
type
)
{
static
Invokers
invokers
(
MethodType
type
)
{
return
MethodTypeImpl
.
invokers
(
IMPL_TOKEN
,
type
);
return
MethodTypeImpl
.
invokers
(
IMPL_TOKEN
,
type
);
...
@@ -974,23 +977,23 @@ public class MethodHandles {
...
@@ -974,23 +977,23 @@ public class MethodHandles {
if
(
t0
.
isPrimitive
())
if
(
t0
.
isPrimitive
())
return
Wrapper
.
asPrimitiveType
(
t1
).
cast
(
value
);
return
Wrapper
.
asPrimitiveType
(
t1
).
cast
(
value
);
else
else
return
Wrapper
.
OBJECT
.
c
as
t
(
value
,
t1
);
return
Wrapper
.
OBJECT
.
c
onver
t
(
value
,
t1
);
}
}
boolean
prim0
=
t0
.
isPrimitive
(),
prim1
=
t1
.
isPrimitive
();
boolean
prim0
=
t0
.
isPrimitive
(),
prim1
=
t1
.
isPrimitive
();
if
(!
prim0
)
{
if
(!
prim0
)
{
// check contract with caller
// check contract with caller
Wrapper
.
OBJECT
.
c
as
t
(
value
,
t0
);
Wrapper
.
OBJECT
.
c
onver
t
(
value
,
t0
);
if
(!
prim1
)
{
if
(!
prim1
)
{
return
Wrapper
.
OBJECT
.
c
as
t
(
value
,
t1
);
return
Wrapper
.
OBJECT
.
c
onver
t
(
value
,
t1
);
}
}
// convert reference to primitive by unboxing
// convert reference to primitive by unboxing
Wrapper
w1
=
Wrapper
.
forPrimitiveType
(
t1
);
Wrapper
w1
=
Wrapper
.
forPrimitiveType
(
t1
);
return
w1
.
c
as
t
(
value
,
t1
);
return
w1
.
c
onver
t
(
value
,
t1
);
}
}
// check contract with caller:
// check contract with caller:
Wrapper
.
asWrapperType
(
t0
).
cast
(
value
);
Wrapper
.
asWrapperType
(
t0
).
cast
(
value
);
Wrapper
w1
=
Wrapper
.
forPrimitiveType
(
t1
);
Wrapper
w1
=
Wrapper
.
forPrimitiveType
(
t1
);
return
w1
.
c
as
t
(
value
,
t1
);
return
w1
.
c
onver
t
(
value
,
t1
);
}
}
static
static
...
@@ -1011,7 +1014,7 @@ public class MethodHandles {
...
@@ -1011,7 +1014,7 @@ public class MethodHandles {
* Produce a method handle which adapts the type of the
* Produce a method handle which adapts the type of the
* given method handle to a new type by pairwise argument conversion.
* given method handle to a new type by pairwise argument conversion.
* The original type and new type must have the same number of arguments.
* The original type and new type must have the same number of arguments.
* The resulting method handle is guaranteed to
confess
a type
* The resulting method handle is guaranteed to
report
a type
* which is equal to the desired new type.
* which is equal to the desired new type.
* <p>
* <p>
* If the original type and new type are equal, returns target.
* If the original type and new type are equal, returns target.
...
@@ -1023,34 +1026,21 @@ public class MethodHandles {
...
@@ -1023,34 +1026,21 @@ public class MethodHandles {
* Given those types T0, T1, one of the following conversions is applied
* Given those types T0, T1, one of the following conversions is applied
* if possible:
* if possible:
* <ul>
* <ul>
* <li>If T0 and T1 are references, and T1 is not an interface type,
* <li>If T0 and T1 are references, then a cast to T1 is applied.
* then a cast to T1 is applied.
* (The types do not need to be related in any particular way.)
* (The types do not need to be related in any particular way.)
* <li>If T0 and T1 are references, and T1 is an interface type,
* <li>If T0 and T1 are primitives, then a Java method invocation
* then the value of type T0 is passed as a T1 without a cast.
* conversion (JLS 5.3) is applied, if one exists.
* (This treatment of interfaces follows the usage of the bytecode verifier.)
* <li>If T0 and T1 are primitives, then a Java casting
* conversion (JLS 5.5) is applied, if one exists.
* <li>If T0 and T1 are primitives and one is boolean,
* the boolean is treated as a one-bit unsigned integer.
* (This treatment follows the usage of the bytecode verifier.)
* A conversion from another primitive type behaves as if
* it first converts to byte, and then masks all but the low bit.
* <li>If T0 is a primitive and T1 a reference, a boxing
* <li>If T0 is a primitive and T1 a reference, a boxing
* conversion is applied if one exists, possibly followed by
* conversion is applied if one exists, possibly followed by
* a
n
reference conversion to a superclass.
* a reference conversion to a superclass.
* T1 must be a wrapper class or a supertype of one.
* T1 must be a wrapper class or a supertype of one.
* If T1 is a wrapper class, T0 is converted if necessary
* to T1's primitive type by one of the preceding conversions.
* Otherwise, T0 is boxed, and its wrapper converted to T1.
* <li>If T0 is a reference and T1 a primitive, an unboxing
* <li>If T0 is a reference and T1 a primitive, an unboxing
* conversion is applied if one exists, possibly preceded by
* conversion will be applied at runtime, possibly followed
* a reference conversion to a wrapper class.
* by a Java method invocation conversion (JLS 5.3)
* on the primitive value. (These are the widening conversions.)
* T0 must be a wrapper class or a supertype of one.
* T0 must be a wrapper class or a supertype of one.
* If T0 is a wrapper class, its primitive value is converted
* (In the case where T0 is Object, these are the conversions
* if necessary to T1 by one of the preceding conversions.
* allowed by java.lang.reflect.Method.invoke.)
* Otherwise, T0 is converted directly to the wrapper type for T1,
* which is then unboxed.
* <li>If the return type T1 is void, any returned value is discarded
* <li>If the return type T1 is void, any returned value is discarded
* <li>If the return type T0 is void and T1 a reference, a null value is introduced.
* <li>If the return type T0 is void and T1 a reference, a null value is introduced.
* <li>If the return type T0 is void and T1 a primitive, a zero value is introduced.
* <li>If the return type T0 is void and T1 a primitive, a zero value is introduced.
...
@@ -1060,8 +1050,9 @@ public class MethodHandles {
...
@@ -1060,8 +1050,9 @@ public class MethodHandles {
* @return a method handle which delegates to {@code target} after performing
* @return a method handle which delegates to {@code target} after performing
* any necessary argument conversions, and arranges for any
* any necessary argument conversions, and arranges for any
* necessary return value conversions
* necessary return value conversions
* @throws
IllegalArgument
Exception if the conversion cannot be made
* @throws
WrongMethodType
Exception if the conversion cannot be made
* @see MethodHandle#asType
* @see MethodHandle#asType
* @see MethodHandles#explicitCastArguments
*/
*/
public
static
public
static
MethodHandle
convertArguments
(
MethodHandle
target
,
MethodType
newType
)
{
MethodHandle
convertArguments
(
MethodHandle
target
,
MethodType
newType
)
{
...
@@ -1081,9 +1072,88 @@ public class MethodHandles {
...
@@ -1081,9 +1072,88 @@ public class MethodHandles {
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle which adapts the type of the
* given method handle to a new type by pairwise argument conversion.
* The original type and new type must have the same number of arguments.
* The resulting method handle is guaranteed to report a type
* which is equal to the desired new type.
* <p>
* If the original type and new type are equal, returns target.
* <p>
* The same conversions are allowed as for {@link #convertArguments convertArguments},
* and some additional conversions are also applied if those conversions fail.
* Given types T0, T1, one of the following conversions is applied
* in addition, if the conversions specified for {@code convertArguments}
* would be insufficient:
* <ul>
* <li>If T0 and T1 are references, and T1 is an interface type,
* then the value of type T0 is passed as a T1 without a cast.
* (This treatment of interfaces follows the usage of the bytecode verifier.)
* <li>If T0 and T1 are primitives and one is boolean,
* the boolean is treated as a one-bit unsigned integer.
* (This treatment follows the usage of the bytecode verifier.)
* A conversion from another primitive type behaves as if
* it first converts to byte, and then masks all but the low bit.
* <li>If a primitive value would be converted by {@code convertArguments}
* using Java method invocation conversion (JLS 5.3),
* Java casting conversion (JLS 5.5) may be used also.
* This allows primitives to be narrowed as well as widened.
* </ul>
* @param target the method handle to invoke after arguments are retyped
* @param newType the expected type of the new method handle
* @return a method handle which delegates to {@code target} after performing
* any necessary argument conversions, and arranges for any
* necessary return value conversions
* @throws WrongMethodTypeException if the conversion cannot be made
* @see MethodHandle#asType
* @see MethodHandles#convertArguments
*/
public
static
MethodHandle
explicitCastArguments
(
MethodHandle
target
,
MethodType
newType
)
{
return
convertArguments
(
target
,
newType
);
// FIXME!
}
/*
FIXME: Reconcile javadoc with 10/22/2010 EG notes on conversion:
Both converters arrange for their method handles to convert arguments
and return values. The conversion rules are the same for arguments
and return values, and depend only on source and target types, S and
T. The conversions allowed by castConvertArguments are a strict
superset of those performed by convertArguments.
In all cases, if S and T are references, a simple checkcast is done.
If neither S nor T is a primitive, no attempt is made to unbox and
box. A failed conversion throws ClassCastException.
If T is void, the value is dropped.
For compatibility with reflection, if S is void and T is a reference,
a null value is produced.
For compatibility with reflection, if S is a reference and T is a
primitive, S is first unboxed and then undergoes primitive conversion.
In the case of 'convertArguments', only assignment conversion is
performed (no narrowing primitive conversion).
If S is a primitive, S is boxed, and then the above rules are applied.
If S and T are both primitives, the boxing will be undetectable; only
the primitive conversions will be apparent to the user. The key point
is that if S is a primitive type, the implementation may box it and
treat is as Object, without loss of information, or it may use a "fast
path" which does not use boxing.
Notwithstanding the rules above, for compatibility with the verifier,
if T is an interface, it is treated as if it were Object. [KEEP THIS?]
Also, for compatibility with the verifier, a boolean may be undergo
widening or narrowing conversion to any other primitive type. [KEEP THIS?]
*/
/**
* Produce a method handle which adapts the calling sequence of the
* Produce a method handle which adapts the calling sequence of the
* given method handle to a new type, by reordering the arguments.
* given method handle to a new type, by reordering the arguments.
* The resulting method handle is guaranteed to
confess
a type
* The resulting method handle is guaranteed to
report
a type
* which is equal to the desired new type.
* which is equal to the desired new type.
* <p>
* <p>
* The given array controls the reordering.
* The given array controls the reordering.
...
@@ -1096,22 +1166,42 @@ public class MethodHandles {
...
@@ -1096,22 +1166,42 @@ public class MethodHandles {
* outgoing argument will be taken from the {@code I}-th incoming
* outgoing argument will be taken from the {@code I}-th incoming
* argument, where {@code I} is {@code reorder[N]}.
* argument, where {@code I} is {@code reorder[N]}.
* <p>
* <p>
* No argument or return value conversions are applied.
* The type of each incoming argument, as determined by {@code newType},
* must be identical to the type of the corresponding outgoing argument
* or arguments in the target method handle.
* The return type of {@code newType} must be identical to the return
* type of the original target.
* <p>
* The reordering array need not specify an actual permutation.
* The reordering array need not specify an actual permutation.
* An incoming argument will be duplicated if its index appears
* An incoming argument will be duplicated if its index appears
* more than once in the array, and an incoming argument will be dropped
* more than once in the array, and an incoming argument will be dropped
* if its index does not appear in the array.
* if its index does not appear in the array.
* <p>
* As in the case of {@link #dropArguments(MethodHandle,int,List) dropArguments},
* Pairwise conversions are applied as needed to arguments and return
* incoming arguments which are not mentioned in the reordering array
* values, as with {@link #convertArguments}.
* are may be any type, as determined only by {@code newType}.
* <blockquote><pre>
MethodType intfn1 = MethodType.methodType(int.class, int.class);
MethodType intfn2 = MethodType.methodType(int.class, int.class, int.class);
MethodHandle sub = ... {int x, int y => x-y} ...;
assert(sub.type().equals(intfn2));
MethodHandle sub1 = MethodHandles.permuteArguments(sub, intfn2, 0, 1);
MethodHandle rsub = MethodHandles.permuteArguments(sub, intfn2, 1, 0);
assert((int)rsub.invokeExact(1, 100) == 99);
MethodHandle add = ... {int x, int y => x+y} ...;
assert(add.type().equals(intfn2));
MethodHandle twice = MethodHandles.permuteArguments(add, intfn1, 0, 0);
assert(twice.type().equals(intfn1));
assert((int)twice.invokeExact(21) == 42);
* </pre></blockquote>
* @param target the method handle to invoke after arguments are reordered
* @param target the method handle to invoke after arguments are reordered
* @param newType the expected type of the new method handle
* @param newType the expected type of the new method handle
* @param reorder a string which controls the reordering
* @param reorder a string which controls the reordering
* @return a method handle which delegates to {@code target} after performing
* @return a method handle which delegates to {@code target} after it
* any necessary argument motion and conversions, and arranges for any
* drops unused arguments and moves and/or duplicates the other arguments
* necessary return value conversions
*/
*/
public
static
public
static
MethodHandle
permuteArguments
(
MethodHandle
target
,
MethodType
newType
,
int
[]
reorder
)
{
MethodHandle
permuteArguments
(
MethodHandle
target
,
MethodType
newType
,
int
...
reorder
)
{
MethodType
oldType
=
target
.
type
();
MethodType
oldType
=
target
.
type
();
checkReorder
(
reorder
,
newType
,
oldType
);
checkReorder
(
reorder
,
newType
,
oldType
);
return
MethodHandleImpl
.
convertArguments
(
IMPL_TOKEN
,
target
,
return
MethodHandleImpl
.
convertArguments
(
IMPL_TOKEN
,
target
,
...
@@ -1134,33 +1224,21 @@ public class MethodHandles {
...
@@ -1134,33 +1224,21 @@ public class MethodHandles {
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
* Produce a method handle which adapts the type of the
* Equivalent to the following code:
* given method handle to a new type, by spreading the final argument.
* <p><blockquote><pre>
* The resulting method handle is guaranteed to confess a type
* int spreadPos = newType.parameterCount() - 1;
* which is equal to the desired new type.
* Class<?> spreadType = newType.parameterType(spreadPos);
* <p>
* int spreadCount = target.type().parameterCount() - spreadPos;
* The final parameter type of the new type must be an array type T[].
* MethodHandle adapter = target.asSpreader(spreadType, spreadCount);
* This is the type of what is called the <i>spread</i> argument.
* adapter = adapter.asType(newType);
* All other arguments of the new type are called <i>ordinary</i> arguments.
* return adapter;
* <p>
* </pre></blockquote>
* The ordinary arguments of the new type are pairwise converted
* @param target the method handle to invoke after argument spreading
* to the initial parameter types of the old type, according to the
* rules in {@link #convertArguments}.
* Any additional arguments in the old type
* are converted from the array element type T,
* again according to the rules in {@link #convertArguments}.
* The return value is converted according likewise.
* <p>
* The call verifies that the spread argument is in fact an array
* of exactly the type length, i.e., the excess number of
* arguments in the old type over the ordinary arguments in the new type.
* If there are no excess arguments, the spread argument is also
* allowed to be null.
* @param target the method handle to invoke after the argument is prepended
* @param newType the expected type of the new method handle
* @param newType the expected type of the new method handle
* @return a
new
method handle which spreads its final argument,
* @return a method handle which spreads its final argument,
* before calling the original method handle
* before calling the original method handle
* @deprecated Use {@link MethodHandle#asSpreader}
*/
*/
public
static
public
static
MethodHandle
spreadArguments
(
MethodHandle
target
,
MethodType
newType
)
{
MethodHandle
spreadArguments
(
MethodHandle
target
,
MethodType
newType
)
{
...
@@ -1180,21 +1258,22 @@ public class MethodHandles {
...
@@ -1180,21 +1258,22 @@ public class MethodHandles {
}
}
/**
/**
* <em>
PROVISIONAL API, WORK IN PROGRESS
:</em>
* <em>
METHOD WILL BE REMOVED FOR PFD
:</em>
*
Produce a method handle which adapts the type of the
*
Equivalent to the following code:
*
given method handle to a new type, by collecting a series of
*
<p><blockquote><pre>
*
trailing arguments as elements to a single argument array.
*
int collectPos = target.type().parameterCount() - 1;
*
<p>
*
Class<?> collectType = target.type().parameterType(collectPos);
*
This method may be used as an inverse to {@link #spreadArguments}.
*
if (!collectType.isArray()) collectType = Object[].class;
*
The final parameter type of the old type must be an array type T[],
*
int collectCount = newType.parameterCount() - collectPos;
*
which is the type of what is called the <i>spread</i> argument.
*
MethodHandle adapter = target.asCollector(collectType, collectCount);
*
The trailing arguments of the new type which correspond to
*
adapter = adapter.asType(newType);
*
the spread argument are all converted to type T and collected
*
return adapter;
*
into an array before the original method is called.
*
</pre></blockquote>
* @param target the method handle to invoke after
the argument is prepended
* @param target the method handle to invoke after
argument collection
* @param newType the expected type of the new method handle
* @param newType the expected type of the new method handle
* @return a
new
method handle which collects some trailing argument
* @return a method handle which collects some trailing argument
* into an array, before calling the original method handle
* into an array, before calling the original method handle
* @deprecated Use {@link MethodHandle#asCollector} instead.
*/
*/
public
static
public
static
MethodHandle
collectArguments
(
MethodHandle
target
,
MethodType
newType
)
{
MethodHandle
collectArguments
(
MethodHandle
target
,
MethodType
newType
)
{
...
@@ -1214,6 +1293,92 @@ public class MethodHandles {
...
@@ -1214,6 +1293,92 @@ public class MethodHandles {
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle of the requested return type which returns the given
* constant value every time it is invoked.
* <p>
* Before the method handle is returned, the passed-in value is converted to the requested type.
* If the requested type is primitive, widening primitive conversions are attempted,
* else reference conversions are attempted.
* <p>The returned method handle is equivalent to {@code identity(type).bindTo(value)},
* unless the type is {@code void}, in which case it is {@code identity(type)}.
* @param type the return type of the desired method handle
* @param value the value to return
* @return a method handle of the given return type and no arguments, which always returns the given value
* @throws WrongMethodTypeException if the value cannot be converted to the required return type
*/
public
static
MethodHandle
constant
(
Class
<?>
type
,
Object
value
)
{
if
(
type
.
isPrimitive
())
{
if
(
type
==
void
.
class
)
return
identity
(
type
);
Wrapper
w
=
Wrapper
.
forPrimitiveType
(
type
);
return
identity
(
type
).
bindTo
(
w
.
convert
(
value
,
type
));
}
else
{
return
identity
(
type
).
bindTo
(
type
.
cast
(
value
));
}
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle of the requested type which returns the given
* constant value every time it is invoked.
* <p>
* Before the method handle is returned, the passed-in value is converted to the requested return type,
* as if by {@link #explicitCastArguments #explicitCastArguments}.
* That is, if the return type is primitive, the value is unboxed,
* and the primitive value is widened and/or narrowed.
* Otherwise, reference conversions are attempted.
* @param type the type of the desired method handle
* @param value the value to return
* @return a method handle of the given return type and no arguments, which always returns the given value
* @throws WrongMethodTypeException if the value cannot be converted to the required return type
*/
public
static
MethodHandle
constant
(
MethodType
type
,
Object
value
)
{
MethodHandle
target
=
constant
(
type
.
returnType
(),
value
);
int
len
=
type
.
parameterCount
();
if
(
len
==
0
)
return
target
.
asType
(
type
);
target
=
target
.
asType
(
type
.
dropParameterTypes
(
0
,
len
));
return
dropArguments
(
target
,
0
,
type
.
parameterList
().
subList
(
0
,
len
));
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle which returns its sole argument when invoked.
* <p>The identity function for {@code void} takes no arguments and returns no values.
* @param type the type of the sole parameter and return value of the desired method handle
* @return a unary method handle which accepts and returns the given type
*/
public
static
MethodHandle
identity
(
Class
<?>
type
)
{
return
ValueConversions
.
identity
(
type
);
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle of the requested type which returns its argument when invoked.
* If the return type differs from the first argument type, the argument will be
* converted as if by {@link #explicitCastArguments explicitCastArguments}.
* All other arguments are discarded.
* <p>The identity function for {@code void} discards all its arguments.
* <p>
* @param type the type of the desired method handle
* @return a method handle of the given type, which always returns its first argument
* @throws WrongMethodTypeException if the first argument cannot be converted to the required return type
*/
public
static
MethodHandle
identity
(
MethodType
type
)
{
MethodHandle
target
=
identity
(
type
.
returnType
());
int
len
=
type
.
parameterCount
();
if
(
len
==
1
)
return
explicitCastArguments
(
target
,
type
);
if
(
len
==
0
)
throw
new
IllegalArgumentException
(
"not enough arguments"
);
target
=
explicitCastArguments
(
target
,
type
.
dropParameterTypes
(
1
,
len
));
return
dropArguments
(
target
,
1
,
type
.
parameterList
().
subList
(
1
,
len
));
}
/**
* Produce a method handle which calls the original method handle {@code target},
* Produce a method handle which calls the original method handle {@code target},
* after inserting the given argument(s) at the given position.
* after inserting the given argument(s) at the given position.
* The formal parameters to {@code target} which will be supplied by those
* The formal parameters to {@code target} which will be supplied by those
...
@@ -1233,8 +1398,9 @@ public class MethodHandles {
...
@@ -1233,8 +1398,9 @@ public class MethodHandles {
* @param target the method handle to invoke after the argument is inserted
* @param target the method handle to invoke after the argument is inserted
* @param pos where to insert the argument (zero for the first)
* @param pos where to insert the argument (zero for the first)
* @param values the series of arguments to insert
* @param values the series of arguments to insert
* @return a
new
method handle which inserts an additional argument,
* @return a method handle which inserts an additional argument,
* before calling the original method handle
* before calling the original method handle
* @see MethodHandle#bindTo
*/
*/
public
static
public
static
MethodHandle
insertArguments
(
MethodHandle
target
,
int
pos
,
Object
...
values
)
{
MethodHandle
insertArguments
(
MethodHandle
target
,
int
pos
,
Object
...
values
)
{
...
@@ -1267,14 +1433,7 @@ public class MethodHandles {
...
@@ -1267,14 +1433,7 @@ public class MethodHandles {
return
result
;
return
result
;
}
}
@Deprecated
// "use MethodHandles.insertArguments instead"
public
static
MethodHandle
insertArgument
(
MethodHandle
target
,
int
pos
,
Object
value
)
{
return
insertArguments
(
target
,
pos
,
value
);
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle which calls the original method handle,
* Produce a method handle which calls the original method handle,
* after dropping the given argument(s) at the given position.
* after dropping the given argument(s) at the given position.
* The type of the new method handle will insert the given argument
* The type of the new method handle will insert the given argument
...
@@ -1302,10 +1461,10 @@ public class MethodHandles {
...
@@ -1302,10 +1461,10 @@ public class MethodHandles {
* MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
* MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
* System.out.println((String) d12.invokeExact("x", 12, true, "z")); // xz
* System.out.println((String) d12.invokeExact("x", 12, true, "z")); // xz
* </pre></blockquote>
* </pre></blockquote>
* @param target the method handle to invoke after the argument
is
dropped
* @param target the method handle to invoke after the argument
s are
dropped
* @param valueTypes the type(s) of the argument to drop
* @param valueTypes the type(s) of the argument
(s)
to drop
* @param pos
which argument to drop (zero for the fir
st)
* @param pos
position of first argument to drop (zero for the leftmo
st)
* @return a
new method handle which drops an argument of the given type
,
* @return a
method handle which drops arguments of the given types
,
* before calling the original method handle
* before calling the original method handle
*/
*/
public
static
public
static
...
@@ -1323,23 +1482,36 @@ public class MethodHandles {
...
@@ -1323,23 +1482,36 @@ public class MethodHandles {
return
MethodHandleImpl
.
dropArguments
(
IMPL_TOKEN
,
target
,
newType
,
pos
);
return
MethodHandleImpl
.
dropArguments
(
IMPL_TOKEN
,
target
,
newType
,
pos
);
}
}
/**
* Produce a method handle which calls the original method handle,
* after dropping the given argument(s) at the given position.
* The type of the new method handle will insert the given argument
* type(s), at that position, into the original handle's type.
* This method is equivalent to the following code:
* <code>
* {@link #dropArguments(MethodHandle,int,List) dropArguments}(target, pos, Arrays.asList(valueTypes))
* </code>
* @param target the method handle to invoke after the arguments are dropped
* @param valueTypes the type(s) of the argument(s) to drop
* @param pos position of first argument to drop (zero for the leftmost)
* @return a method handle which drops arguments of the given types,
* before calling the original method handle
*/
public
static
public
static
MethodHandle
dropArguments
(
MethodHandle
target
,
int
pos
,
Class
<?>...
valueTypes
)
{
MethodHandle
dropArguments
(
MethodHandle
target
,
int
pos
,
Class
<?>...
valueTypes
)
{
return
dropArguments
(
target
,
pos
,
Arrays
.
asList
(
valueTypes
));
return
dropArguments
(
target
,
pos
,
Arrays
.
asList
(
valueTypes
));
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Adapt a target method handle {@code target} by pre-processing
* Adapt a target method handle {@code target} by pre-processing
* one or more of its arguments, each with its own unary filter function,
* one or more of its arguments, each with its own unary filter function,
* and then calling the target with each pre-processed argument
* and then calling the target with each pre-processed argument
* replaced by the result of its corresponding filter function.
* replaced by the result of its corresponding filter function.
* <p>
* <p>
* The pre-processing is performed by one or more method handles,
* The pre-processing is performed by one or more method handles,
* specified in the non-null elements of the {@code filters} array.
* specified in the elements of the {@code filters} array.
* (If there are no such elements, the original target is returned.)
* (If there are no elements in the array, the original target is returned.)
* Each filter (that is, each non-null element of {@code filters})
* Each filter is applied to the corresponding argument of the adapter.
* is applied to the corresponding argument of the adapter.
* <p>
* <p>
* If a filter {@code F} applies to the {@code N}th argument of
* If a filter {@code F} applies to the {@code N}th argument of
* the method handle, then {@code F} must be a method handle which
* the method handle, then {@code F} must be a method handle which
...
@@ -1349,46 +1521,49 @@ public class MethodHandles {
...
@@ -1349,46 +1521,49 @@ public class MethodHandles {
* The return type of {@code F} must be identical to the corresponding
* The return type of {@code F} must be identical to the corresponding
* parameter type of the target.
* parameter type of the target.
* <p>
* <p>
* It is an error if there are
non-null
elements of {@code filters}
* It is an error if there are elements of {@code filters}
* which do not correspond to argument positions in the target.
* which do not correspond to argument positions in the target.
* The actual length of the target array may be any number, it need
* <b>Example:</b>
* not be the same as the parameter count of the target type.
* <p><blockquote><pre>
* (This provides an easy way to filter just the first argument or two
import static java.dyn.MethodHandles.*;
* of a target method handle.)
import static java.dyn.MethodType.*;
* <p> Here is pseudocode for the resulting adapter:
...
* <blockquote><pre>
MethodHandle cat = lookup().findVirtual(String.class,
* // there are N arguments in the A sequence
"concat", methodType(String.class, String.class));
* T target(A[N]...);
MethodHandle upcase = lookup().findVirtual(String.class,
* [i<N] V[i] filter[i](B[i]) = filters[i] ?: identity;
"toUpperCase", methodType(String.class));
* T adapter(B[N]... b) {
System.out.println((String) cat.invokeExact("x", "y")); // xy
* A[N] a...;
MethodHandle f0 = filterArguments(cat, 0, upcase);
* [i<N] a[i] = filter[i](b[i]);
System.out.println((String) f0.invokeExact("x", "y")); // Xy
* return target(a...);
MethodHandle f1 = filterArguments(cat, 1, upcase);
* }
System.out.println((String) f1.invokeExact("x", "y")); // xY
MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
System.out.println((String) f2.invokeExact("x", "y")); // XY
* </pre></blockquote>
* </pre></blockquote>
* @param target the method handle to invoke after arguments are filtered
* @param target the method handle to invoke after arguments are filtered
* @param pos the position of the first argument to filter
* @param filters method handles to call initially on filtered arguments
* @param filters method handles to call initially on filtered arguments
* @return method handle which incorporates the specified argument filtering logic
* @return method handle which incorporates the specified argument filtering logic
* @throws IllegalArgumentException if a
non-null element of {@code filters}
* @throws IllegalArgumentException if a
n element of {@code filters} is null or
* does not match a corresponding argument type of {@code target}
* does not match a corresponding argument type of {@code target}
as described above
*/
*/
public
static
public
static
MethodHandle
filterArguments
(
MethodHandle
target
,
MethodHandle
...
filters
)
{
MethodHandle
filterArguments
(
MethodHandle
target
,
int
pos
,
MethodHandle
...
filters
)
{
MethodType
targetType
=
target
.
type
();
MethodType
targetType
=
target
.
type
();
MethodHandle
adapter
=
target
;
MethodHandle
adapter
=
target
;
MethodType
adapterType
=
targetType
;
MethodType
adapterType
=
targetType
;
int
pos
=
-
1
,
maxPos
=
targetType
.
parameterCount
();
int
maxPos
=
targetType
.
parameterCount
();
int
curPos
=
pos
;
for
(
MethodHandle
filter
:
filters
)
{
for
(
MethodHandle
filter
:
filters
)
{
pos
+=
1
;
if
(
curPos
>=
maxPos
)
if
(
filter
==
null
)
continue
;
if
(
pos
>=
maxPos
)
throw
newIllegalArgumentException
(
"too many filters"
);
throw
newIllegalArgumentException
(
"too many filters"
);
MethodType
filterType
=
filter
.
type
();
MethodType
filterType
=
filter
.
type
();
if
(
filterType
.
parameterCount
()
!=
1
if
(
filterType
.
parameterCount
()
!=
1
||
filterType
.
returnType
()
!=
targetType
.
parameterType
(
p
os
))
||
filterType
.
returnType
()
!=
targetType
.
parameterType
(
curP
os
))
throw
newIllegalArgumentException
(
"target and filter types do not match"
);
throw
newIllegalArgumentException
(
"target and filter types do not match"
);
adapterType
=
adapterType
.
changeParameterType
(
pos
,
filterType
.
parameterType
(
0
));
adapterType
=
adapterType
.
changeParameterType
(
curPos
,
filterType
.
parameterType
(
0
));
adapter
=
MethodHandleImpl
.
filterArgument
(
IMPL_TOKEN
,
adapter
,
pos
,
filter
);
adapter
=
MethodHandleImpl
.
filterArgument
(
IMPL_TOKEN
,
adapter
,
curPos
,
filter
);
curPos
+=
1
;
}
}
MethodType
midType
=
adapter
.
type
();
MethodType
midType
=
adapter
.
type
();
if
(
midType
!=
adapterType
)
if
(
midType
!=
adapterType
)
...
@@ -1396,9 +1571,37 @@ public class MethodHandles {
...
@@ -1396,9 +1571,37 @@ public class MethodHandles {
return
adapter
;
return
adapter
;
}
}
/** Apply the given filter function to the return value of the given target.
/** <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Adapt a target method handle {@code target} by post-processing
* its return value with a unary filter function.
* <p>
* If a filter {@code F} applies to the return value of
* the target method handle, then {@code F} must be a method handle which
* takes exactly one argument. The return type of {@code F}
* replaces the return type of the target
* in the resulting adapted method handle.
* The argument type of {@code F} must be identical to the
* return type of the target.
* <b>Example:</b>
* <p><blockquote><pre>
import static java.dyn.MethodHandles.*;
import static java.dyn.MethodType.*;
...
MethodHandle cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
MethodHandle length = lookup().findVirtual(String.class,
"length", methodType(int.class));
System.out.println((String) cat.invokeExact("x", "y")); // xy
MethodHandle f0 = filterReturnValue(cat, length);
System.out.println((int) f0.invokeExact("x", "y")); // 2
* </pre></blockquote>
* @param target the method handle to invoke before filtering the return value
* @param filter method handle to call on the return value
* @return method handle which incorporates the specified return value filtering logic
* @throws IllegalArgumentException if {@code filter} is null or
* does not match the return type of {@code target} as described above
*/
*/
/*public*/
static
public
static
MethodHandle
filterReturnValue
(
MethodHandle
target
,
MethodHandle
filter
)
{
MethodHandle
filterReturnValue
(
MethodHandle
target
,
MethodHandle
filter
)
{
MethodType
targetType
=
target
.
type
();
MethodType
targetType
=
target
.
type
();
MethodType
filterType
=
filter
.
type
();
MethodType
filterType
=
filter
.
type
();
...
@@ -1411,7 +1614,6 @@ public class MethodHandles {
...
@@ -1411,7 +1614,6 @@ public class MethodHandles {
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Adapt a target method handle {@code target} by pre-processing
* Adapt a target method handle {@code target} by pre-processing
* some of its arguments, and then calling the target with
* some of its arguments, and then calling the target with
* the result of the pre-processing, plus all original arguments.
* the result of the pre-processing, plus all original arguments.
...
@@ -1428,10 +1630,10 @@ public class MethodHandles {
...
@@ -1428,10 +1630,10 @@ public class MethodHandles {
* The resulting adapter is the same type as the target, except that the
* The resulting adapter is the same type as the target, except that the
* initial argument type of the target is dropped.
* initial argument type of the target is dropped.
* <p>
* <p>
* (Note that {@link #dropArguments} can be used to remove any arguments
* (Note that {@link #dropArguments
(MethodHandle,int,List) dropArguments
} can be used to remove any arguments
* that either the {@code combiner} or {@code target} does not wish to receive.
* that either the {@code combiner} or {@code target} does not wish to receive.
* If some of the incoming arguments are destined only for the combiner,
* If some of the incoming arguments are destined only for the combiner,
* consider using {@link
#collectArguments
} instead, since those
* consider using {@link
MethodHandle#asCollector
} instead, since those
* arguments will not need to be live on the stack on entry to the
* arguments will not need to be live on the stack on entry to the
* target.)
* target.)
* <p>
* <p>
...
@@ -1471,31 +1673,7 @@ public class MethodHandles {
...
@@ -1471,31 +1673,7 @@ public class MethodHandles {
return
MethodHandleImpl
.
foldArguments
(
IMPL_TOKEN
,
target
,
newType
,
combiner
);
return
MethodHandleImpl
.
foldArguments
(
IMPL_TOKEN
,
target
,
newType
,
combiner
);
}
}
// /**
// * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
// * Adapt a target method handle {@code target} by pre-processing
// * some of its arguments to derive a new target method handle.
// * Call the new target on the original arguments.
// * @param combined method handle to call initially on the incoming arguments
// * @return method handle which incorporates the specified dispatching logic
// * @throws IllegalArgumentException if the first argument type of
// * {@code combiner}'s return type is not {@link MethodHandle},
// * or if the next argument types of {@code target}
// * are not identical with the argument types of {@code combiner}
// */
// public static
// MethodHandle dispatchArguments(MethodType targetType, MethodHandle dispatcher) {
// MethodType dispatcherType = dispatcher.type();
// int foldArgs = dispatcherType.parameterCount();
// boolean ok = (targetType.parameterCount() >= foldArgs);
// if (!ok)
// throw misMatchedTypes("target and dispatcher types", targetType, dispatcherType);
// MethodHandle target = exactInvoker(targetType);
// return MethodHandleImpl.foldArguments(IMPL_TOKEN, target, targetType, dispatcher);
// }
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Make a method handle which adapts a target method handle,
* Make a method handle which adapts a target method handle,
* by guarding it with a test, a boolean-valued method handle.
* by guarding it with a test, a boolean-valued method handle.
* If the guard fails, a fallback handle is called instead.
* If the guard fails, a fallback handle is called instead.
...
@@ -1572,7 +1750,6 @@ public class MethodHandles {
...
@@ -1572,7 +1750,6 @@ public class MethodHandles {
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Make a method handle which adapts a target method handle,
* Make a method handle which adapts a target method handle,
* by running it inside an exception handler.
* by running it inside an exception handler.
* If the target returns normally, the adapter returns that value.
* If the target returns normally, the adapter returns that value.
...
@@ -1635,6 +1812,7 @@ public class MethodHandles {
...
@@ -1635,6 +1812,7 @@ public class MethodHandles {
}
}
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a wrapper instance of the given "SAM" type which redirects its calls to the given method handle.
* 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.
* A SAM type is a type which declares a single abstract method.
* Additionally, it must have either no constructor (as an interface)
* Additionally, it must have either no constructor (as an interface)
...
@@ -1663,7 +1841,6 @@ public class MethodHandles {
...
@@ -1663,7 +1841,6 @@ public class MethodHandles {
* <li>the SAM type itself and any methods in the SAM type
* <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>the supertypes of the SAM type (if any) and their methods
* <li>{@link Object} and its methods
* <li>{@link Object} and its methods
* <li>{@link MethodHandleProvider} and its methods
* </ul>
* </ul>
* <p>
* <p>
* No stable mapping is promised between the SAM type and
* No stable mapping is promised between the SAM type and
...
@@ -1684,9 +1861,9 @@ public class MethodHandles {
...
@@ -1684,9 +1861,9 @@ public class MethodHandles {
*/
*/
// ISSUE: Should we delegate equals/hashCode to the targets?
// ISSUE: Should we delegate equals/hashCode to the targets?
// Not useful unless there is a stable equals/hashCode behavior
// Not useful unless there is a stable equals/hashCode behavior
// for MethodHandle,
and for MethodHandleProvider.asMethodHandle
.
// for MethodHandle,
but there isn't
.
public
static
public
static
<
T
>
T
asInstance
(
MethodHandle
target
,
Class
<
T
>
samType
)
{
<
T
>
T
asInstance
(
final
MethodHandle
target
,
final
Class
<
T
>
samType
)
{
// POC implementation only; violates the above contract several ways
// POC implementation only; violates the above contract several ways
final
Method
sam
=
getSamMethod
(
samType
);
final
Method
sam
=
getSamMethod
(
samType
);
if
(
sam
==
null
)
if
(
sam
==
null
)
...
@@ -1694,21 +1871,42 @@ public class MethodHandles {
...
@@ -1694,21 +1871,42 @@ public class MethodHandles {
MethodType
samMT
=
MethodType
.
methodType
(
sam
.
getReturnType
(),
sam
.
getParameterTypes
());
MethodType
samMT
=
MethodType
.
methodType
(
sam
.
getReturnType
(),
sam
.
getParameterTypes
());
if
(!
samMT
.
equals
(
target
.
type
()))
if
(!
samMT
.
equals
(
target
.
type
()))
throw
new
IllegalArgumentException
(
"wrong method type"
);
throw
new
IllegalArgumentException
(
"wrong method type"
);
final
MethodHandle
mh
=
target
;
return
samType
.
cast
(
Proxy
.
newProxyInstance
(
return
samType
.
cast
(
Proxy
.
newProxyInstance
(
samType
.
getClassLoader
(),
samType
.
getClassLoader
(),
new
Class
[]{
samType
,
MethodHandleProvider
.
class
},
new
Class
[]{
samType
,
AsInstanceObject
.
class
},
new
InvocationHandler
()
{
new
InvocationHandler
()
{
private
Object
getArg
(
String
name
)
{
if
((
Object
)
name
==
"getAsInstanceTarget"
)
return
target
;
if
((
Object
)
name
==
"getAsInstanceType"
)
return
samType
;
throw
new
AssertionError
();
}
public
Object
invoke
(
Object
proxy
,
Method
method
,
Object
[]
args
)
throws
Throwable
{
public
Object
invoke
(
Object
proxy
,
Method
method
,
Object
[]
args
)
throws
Throwable
{
if
(
method
.
getDeclaringClass
()
==
MethodHandleProvider
.
class
)
{
if
(
method
.
getDeclaringClass
()
==
AsInstanceObject
.
class
)
return
method
.
invoke
(
mh
,
args
);
return
getArg
(
method
.
getName
());
}
assert
method
.
equals
(
sam
)
:
method
;
assert
method
.
equals
(
sam
)
:
method
;
return
mh
.
invokeVarargs
(
args
);
return
target
.
invokeVarargs
(
args
);
}
}
}));
}));
}
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Interface implemented by every object which is produced by {@link #asInstance asInstance}.
* The methods of this interface allow a caller to recover the parameters
* to {@code asInstance}.
* This allows applications to repeatedly convert between method handles
* and SAM objects, without the risk of creating unbounded delegation chains.
*/
public
interface
AsInstanceObject
{
/** Produce or recover a target method handle which is behaviorally
* equivalent to the SAM method of this object.
*/
public
MethodHandle
getAsInstanceTarget
();
/** Recover the SAM type for which this object was created.
*/
public
Class
<?>
getAsInstanceType
();
}
private
static
private
static
Method
getSamMethod
(
Class
<?>
samType
)
{
Method
getSamMethod
(
Class
<?>
samType
)
{
Method
sam
=
null
;
Method
sam
=
null
;
...
...
src/share/classes/java/dyn/MethodType.java
浏览文件 @
5150d263
...
@@ -119,7 +119,7 @@ class MethodType implements java.lang.reflect.Type {
...
@@ -119,7 +119,7 @@ class MethodType implements java.lang.reflect.Type {
for
(
Class
<?>
ptype
:
ptypes
)
{
for
(
Class
<?>
ptype
:
ptypes
)
{
ptype
.
equals
(
ptype
);
// null check
ptype
.
equals
(
ptype
);
// null check
if
(
ptype
==
void
.
class
)
if
(
ptype
==
void
.
class
)
throw
newIllegalArgumentException
(
"
void parameter: "
+
this
);
throw
newIllegalArgumentException
(
"
parameter type cannot be void"
);
}
}
}
}
...
@@ -139,10 +139,6 @@ class MethodType implements java.lang.reflect.Type {
...
@@ -139,10 +139,6 @@ class MethodType implements java.lang.reflect.Type {
MethodType
methodType
(
Class
<?>
rtype
,
Class
<?>[]
ptypes
)
{
MethodType
methodType
(
Class
<?>
rtype
,
Class
<?>[]
ptypes
)
{
return
makeImpl
(
rtype
,
ptypes
,
false
);
return
makeImpl
(
rtype
,
ptypes
,
false
);
}
}
@Deprecated
public
static
MethodType
make
(
Class
<?>
rtype
,
Class
<?>[]
ptypes
)
{
return
methodType
(
rtype
,
ptypes
);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. */
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. */
public
static
public
static
...
@@ -150,10 +146,6 @@ class MethodType implements java.lang.reflect.Type {
...
@@ -150,10 +146,6 @@ class MethodType implements java.lang.reflect.Type {
boolean
notrust
=
false
;
// random List impl. could return evil ptypes array
boolean
notrust
=
false
;
// random List impl. could return evil ptypes array
return
makeImpl
(
rtype
,
ptypes
.
toArray
(
NO_PTYPES
),
notrust
);
return
makeImpl
(
rtype
,
ptypes
.
toArray
(
NO_PTYPES
),
notrust
);
}
}
@Deprecated
public
static
MethodType
make
(
Class
<?>
rtype
,
List
<?
extends
Class
<?>>
ptypes
)
{
return
methodType
(
rtype
,
ptypes
);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* The leading parameter type is prepended to the remaining array.
* The leading parameter type is prepended to the remaining array.
...
@@ -165,10 +157,6 @@ class MethodType implements java.lang.reflect.Type {
...
@@ -165,10 +157,6 @@ class MethodType implements java.lang.reflect.Type {
System
.
arraycopy
(
ptypes
,
0
,
ptypes1
,
1
,
ptypes
.
length
);
System
.
arraycopy
(
ptypes
,
0
,
ptypes1
,
1
,
ptypes
.
length
);
return
makeImpl
(
rtype
,
ptypes1
,
true
);
return
makeImpl
(
rtype
,
ptypes1
,
true
);
}
}
@Deprecated
public
static
MethodType
make
(
Class
<?>
rtype
,
Class
<?>
ptype0
,
Class
<?>...
ptypes
)
{
return
methodType
(
rtype
,
ptype0
,
ptypes
);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* The resulting method has no parameter types.
* The resulting method has no parameter types.
...
@@ -177,10 +165,6 @@ class MethodType implements java.lang.reflect.Type {
...
@@ -177,10 +165,6 @@ class MethodType implements java.lang.reflect.Type {
MethodType
methodType
(
Class
<?>
rtype
)
{
MethodType
methodType
(
Class
<?>
rtype
)
{
return
makeImpl
(
rtype
,
NO_PTYPES
,
true
);
return
makeImpl
(
rtype
,
NO_PTYPES
,
true
);
}
}
@Deprecated
public
static
MethodType
make
(
Class
<?>
rtype
)
{
return
methodType
(
rtype
);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* The resulting method has the single given parameter type.
* The resulting method has the single given parameter type.
...
@@ -189,10 +173,6 @@ class MethodType implements java.lang.reflect.Type {
...
@@ -189,10 +173,6 @@ class MethodType implements java.lang.reflect.Type {
MethodType
methodType
(
Class
<?>
rtype
,
Class
<?>
ptype0
)
{
MethodType
methodType
(
Class
<?>
rtype
,
Class
<?>
ptype0
)
{
return
makeImpl
(
rtype
,
new
Class
<?>[]{
ptype0
},
true
);
return
makeImpl
(
rtype
,
new
Class
<?>[]{
ptype0
},
true
);
}
}
@Deprecated
public
static
MethodType
make
(
Class
<?>
rtype
,
Class
<?>
ptype0
)
{
return
methodType
(
rtype
,
ptype0
);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* The resulting method has the same parameter types as {@code ptypes},
* The resulting method has the same parameter types as {@code ptypes},
...
@@ -202,10 +182,6 @@ class MethodType implements java.lang.reflect.Type {
...
@@ -202,10 +182,6 @@ class MethodType implements java.lang.reflect.Type {
MethodType
methodType
(
Class
<?>
rtype
,
MethodType
ptypes
)
{
MethodType
methodType
(
Class
<?>
rtype
,
MethodType
ptypes
)
{
return
makeImpl
(
rtype
,
ptypes
.
ptypes
,
true
);
return
makeImpl
(
rtype
,
ptypes
.
ptypes
,
true
);
}
}
@Deprecated
public
static
MethodType
make
(
Class
<?>
rtype
,
MethodType
ptypes
)
{
return
methodType
(
rtype
,
ptypes
);
}
/**
/**
* Sole factory method to find or create an interned method type.
* Sole factory method to find or create an interned method type.
...
@@ -275,10 +251,6 @@ class MethodType implements java.lang.reflect.Type {
...
@@ -275,10 +251,6 @@ class MethodType implements java.lang.reflect.Type {
}
}
return
mt
;
return
mt
;
}
}
@Deprecated
public
static
MethodType
makeGeneric
(
int
objectArgCount
,
boolean
varargs
)
{
return
genericMethodType
(
objectArgCount
,
varargs
);
}
/**
/**
* All parameters and the return type will be Object.
* All parameters and the return type will be Object.
...
@@ -290,10 +262,6 @@ class MethodType implements java.lang.reflect.Type {
...
@@ -290,10 +262,6 @@ class MethodType implements java.lang.reflect.Type {
MethodType
genericMethodType
(
int
objectArgCount
)
{
MethodType
genericMethodType
(
int
objectArgCount
)
{
return
genericMethodType
(
objectArgCount
,
false
);
return
genericMethodType
(
objectArgCount
,
false
);
}
}
@Deprecated
public
static
MethodType
makeGeneric
(
int
objectArgCount
)
{
return
genericMethodType
(
objectArgCount
);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @param num the index (zero-based) of the parameter type to change
* @param num the index (zero-based) of the parameter type to change
...
@@ -307,18 +275,6 @@ class MethodType implements java.lang.reflect.Type {
...
@@ -307,18 +275,6 @@ class MethodType implements java.lang.reflect.Type {
return
makeImpl
(
rtype
,
nptypes
,
true
);
return
makeImpl
(
rtype
,
nptypes
,
true
);
}
}
/** Convenience method for {@link #insertParameterTypes}.
* @deprecated Use {@link #insertParameterTypes} instead.
*/
@Deprecated
public
MethodType
insertParameterType
(
int
num
,
Class
<?>
nptype
)
{
int
len
=
ptypes
.
length
;
Class
<?>[]
nptypes
=
Arrays
.
copyOfRange
(
ptypes
,
0
,
len
+
1
);
System
.
arraycopy
(
nptypes
,
num
,
nptypes
,
num
+
1
,
len
-
num
);
nptypes
[
num
]
=
nptype
;
return
makeImpl
(
rtype
,
nptypes
,
true
);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @param num the position (zero-based) of the inserted parameter type(s)
* @param num the position (zero-based) of the inserted parameter type(s)
* @param ptypesToInsert zero or more a new parameter types to insert into the parameter list
* @param ptypesToInsert zero or more a new parameter types to insert into the parameter list
...
@@ -336,6 +292,14 @@ class MethodType implements java.lang.reflect.Type {
...
@@ -336,6 +292,14 @@ class MethodType implements java.lang.reflect.Type {
return
makeImpl
(
rtype
,
nptypes
,
true
);
return
makeImpl
(
rtype
,
nptypes
,
true
);
}
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @param ptypesToInsert zero or more a new parameter types to insert after the end of the parameter list
* @return the same type, except with the selected parameter(s) appended
*/
public
MethodType
appendParameterTypes
(
Class
<?>...
ptypesToInsert
)
{
return
insertParameterTypes
(
parameterCount
(),
ptypesToInsert
);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @param num the position (zero-based) of the inserted parameter type(s)
* @param num the position (zero-based) of the inserted parameter type(s)
* @param ptypesToInsert zero or more a new parameter types to insert into the parameter list
* @param ptypesToInsert zero or more a new parameter types to insert into the parameter list
...
@@ -377,14 +341,6 @@ class MethodType implements java.lang.reflect.Type {
...
@@ -377,14 +341,6 @@ class MethodType implements java.lang.reflect.Type {
return
makeImpl
(
rtype
,
nptypes
,
true
);
return
makeImpl
(
rtype
,
nptypes
,
true
);
}
}
/** Convenience method for {@link #dropParameterTypes}.
* @deprecated Use {@link #dropParameterTypes} instead.
*/
@Deprecated
public
MethodType
dropParameterType
(
int
num
)
{
return
dropParameterTypes
(
num
,
num
+
1
);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @param nrtype a return parameter type to replace the old one with
* @param nrtype a return parameter type to replace the old one with
* @return the same type, except with the return type change
* @return the same type, except with the return type change
...
@@ -690,14 +646,4 @@ class MethodType implements java.lang.reflect.Type {
...
@@ -690,14 +646,4 @@ class MethodType implements java.lang.reflect.Type {
public
String
toMethodDescriptorString
()
{
public
String
toMethodDescriptorString
()
{
return
BytecodeDescriptor
.
unparse
(
this
);
return
BytecodeDescriptor
.
unparse
(
this
);
}
}
/** Temporary alias for toMethodDescriptorString; delete after M3. */
public
String
toBytecodeString
()
{
return
toMethodDescriptorString
();
}
/** Temporary alias for fromMethodDescriptorString; delete after M3. */
public
static
MethodType
fromBytecodeString
(
String
descriptor
,
ClassLoader
loader
)
throws
IllegalArgumentException
,
TypeNotPresentException
{
return
fromMethodDescriptorString
(
descriptor
,
loader
);
}
}
}
src/share/classes/java/dyn/VolatileCallSite.java
0 → 100644
浏览文件 @
5150d263
/*
* 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.List
;
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* A {@code VolatileCallSite} is a {@link CallSite} whose target acts like a volatile variable.
* An {@code invokedynamic} instruction linked to a {@code VolatileCallSite} sees updates
* to its call site target immediately, even if the update occurs in another thread.
* <p>
* Also, a volatile call site has the ability to be <em>invalidated</em>,
* or reset to a well-defined fallback state.
* <p>
* A volatile call site can be used as a switch to control the behavior
* of another method handle. For example:
* <blockquote><pre>
MethodHandle strcat = MethodHandles.lookup()
.findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class));
MethodHandle trueCon = MethodHandles.constant(boolean.class, true);
MethodHandle falseCon = MethodHandles.constant(boolean.class, false);
VolatileCallSite switcher = new VolatileCallSite(trueCon, falseCon);
// following steps may be repeated to re-use the same switcher:
MethodHandle worker1 = strcat;
MethodHandle worker2 = MethodHandles.permuteArguments(strcat, strcat.type(), 1, 0);
MethodHandle worker = MethodHandles.guardWithTest(switcher.dynamicInvoker(), worker1, worker2);
System.out.println((String) worker.invokeExact("met", "hod")); // method
switcher.invalidate();
System.out.println((String) worker.invokeExact("met", "hod")); // hodmet
* </pre></blockquote>
* In this case, the fallback path (worker2) does not cause a state change.
* In a real application, the fallback path could cause call sites to relink
* themselves in response to a global data structure change.
* Thus, volatile call sites can be used to build dependency mechanisms.
* @author John Rose, JSR 292 EG
*/
public
class
VolatileCallSite
extends
CallSite
{
volatile
MethodHandle
fallback
;
/** Create a call site with a volatile target.
* The initial target and fallback are both set to a method handle
* of the given type which will throw {@code IllegalStateException}.
*/
public
VolatileCallSite
(
MethodType
type
)
{
super
(
type
);
fallback
=
target
;
}
/** Create a call site with a volatile target.
* The fallback and target are both set to the same initial value.
*/
public
VolatileCallSite
(
MethodHandle
target
)
{
super
(
target
);
fallback
=
target
;
}
/** Create a call site with a volatile target.
* The fallback and target are set to the given initial values.
*/
public
VolatileCallSite
(
MethodHandle
target
,
MethodHandle
fallback
)
{
this
(
target
);
checkTargetChange
(
target
,
fallback
);
// make sure they have the same type
this
.
fallback
=
fallback
;
}
/** Internal override to nominally final getTarget. */
@Override
MethodHandle
getTarget0
()
{
return
getTargetVolatile
();
}
/**
* Set the target method of this call site, as a volatile variable.
* Has the same effect as {@link CallSite#setTarget}, with the additional
* effects associated with volatiles, in the Java Memory Model.
*/
@Override
public
void
setTarget
(
MethodHandle
newTarget
)
{
checkTargetChange
(
getTargetVolatile
(),
newTarget
);
setTargetVolatile
(
newTarget
);
}
/**
* Return the fallback target for this call site.
* It is initialized to the target the call site had when it was constructed,
* but it may be changed by {@link setFallbackTarget}.
* <p>
* Like the regular target of a volatile call site,
* the fallback target also has the behavior of a volatile variable.
*/
public
MethodHandle
getFallbackTarget
()
{
return
fallback
;
}
/**
* Update the fallback target for this call site.
* @see #getFallbackTarget
*/
public
void
setFallbackTarget
(
MethodHandle
newFallbackTarget
)
{
checkTargetChange
(
fallback
,
newFallbackTarget
);
fallback
=
newFallbackTarget
;
}
/**
* Reset this call site to a known state by changing the target to the fallback target value.
* Equivalent to {@code setTarget(getFallbackTarget())}.
*/
public
void
invalidate
()
{
setTargetVolatile
(
getFallbackTarget
());
}
/**
* Reset all call sites in a list by changing the target of each to its fallback value.
*/
public
static
void
invalidateAll
(
List
<
VolatileCallSite
>
sites
)
{
for
(
VolatileCallSite
site
:
sites
)
{
site
.
invalidate
();
}
}
}
src/share/classes/java/dyn/package-info.java
浏览文件 @
5150d263
...
@@ -24,7 +24,6 @@
...
@@ -24,7 +24,6 @@
*/
*/
/**
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* This package contains dynamic language support provided directly by
* This package contains dynamic language support provided directly by
* the Java core class libraries and virtual machine.
* the Java core class libraries and virtual machine.
* <p>
* <p>
...
@@ -42,13 +41,6 @@
...
@@ -42,13 +41,6 @@
* argument and return value conversions are applied.
* argument and return value conversions are applied.
* </li>
* </li>
*
*
* <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>
*
* <li>The JVM bytecode format supports immediate constants of
* <li>The JVM bytecode format supports immediate constants of
* the classes {@link java.dyn.MethodHandle MethodHandle} and {@link java.dyn.MethodType MethodType}.
* the classes {@link java.dyn.MethodHandle MethodHandle} and {@link java.dyn.MethodType MethodType}.
* </li>
* </li>
...
@@ -56,7 +48,8 @@
...
@@ -56,7 +48,8 @@
*
*
* <h2><a name="jvm_mods"></a>Corresponding JVM bytecode format changes</h2>
* <h2><a name="jvm_mods"></a>Corresponding JVM bytecode format changes</h2>
* <em>The following low-level information is presented here as a preview of
* <em>The following low-level information is presented here as a preview of
* changes being made to the Java Virtual Machine specification for JSR 292.</em>
* changes being made to the Java Virtual Machine specification for JSR 292.
* This information will be incorporated in a future version of the JVM specification.</em>
*
*
* <h3>{@code invokedynamic} instruction format</h3>
* <h3>{@code invokedynamic} instruction format</h3>
* In bytecode, an {@code invokedynamic} instruction is formatted as five bytes.
* In bytecode, an {@code invokedynamic} instruction is formatted as five bytes.
...
@@ -64,22 +57,21 @@
...
@@ -64,22 +57,21 @@
* The next two bytes are a constant pool index (in the same format as for the other {@code invoke} instructions).
* 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 final two bytes are reserved for future use and required to be zero.
* The constant pool reference of an {@code invokedynamic} instruction is to a entry
* 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.
* with tag {@code CONSTANT_InvokeDynamic} (decimal 18). See below for its format.
* The entry specifies the bootstrap method (a {@link java.dyn.MethodHandle MethodHandle} constant),
* (The tag value 17 is also allowed. See below.)
* the dynamic invocation name, and the argument types and return type of the call.
* The entry specifies the following information:
* <ul>
* <li>a bootstrap method (a {@link java.dyn.MethodHandle MethodHandle} constant)</li>
* <li>the dynamic invocation name (a UTF8 string)</li>
* <li>the argument and return types of the call (encoded as a signature in a UTF8 string)</li>
* <li>optionally, a sequence of additional <em>static arguments</em> to the bootstrap method (constants loadable via {@code ldc})</li>
* </ul>
* <p>
* <p>
* Each instance of an {@code invokedynamic} instruction is called a <em>dynamic call site</em>.
* 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
* Multiple instances of an {@code invokedynamic} instruction can share a single
* {@code CONSTANT_InvokeDynamic} entry.
* {@code CONSTANT_InvokeDynamic} entry.
* In any case, distinct call sites always have distinct linkage state.
* In any case, distinct call sites always have distinct linkage state.
* <p>
* <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
* A dynamic call site is originally in an unlinked state. In this state, there is
* no target method for the call site to invoke.
* no target method for the call site to invoke.
* A dynamic call site is linked by means of a bootstrap method,
* A dynamic call site is linked by means of a bootstrap method,
...
@@ -90,17 +82,35 @@
...
@@ -90,17 +82,35 @@
* bootstrap method was specified dynamically, in a per-class basis, during class initialization.)</em>
* bootstrap method was specified dynamically, in a per-class basis, during class initialization.)</em>
*
*
* <h3>constant pool entries for {@code invokedynamic} instructions</h3>
* <h3>constant pool entries for {@code invokedynamic} instructions</h3>
* If a constant pool entry has the tag {@code CONSTANT_InvokeDynamic} (decimal 17),
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* it must contain exactly four more bytes.
* If a constant pool entry has the tag {@code CONSTANT_InvokeDynamic} (decimal 18),
* The first two bytes after the tag must be an index to a {@code CONSTANT_MethodHandle}
* it must contain at least six more bytes after the tag.
* entry, and the second two bytes must be an index to a {@code CONSTANT_NameAndType}.
* All of these bytes are grouped in pairs,
* and each pair is interpreted as a 16-bit index (in the usual {@code u2} format).
* The first pair of bytes after the tag must be an index to a {@code CONSTANT_MethodHandle}
* entry, and the second pair of bytes must be an index to a {@code CONSTANT_NameAndType}.
* The third pair of bytes specifies a count <em>N</em> of remaining byte pairs.
* After the tag and required bytes, there must be exactly <em>2N</em> remaining bytes
* in the constant pool entry, each pair providing the index of a constant pool entry.
* <p>
* The first index specifies a bootstrap method used by the associated dynamic call sites.
* 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 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},
* 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
* except that the bootstrap method reference replaces
* is replaced by a bootstrap method reference.
* the {@code CONSTANT_Class} reference of a {@code CONSTANT_Methodref} entry.
* The remaining indexes (if there is a non-zero count) specify
* <a href="#args">additional static arguments</a> for the bootstrap method.
* <p>
* Some older JVMs may allow an older constant pool entry tag of decimal 17.
* The format and behavior of a constant pool entry with this tag is identical to
* an entry with a tag of decimal 18, except that the constant pool entry must not
* contain extra static arguments or a static argument count.
* The fixed size of such an entry is therefore four bytes after the tag.
* The value of the missing static argument count is taken to be zero.
* <em>(Note: The Proposed Final Draft of this specification is not likely to support
* both of these formats.)</em>
*
*
* <h3>constant pool entries for {@
code MethodType}s
</h3>
* <h3>constant pool entries for {@
linkplain java.dyn.MethodType method types}
</h3>
* If a constant pool entry has the tag {@code CONSTANT_MethodType} (decimal 16),
* If a constant pool entry has the tag {@code CONSTANT_MethodType} (decimal 16),
* it must contain exactly two more bytes, which must be an index to a {@code CONSTANT_Utf8}
* it must contain exactly two more bytes, which must be an index to a {@code CONSTANT_Utf8}
* entry which represents a method type signature.
* entry which represents a method type signature.
...
@@ -112,8 +122,13 @@
...
@@ -112,8 +122,13 @@
* but not initialized.
* but not initialized.
* Access checking and error reporting is performed exactly as it is for
* Access checking and error reporting is performed exactly as it is for
* references by {@code ldc} instructions to {@code CONSTANT_Class} constants.
* references by {@code ldc} instructions to {@code CONSTANT_Class} constants.
* <p>
* Every use of this constant pool entry must lead to the same outcome.
* If the resolution of the names in the method type constant causes an exception to occur,
* this exception must be recorded by the JVM, and re-thrown on every subsequent attempt
* to use this particular constant.
*
*
* <h3>constant pool entries for {@
code MethodHandle}s
</h3>
* <h3>constant pool entries for {@
linkplain java.dyn.MethodHandle method handles}
</h3>
* If a constant pool entry has the tag {@code CONSTANT_MethodHandle} (decimal 15),
* 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
* it must contain exactly three more bytes. The first byte after the tag is a subtag
* value which must be in the range 1 through 9, and the last two must be an index to a
* value which must be in the range 1 through 9, and the last two must be an index to a
...
@@ -129,7 +144,7 @@
...
@@ -129,7 +144,7 @@
* <p>
* <p>
* As with {@code CONSTANT_Class} and {@code CONSTANT_MethodType} constants,
* As with {@code CONSTANT_Class} and {@code CONSTANT_MethodType} constants,
* the {@code Class} or {@code MethodType} object which reifies the field or method's
* the {@code Class} or {@code MethodType} object which reifies the field or method's
* type is created. Any classes mentioned in this reifica
it
on will be loaded if necessary,
* type is created. Any classes mentioned in this reifica
ti
on will be loaded if necessary,
* but not initialized, and access checking and error reporting performed as usual.
* but not initialized, and access checking and error reporting performed as usual.
* <p>
* <p>
* The method handle itself will have a type and behavior determined by the subtag as follows:
* The method handle itself will have a type and behavior determined by the subtag as follows:
...
@@ -150,14 +165,29 @@
...
@@ -150,14 +165,29 @@
* <p>
* <p>
* The special names {@code <init>} and {@code <clinit>} are not allowed except for subtag 8 as shown.
* The special names {@code <init>} and {@code <clinit>} are not allowed except for subtag 8 as shown.
* <p>
* <p>
* The
verifier applies
the same access checks and restrictions for these references as for the hypothetical
* The
JVM verifier and linker apply
the same access checks and restrictions for these references as for the hypothetical
* bytecode instructions specified in the last column of the table. In particular, method handles to
* bytecode instructions specified in the last column of the table. In particular, method handles to
* private and protected members can be created in exactly those classes for which the corresponding
* private and protected members can be created in exactly those classes for which the corresponding
* normal accesses are legal.
* normal accesses are legal.
* <p>
* <p>
* None of these constant types force class initialization.
* A constant may refer to a method or constructor with the {@code varargs}
* Method handles for subtags {@code REF_getStatic}, {@code REF_putStatic}, and {@code REF_invokeStatic}
* bit (hexadecimal {@code 80}) set in its modifier bitmask.
* The method handle constant produced for such a method behaves the same
* as if the {@code varargs} bit were not set.
* The argument-collecting behavior of {@code varargs} can be emulated by
* adapting the method handle constant with
* {@link java.dyn.MethodHandle#asCollector asCollector}.
* There is no provision for doing this automatically.
* <p>
* Although the {@code CONSTANT_MethodHandle} and {@code CONSTANT_MethodType} constant types
* resolve class names, they do not force class initialization.
* Method handle constants 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.
* may force class initialization on their first invocation, just like the corresponding bytecodes.
* <p>
* Every use of this constant pool entry must lead to the same outcome.
* If the resolution of the names in the method handle constant causes an exception to occur,
* this exception must be recorded by the JVM, and re-thrown on every subsequent attempt
* to use this particular constant.
*
*
* <h2><a name="bsm"></a>Bootstrap Methods</h2>
* <h2><a name="bsm"></a>Bootstrap Methods</h2>
* Before the JVM can execute a dynamic call site (an {@code invokedynamic} instruction),
* Before the JVM can execute a dynamic call site (an {@code invokedynamic} instruction),
...
@@ -181,24 +211,36 @@
...
@@ -181,24 +211,36 @@
* call site execution.
* call site execution.
* Linkage does not trigger class initialization.
* Linkage does not trigger class initialization.
* <p>
* <p>
* Next, the bootstrap method call is started, with four values being stacked:
* Next, the bootstrap method call is started, with four
or five
values being stacked:
* <ul>
* <ul>
* <li>a {@code MethodHandle}, the resolved bootstrap method itself </li>
* <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
MethodHandles.Lookup}, a lookup object on
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 String}, the method name mentioned in the call site </li>
* <li>a {@code MethodType}, the resolved type signature of the call </li>
* <li>a {@code MethodType}, the resolved type signature of the call </li>
* <li>optionally, a single object representing one or more <a href="#args">additional static arguments</a> </li>
* </ul>
* </ul>
* The method handle is then applied to the other values as if by
* The method handle is then applied to the other values as if by
* {@linkplain java.dyn.MethodHandle#invokeGeneric the <code>invokeGeneric</code> method}.
* {@link java.dyn.MethodHandle#invokeGeneric invokeGeneric}.
* The returned result must be a {@link java.dyn.CallSite CallSite}, a {@link java.dyn.MethodHandle MethodHandle},
* The returned result must be a {@link java.dyn.CallSite CallSite} (or a subclass).
* or another {@link java.dyn.MethodHandleProvider MethodHandleProvider} value.
* The type of the call site's target must be exactly equal to the type
* 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
* derived from the dynamic call site signature and passed to
* the bootstrap method.
* the bootstrap method.
* The call site then becomes permanently linked to the dynamic call site.
* <p>
* As long as each bootstrap method can be correctly invoked
* by <code>invokeGeneric</code>, its detailed type is arbitrary.
* For example, the first argument could be {@code Object}
* instead of {@code MethodHandles.Lookup}, and the return type
* could also be {@code Object} instead of {@code CallSite}.
* <p>
* As with any method handle constant, a {@code varargs} modifier bit
* on the bootstrap method is ignored.
* <p>
* Note that the first argument of the bootstrap method cannot be
* a simple {@code Class} reference. (This is a change from earlier
* versions of this specification. If the caller class is needed,
* it is easy to {@linkplain java.dyn.MethodHandles.Lookup#lookupClass() extract it}
* from the {@code Lookup} object.
* <p>
* <p>
* After resolution, the linkage process may fail in a variety of ways.
* After resolution, the linkage process may fail in a variety of ways.
* All failures are reported by an {@link java.dyn.InvokeDynamicBootstrapError InvokeDynamicBootstrapError},
* All failures are reported by an {@link java.dyn.InvokeDynamicBootstrapError InvokeDynamicBootstrapError},
...
@@ -206,13 +248,14 @@
...
@@ -206,13 +248,14 @@
* site execution.
* site execution.
* The following circumstances will cause this:
* The following circumstances will cause this:
* <ul>
* <ul>
* <li>the bootstrap method cannot be resolved </li>
* <li>the bootstrap method has the wrong arity,
* causing {@code invokeGeneric} to throw {@code WrongMethodTypeException} </li>
* <li>the bootstrap method has a wrong argument or return type </li>
* <li>the bootstrap method invocation completes abnormally </li>
* <li>the bootstrap method invocation completes abnormally </li>
* <li>the result from the bootstrap invocation is not a reference to
* <li>the result from the bootstrap invocation is not a reference to
* an object of type {@link java.dyn.MethodHandleProvider MethodHandleProvider} </li>
* an object of type {@link java.dyn.CallSite CallSite} </li>
* <li>the call to {@code asMethodHandle} completes abnormally </li>
* <li>the target of the {@code CallSite} does not have a target of
* <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>
* the expected {@code MethodType} </li>
* </ul>
* </ul>
* <h3>timing of linkage</h3>
* <h3>timing of linkage</h3>
...
@@ -220,67 +263,119 @@
...
@@ -220,67 +263,119 @@
* The bootstrap method call implementing the linkage occurs within
* The bootstrap method call implementing the linkage occurs within
* a thread that is attempting a first execution.
* a thread that is attempting a first execution.
* <p>
* <p>
* If there are several such threads, the JVM picks one thread
* If there are several such threads, the bootstrap method may be
* and runs the bootstrap method while the others wait for the
* invoked in several threads concurrently.
* invocation to terminate normally or abnormally.
* Therefore, bootstrap methods which access global application
* <p>
* data must take the usual precautions against race conditions.
* After a bootstrap method is called and a method handle target
* In any case, every {@code invokedynamic} instruction is either
* successfully extracted, the JVM attempts to link the instruction
* unlinked or linked to a unique {@code CallSite} object.
* 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>
* <p>
* In an application which requires dynamic call sites with individually
* In an application which requires dynamic call sites with individually
* mutable behaviors, their bootstrap methods should produce distinct
* mutable behaviors, their bootstrap methods should produce distinct
* {@link java.dyn.CallSite CallSite} objects, one for each linkage request.
* {@link java.dyn.CallSite CallSite} objects, one for each linkage request.
* <p>
* Alternatively, an application can link a single {@code CallSite} object
* If a class containing {@code invokedynamic} instructions
* to several {@code invokedynamic} instructions, in which case
* is {@linkplain java.dyn.Linkage#invalidateCallerClass(Class) invalidated},
* a change to the target method will become visible at each of
* subsequent execution of those {@code invokedynamic} instructions
* the 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>
* <p>
* If several threads simultaneously execute a bootstrap method for a single dynamic
* 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
* call site, the JVM must choose one
{@code CallSite} object and install
it visibly to
* all threads. Any other bootstrap method calls are allowed to complete, but their
* 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
* results are ignored, and their dynamic call site invocations proceed with the originally
* chosen target object.
* chosen target object.
* <p>
* <p>
* The JVM is free to duplicate dynamic call sites.
* <em>Note: Unlike some previous versions of this specification,
* This means that, even if a class contains just one {@code invokedynamic}
* these rules do not enable the JVM to duplicate dynamic call sites,
* instruction, its bootstrap method may be executed several times,
* or to issue “causeless” bootstrap method calls.
* once for each duplicate. Thus, bootstrap method code should not
* Every dynamic call site transitions at most once from unlinked to linked,
* assume an exclusive one-to-one correspondence between particular occurrences
* just before its first invocation.</em>
* of {@code invokedynamic} bytecodes in class files and linkage events.
*
* <p>
* <h3><a name="args">static arguments to the bootstrap method</h3>
* In principle, each individual execution of an {@code invokedynamic}
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* instruction could be deemed (by a conforming implementation) to be a separate
* An {@code invokedynamic} instruction specifies at least three arguments
* duplicate, requiring its own execution of the bootstrap method.
* to pass to its bootstrap method:
* However, implementations are expected to perform code duplication
* The caller class (expressed as a {@link java.dyn.MethodHandles.Lookup Lookup object},
* (if at all) in order to improve performance, not make it worse.
* the name (extracted from the {@code CONSTANT_NameAndType} entry),
* and the type (also extracted from the {@code CONSTANT_NameAndType} entry).
* The {@code invokedynamic} instruction may specify additional metadata values
* to pass to its bootstrap method.
* Collectively, these values are called <em>static arguments</em> to the
* {@code invokedynamic} instruction, because they are used once at link
* time to determine the instruction's behavior on subsequent sets of
* <em>dynamic arguments</em>.
* <p>
* Static arguments are used to communicate application-specific meta-data
* to the bootstrap method.
* Drawn from the constant pool, they may include references to classes, method handles,
* or numeric data that may be relevant to the task of linking that particular call site.
* <p>
* The third byte pair in a {@code CONSTANT_InvokeDynamic} entry, if it is not zero,
* counts up to 65535 additional constant pool indexes which contribute to a static argument.
* Each of these indexes must refer to one of a type of constant entry which is compatible with
* the {@code ldc} instruction.
* Before the bootstrap method is invoked, each index is used to compute an {@code Object}
* reference to the indexed value in the constant pool.
* If the value is a primitive type, it is converted to a reference by boxing conversion.
* The valid constant pool entries are listed in this table:
* <code>
* <table border=1 cellpadding=5 summary="Static argument types">
* <tr><th>entry type</th><th>argument type</th><th>argument value</th></tr>
* <tr><td>CONSTANT_String</td><td><code>java.lang.String</code></td><td>the indexed string literal</td></tr>
* <tr><td>CONSTANT_Class</td><td><code>java.lang.Class</code></td><td>the indexed class, resolved</td></tr>
* <tr><td>CONSTANT_Integer</td><td><code>java.lang.Integer</code></td><td>the indexed int value</td></tr>
* <tr><td>CONSTANT_Long</td><td><code>java.lang.Long</code></td><td>the indexed long value</td></tr>
* <tr><td>CONSTANT_Float</td><td><code>java.lang.Float</code></td><td>the indexed float value</td></tr>
* <tr><td>CONSTANT_Double</td><td><code>java.lang.Double</code></td><td>the indexed double value</td></tr>
* <tr><td>CONSTANT_MethodHandle</td><td><code>java.dyn.MethodHandle</code></td><td>the indexed method handle constant</td></tr>
* <tr><td>CONSTANT_MethodType</td><td><code>java.dyn.MethodType</code></td><td>the indexed method type constant</td></tr>
* </table>
* </code>
* <p>
* If a given {@code invokedynamic} instruction specifies no static arguments,
* the instruction's bootstrap method will be invoked on three arguments,
* conveying the instruction's caller class, name, and method type.
* If the {@code invokedynamic} instruction specifies one or more static arguments,
* a fourth argument will be passed to the bootstrap argument,
* either an {@code Object} reference to the sole extra argument (if there is one)
* or an {@code Object} array of references to all the arguments (if there are two or more),
* as if the bootstrap method is a variable-arity method.
* <code>
* <table border=1 cellpadding=5 summary="Static argument types">
* <tr><th>N</th><th>sample bootstrap method</th></tr>
* <tr><td>0</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type)</code></td></tr>
* <tr><td>1</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type, Object arg)</code></td></tr>
* <tr><td>2</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)</code></td></tr>
* </table>
* </code>
* <p>
* The argument and return types listed here are used by the {@code invokeGeneric}
* call to the bootstrap method.
* As noted above, the actual method type of the bootstrap method can vary.
* For example, the fourth argument could be {@code MethodHandle},
* if that is the type of the corresponding constant in
* the {@code CONSTANT_InvokeDynamic} entry.
* In that case, the {@code invokeGeneric} call will pass the extra method handle
* constant as an {@code Object}, but the type matching machinery of {@code invokeGeneric}
* will cast the reference back to {@code MethodHandle} before invoking the bootstrap method.
* (If a string constant were passed instead, by badly generated code, that cast would then fail.)
* <p>
* If the fourth argument is an array, the array element type must be {@code Object},
* since object arrays (as produced by the JVM at this point) cannot be converted
* to other array types.
* <p>
* If an array is provided, it will appear to be freshly allocated.
* That is, the same array will not appear to two bootstrap method calls.
* <p>
* Extra bootstrap method arguments are intended to allow language implementors
* to safely and compactly encode metadata.
* In principle, the name and extra arguments are redundant,
* since each call site could be given its own unique bootstrap method.
* Such a practice is likely to produce large class files and constant pools.
* <p>
* <em>The Proposed Final Draft of JSR 292 may remove extra static arguments,
* with the associated constant tag of 18, leaving the constant tag 17.
* If the constant tag of 18 is retained, the constant tag 17 may be removed
* for the sake of simplicity.</em>
*
*
* @author John Rose, JSR 292 EG
* @author John Rose, JSR 292 EG
*/
*/
...
...
src/share/classes/sun/dyn/AdapterMethodHandle.java
浏览文件 @
5150d263
...
@@ -487,7 +487,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -487,7 +487,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
static
class
WithTypeHandler
extends
AdapterMethodHandle
{
static
class
WithTypeHandler
extends
AdapterMethodHandle
{
final
MethodHandle
target
,
typeHandler
;
final
MethodHandle
target
,
typeHandler
;
WithTypeHandler
(
MethodHandle
target
,
MethodHandle
typeHandler
)
{
WithTypeHandler
(
MethodHandle
target
,
MethodHandle
typeHandler
)
{
super
(
target
,
target
.
type
(),
OP_RETYPE_ONLY
);
super
(
target
,
target
.
type
(),
makeConv
(
OP_RETYPE_ONLY
)
);
this
.
target
=
target
;
this
.
target
=
target
;
this
.
typeHandler
=
typeHandler
.
asType
(
TYPE_HANDLER_TYPE
);
this
.
typeHandler
=
typeHandler
.
asType
(
TYPE_HANDLER_TYPE
);
}
}
...
...
src/share/classes/sun/dyn/BoundMethodHandle.java
浏览文件 @
5150d263
...
@@ -106,18 +106,17 @@ public class BoundMethodHandle extends MethodHandle {
...
@@ -106,18 +106,17 @@ public class BoundMethodHandle extends MethodHandle {
assert
(
this
instanceof
AdapterMethodHandle
);
assert
(
this
instanceof
AdapterMethodHandle
);
}
}
/** Initialize the current object as a
Java
method handle, binding it
/** Initialize the current object as a
self-bound
method handle, binding it
* as the first argument of the method handle {@code entryPoint}.
* as the first argument of the method handle {@code entryPoint}.
* The invocation type of the resulting method handle will be the
* The invocation type of the resulting method handle will be the
* same as {@code entryPoint}, except that the first argument
* same as {@code entryPoint}, except that the first argument
* type will be dropped.
* type will be dropped.
*/
*/
protected
BoundMethodHandle
(
MethodHandle
entryPoint
)
{
protected
BoundMethodHandle
(
Access
token
,
MethodHandle
entryPoint
)
{
super
(
Access
.
TOKEN
,
entryPoint
.
type
().
dropParameterTypes
(
0
,
1
));
super
(
token
,
entryPoint
.
type
().
dropParameterTypes
(
0
,
1
));
this
.
argument
=
this
;
// kludge; get rid of
this
.
argument
=
this
;
// kludge; get rid of
this
.
vmargslot
=
this
.
type
().
parameterSlotDepth
(
0
);
this
.
vmargslot
=
this
.
type
().
parameterSlotDepth
(
0
);
initTarget
(
entryPoint
,
0
);
initTarget
(
entryPoint
,
0
);
assert
(
this
instanceof
JavaMethodHandle
);
}
}
/** Make sure the given {@code argument} can be used as {@code argnum}-th
/** Make sure the given {@code argument} can be used as {@code argnum}-th
...
@@ -173,6 +172,11 @@ public class BoundMethodHandle extends MethodHandle {
...
@@ -173,6 +172,11 @@ public class BoundMethodHandle extends MethodHandle {
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
return
MethodHandleImpl
.
addTypeString
(
baseName
(),
this
);
}
/** Component of toString() before the type string. */
protected
String
baseName
()
{
MethodHandle
mh
=
this
;
MethodHandle
mh
=
this
;
while
(
mh
instanceof
BoundMethodHandle
)
{
while
(
mh
instanceof
BoundMethodHandle
)
{
Object
info
=
MethodHandleNatives
.
getTargetInfo
(
mh
);
Object
info
=
MethodHandleNatives
.
getTargetInfo
(
mh
);
...
@@ -185,12 +189,16 @@ public class BoundMethodHandle extends MethodHandle {
...
@@ -185,12 +189,16 @@ public class BoundMethodHandle extends MethodHandle {
if
(
name
!=
null
)
if
(
name
!=
null
)
return
name
;
return
name
;
else
else
return
super
.
toString
();
// <unknown>
, probably
return
noParens
(
super
.
toString
());
// "invoke"
, probably
}
}
assert
(
mh
!=
this
);
assert
(
mh
!=
this
);
if
(
mh
instanceof
JavaMethodHandle
)
break
;
// access JMH.toString(), not BMH.toString()
}
}
return
mh
.
toString
();
return
noParens
(
mh
.
toString
());
}
private
static
String
noParens
(
String
str
)
{
int
paren
=
str
.
indexOf
(
'('
);
if
(
paren
>=
0
)
str
=
str
.
substring
(
0
,
paren
);
return
str
;
}
}
}
}
src/share/classes/sun/dyn/CallSiteImpl.java
浏览文件 @
5150d263
...
@@ -41,25 +41,39 @@ public class CallSiteImpl {
...
@@ -41,25 +41,39 @@ public class CallSiteImpl {
Object
info
,
Object
info
,
// Caller information:
// Caller information:
MemberName
callerMethod
,
int
callerBCI
)
{
MemberName
callerMethod
,
int
callerBCI
)
{
Class
<?>
caller
=
callerMethod
.
getDeclaringClass
();
Class
<?>
callerClass
=
callerMethod
.
getDeclaringClass
();
Object
caller
;
if
(
bootstrapMethod
.
type
().
parameterType
(
0
)
==
Class
.
class
)
caller
=
callerClass
;
// remove for PFD
else
caller
=
MethodHandleImpl
.
IMPL_LOOKUP
.
in
(
callerClass
);
if
(
bootstrapMethod
==
null
)
{
if
(
bootstrapMethod
==
null
)
{
// If there is no bootstrap method, throw IncompatibleClassChangeError.
// If there is no bootstrap method, throw IncompatibleClassChangeError.
// This is a valid generic error type for resolution (JLS 12.3.3).
// This is a valid generic error type for resolution (JLS 12.3.3).
throw
new
IncompatibleClassChangeError
throw
new
IncompatibleClassChangeError
(
"Class "
+
caller
.
getName
()+
" has not declared a bootstrap method for invokedynamic"
);
(
"Class "
+
caller
Class
.
getName
()+
" has not declared a bootstrap method for invokedynamic"
);
}
}
CallSite
site
;
CallSite
site
;
try
{
try
{
Object
binding
;
Object
binding
;
if
(
false
)
// switch when invokeGeneric works
if
(
info
==
null
)
{
binding
=
bootstrapMethod
.
invokeGeneric
(
caller
,
name
,
type
);
if
(
false
)
// switch when invokeGeneric works
else
binding
=
bootstrapMethod
.
invokeGeneric
(
caller
,
name
,
type
);
binding
=
bootstrapMethod
.
invokeVarargs
(
new
Object
[]{
caller
,
name
,
type
});
else
binding
=
bootstrapMethod
.
invokeVarargs
(
new
Object
[]{
caller
,
name
,
type
});
}
else
{
info
=
maybeReBox
(
info
);
if
(
false
)
// switch when invokeGeneric works
binding
=
bootstrapMethod
.
invokeGeneric
(
caller
,
name
,
type
,
info
);
else
binding
=
bootstrapMethod
.
invokeVarargs
(
new
Object
[]{
caller
,
name
,
type
,
info
});
}
//System.out.println("BSM for "+name+type+" => "+binding);
//System.out.println("BSM for "+name+type+" => "+binding);
if
(
binding
instanceof
CallSite
)
{
if
(
binding
instanceof
CallSite
)
{
site
=
(
CallSite
)
binding
;
site
=
(
CallSite
)
binding
;
}
else
if
(
binding
instanceof
MethodHandleProvider
)
{
}
else
if
(
binding
instanceof
MethodHandle
)
{
MethodHandle
target
=
((
MethodHandleProvider
)
binding
).
asMethodHandle
();
// Transitional!
MethodHandle
target
=
(
MethodHandle
)
binding
;
site
=
new
ConstantCallSite
(
target
);
site
=
new
ConstantCallSite
(
target
);
}
else
{
}
else
{
throw
new
ClassCastException
(
"bootstrap method failed to produce a MethodHandle or CallSite"
);
throw
new
ClassCastException
(
"bootstrap method failed to produce a MethodHandle or CallSite"
);
...
@@ -79,6 +93,24 @@ public class CallSiteImpl {
...
@@ -79,6 +93,24 @@ public class CallSiteImpl {
return
site
;
return
site
;
}
}
private
static
Object
maybeReBox
(
Object
x
)
{
if
(
x
instanceof
Integer
)
{
int
xi
=
(
int
)
x
;
if
(
xi
==
(
byte
)
xi
)
x
=
xi
;
// must rebox; see JLS 5.1.7
return
x
;
}
else
if
(
x
instanceof
Object
[])
{
Object
[]
xa
=
(
Object
[])
x
;
for
(
int
i
=
0
;
i
<
xa
.
length
;
i
++)
{
if
(
xa
[
i
]
instanceof
Integer
)
xa
[
i
]
=
maybeReBox
(
xa
[
i
]);
}
return
xa
;
}
else
{
return
x
;
}
}
// This method is private in CallSite because it touches private fields in CallSite.
// This method is private in CallSite because it touches private fields in CallSite.
// These private fields (vmmethod, vmindex) are specific to the JVM.
// 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
;
...
...
src/share/classes/sun/dyn/FilterGeneric.java
浏览文件 @
5150d263
...
@@ -115,7 +115,7 @@ class FilterGeneric {
...
@@ -115,7 +115,7 @@ class FilterGeneric {
static
MethodHandle
make
(
Kind
kind
,
int
pos
,
MethodHandle
filter
,
MethodHandle
target
)
{
static
MethodHandle
make
(
Kind
kind
,
int
pos
,
MethodHandle
filter
,
MethodHandle
target
)
{
FilterGeneric
fgen
=
of
(
kind
,
pos
,
filter
.
type
(),
target
.
type
());
FilterGeneric
fgen
=
of
(
kind
,
pos
,
filter
.
type
(),
target
.
type
());
return
fgen
.
makeInstance
(
kind
,
pos
,
filter
,
target
)
.
asMethodHandle
()
;
return
fgen
.
makeInstance
(
kind
,
pos
,
filter
,
target
);
}
}
/** Return the adapter information for this target and filter type. */
/** Return the adapter information for this target and filter type. */
...
@@ -225,13 +225,13 @@ class FilterGeneric {
...
@@ -225,13 +225,13 @@ class FilterGeneric {
* The invoker is kept separate from the target because it can be
* The invoker is kept separate from the target because it can be
* generated once per type erasure family, and reused across adapters.
* generated once per type erasure family, and reused across adapters.
*/
*/
static
abstract
class
Adapter
extends
Java
MethodHandle
{
static
abstract
class
Adapter
extends
Bound
MethodHandle
{
protected
final
MethodHandle
filter
;
// transforms one or more arguments
protected
final
MethodHandle
filter
;
// transforms one or more arguments
protected
final
MethodHandle
target
;
// ultimate target
protected
final
MethodHandle
target
;
// ultimate target
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
return
target
.
toString
(
);
return
MethodHandleImpl
.
addTypeString
(
target
,
this
);
}
}
protected
boolean
isPrototype
()
{
return
target
==
null
;
}
protected
boolean
isPrototype
()
{
return
target
==
null
;
}
...
@@ -246,7 +246,7 @@ class FilterGeneric {
...
@@ -246,7 +246,7 @@ class FilterGeneric {
protected
Adapter
(
MethodHandle
entryPoint
,
protected
Adapter
(
MethodHandle
entryPoint
,
MethodHandle
filter
,
MethodHandle
target
)
{
MethodHandle
filter
,
MethodHandle
target
)
{
super
(
entryPoint
);
super
(
Access
.
TOKEN
,
entryPoint
);
this
.
filter
=
filter
;
this
.
filter
=
filter
;
this
.
target
=
target
;
this
.
target
=
target
;
}
}
...
...
src/share/classes/sun/dyn/FilterOneArgument.java
浏览文件 @
5150d263
...
@@ -36,7 +36,7 @@ import static sun.dyn.MemberName.uncaughtException;
...
@@ -36,7 +36,7 @@ import static sun.dyn.MemberName.uncaughtException;
* final method type is the responsibility of a JVM-level adapter.
* final method type is the responsibility of a JVM-level adapter.
* @author jrose
* @author jrose
*/
*/
public
class
FilterOneArgument
extends
Java
MethodHandle
{
public
class
FilterOneArgument
extends
Bound
MethodHandle
{
protected
final
MethodHandle
filter
;
// Object -> Object
protected
final
MethodHandle
filter
;
// Object -> Object
protected
final
MethodHandle
target
;
// Object -> Object
protected
final
MethodHandle
target
;
// Object -> Object
...
@@ -62,7 +62,7 @@ public class FilterOneArgument extends JavaMethodHandle {
...
@@ -62,7 +62,7 @@ public class FilterOneArgument extends JavaMethodHandle {
}
}
protected
FilterOneArgument
(
MethodHandle
filter
,
MethodHandle
target
)
{
protected
FilterOneArgument
(
MethodHandle
filter
,
MethodHandle
target
)
{
super
(
INVOKE
);
super
(
Access
.
TOKEN
,
INVOKE
);
this
.
filter
=
filter
;
this
.
filter
=
filter
;
this
.
target
=
target
;
this
.
target
=
target
;
}
}
...
...
src/share/classes/sun/dyn/FromGeneric.java
浏览文件 @
5150d263
...
@@ -241,7 +241,7 @@ class FromGeneric {
...
@@ -241,7 +241,7 @@ class FromGeneric {
* The invoker is kept separate from the target because it can be
* The invoker is kept separate from the target because it can be
* generated once per type erasure family, and reused across adapters.
* generated once per type erasure family, and reused across adapters.
*/
*/
static
abstract
class
Adapter
extends
Java
MethodHandle
{
static
abstract
class
Adapter
extends
Bound
MethodHandle
{
/*
/*
* class X<<R,int N>> extends Adapter {
* class X<<R,int N>> extends Adapter {
* (MH, Object**N)=>raw(R) invoker;
* (MH, Object**N)=>raw(R) invoker;
...
@@ -256,7 +256,7 @@ class FromGeneric {
...
@@ -256,7 +256,7 @@ class FromGeneric {
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
return
target
.
toString
(
);
return
MethodHandleImpl
.
addTypeString
(
target
,
this
);
}
}
protected
boolean
isPrototype
()
{
return
target
==
null
;
}
protected
boolean
isPrototype
()
{
return
target
==
null
;
}
...
@@ -271,7 +271,7 @@ class FromGeneric {
...
@@ -271,7 +271,7 @@ class FromGeneric {
protected
Adapter
(
MethodHandle
entryPoint
,
protected
Adapter
(
MethodHandle
entryPoint
,
MethodHandle
invoker
,
MethodHandle
convert
,
MethodHandle
target
)
{
MethodHandle
invoker
,
MethodHandle
convert
,
MethodHandle
target
)
{
super
(
entryPoint
);
super
(
Access
.
TOKEN
,
entryPoint
);
this
.
invoker
=
invoker
;
this
.
invoker
=
invoker
;
this
.
convert
=
convert
;
this
.
convert
=
convert
;
this
.
target
=
target
;
this
.
target
=
target
;
...
...
src/share/classes/sun/dyn/Invokers.java
浏览文件 @
5150d263
...
@@ -26,6 +26,7 @@
...
@@ -26,6 +26,7 @@
package
sun.dyn
;
package
sun.dyn
;
import
java.dyn.*
;
import
java.dyn.*
;
import
sun.dyn.empty.Empty
;
/**
/**
* Construction and caching of often-used invokers.
* Construction and caching of often-used invokers.
...
@@ -48,6 +49,9 @@ public class Invokers {
...
@@ -48,6 +49,9 @@ public class Invokers {
// generic (untyped) invoker for the outgoing call; accepts a single Object[]
// generic (untyped) invoker for the outgoing call; accepts a single Object[]
private
final
/*lazy*/
MethodHandle
[]
varargsInvokers
;
private
final
/*lazy*/
MethodHandle
[]
varargsInvokers
;
// invoker for an unbound callsite
private
/*lazy*/
MethodHandle
uninitializedCallSite
;
/** Compute and cache information common to all collecting adapters
/** Compute and cache information common to all collecting adapters
* that implement members of the erasure-family of the given erased type.
* that implement members of the erasure-family of the given erased type.
*/
*/
...
@@ -107,6 +111,35 @@ public class Invokers {
...
@@ -107,6 +111,35 @@ public class Invokers {
return
vaInvoker
;
return
vaInvoker
;
}
}
private
static
MethodHandle
THROW_UCS
=
null
;
public
MethodHandle
uninitializedCallSite
()
{
MethodHandle
invoker
=
uninitializedCallSite
;
if
(
invoker
!=
null
)
return
invoker
;
if
(
targetType
.
parameterCount
()
>
0
)
{
MethodType
type0
=
targetType
.
dropParameterTypes
(
0
,
targetType
.
parameterCount
());
Invokers
invokers0
=
MethodTypeImpl
.
invokers
(
Access
.
TOKEN
,
type0
);
invoker
=
MethodHandles
.
dropArguments
(
invokers0
.
uninitializedCallSite
(),
0
,
targetType
.
parameterList
());
assert
(
invoker
.
type
().
equals
(
targetType
));
uninitializedCallSite
=
invoker
;
return
invoker
;
}
if
(
THROW_UCS
==
null
)
{
try
{
THROW_UCS
=
MethodHandleImpl
.
IMPL_LOOKUP
.
findStatic
(
CallSite
.
class
,
"uninitializedCallSite"
,
MethodType
.
methodType
(
Empty
.
class
));
}
catch
(
NoAccessException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
invoker
=
AdapterMethodHandle
.
makeRetypeRaw
(
Access
.
TOKEN
,
targetType
,
THROW_UCS
);
assert
(
invoker
.
type
().
equals
(
targetType
));
uninitializedCallSite
=
invoker
;
return
invoker
;
}
public
String
toString
()
{
public
String
toString
()
{
return
"Invokers"
+
targetType
;
return
"Invokers"
+
targetType
;
}
}
...
...
src/share/classes/sun/dyn/JavaMethodHandle.java
已删除
100644 → 0
浏览文件 @
70e0218c
/*
* Copyright (c) 2008, 2009, 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
sun.dyn
;
import
java.dyn.*
;
import
sun.dyn.Access
;
/**
* A Java method handle is a deprecated proposal for extending
* the basic method handle type with additional
* programmer defined methods and fields.
* Its behavior as a method handle is determined at instance creation time,
* by providing the new instance with an "entry point" method handle
* to handle calls. This entry point must accept a leading argument
* whose type is the Java method handle itself or a supertype, and the
* entry point is always called with the Java method handle itself as
* the first argument. This is similar to ordinary virtual methods, which also
* accept the receiver object {@code this} as an implicit leading argument.
* The {@code MethodType} of the Java method handle is the same as that
* of the entry point method handle, with the leading parameter type
* omitted.
* <p>
* Here is an example of usage, creating a hybrid object/functional datum:
* <p><blockquote><pre>
* class Greeter extends JavaMethodHandle {
* private String greeting = "hello";
* public void setGreeting(String s) { greeting = s; }
* public void run() { System.out.println(greeting+", "+greetee); }
* private final String greetee;
* Greeter(String greetee) {
* super(RUN); // alternatively, super("run")
* this.greetee = greetee;
* }
* // the entry point function is computed once:
* private static final MethodHandle RUN
* = MethodHandles.lookup().findVirtual(Greeter.class, "run",
* MethodType.make(void.class));
* }
* // class Main { public static void main(String... av) { ...
* Greeter greeter = new Greeter("world");
* greeter.run(); // prints "hello, world"
* // Statically typed method handle invocation (most direct):
* MethodHandle mh = greeter;
* mh.<void>invokeExact(); // also prints "hello, world"
* // Dynamically typed method handle invocation:
* MethodHandles.invokeExact(greeter); // also prints "hello, world"
* greeter.setGreeting("howdy");
* mh.invokeExact(); // prints "howdy, world" (object-like mutable behavior)
* </pre></blockquote>
* <p>
* In the example of {@code Greeter}, the method {@code run} provides the entry point.
* The entry point need not be a constant value; it may be independently
* computed in each call to the constructor. The entry point does not
* even need to be a method on the {@code Greeter} class, though
* that is the typical case.
* <p>
* The entry point may also be provided symbolically, in which case the the
* {@code JavaMethodHandle} constructor performs the lookup of the entry point.
* This makes it possible to use {@code JavaMethodHandle} to create an anonymous
* inner class:
* <p><blockquote><pre>
* // We can also do this with symbolic names and/or inner classes:
* MethodHandles.invokeExact(new JavaMethodHandle("yow") {
* void yow() { System.out.println("yow, world"); }
* });
* </pre></blockquote>
* <p>
* Here is similar lower-level code which works in terms of a bound method handle.
* <p><blockquote><pre>
* class Greeter {
* public void run() { System.out.println("hello, "+greetee); }
* private final String greetee;
* Greeter(String greetee) { this.greetee = greetee; }
* // the entry point function is computed once:
* private static final MethodHandle RUN
* = MethodHandles.findVirtual(Greeter.class, "run",
* MethodType.make(void.class));
* }
* // class Main { public static void main(String... av) { ...
* Greeter greeter = new Greeter("world");
* greeter.run(); // prints "hello, world"
* MethodHandle mh = MethodHanndles.insertArgument(Greeter.RUN, 0, greeter);
* mh.invokeExact(); // also prints "hello, world"
* </pre></blockquote>
* Note that the method handle must be separately created as a view on the base object.
* This increases footprint, complexity, and dynamic indirections.
* <p>
* Here is a pure functional value expressed most concisely as an anonymous inner class:
* <p><blockquote><pre>
* // class Main { public static void main(String... av) { ...
* final String greetee = "world";
* MethodHandle greeter = new JavaMethodHandle("run") {
* private void run() { System.out.println("hello, "+greetee); }
* }
* greeter.invokeExact(); // prints "hello, world"
* </pre></blockquote>
* <p>
* Here is an abstract parameterized lvalue, efficiently expressed as a subtype of MethodHandle,
* and instantiated as an anonymous class. The data structure is a handle to 1-D array,
* with a specialized index type (long). It is created by inner class, and uses
* signature-polymorphic APIs throughout.
* <p><blockquote><pre>
* abstract class AssignableMethodHandle extends JavaMethodHandle {
* private final MethodHandle setter;
* public MethodHandle setter() { return setter; }
* public AssignableMethodHandle(String get, String set) {
* super(get);
* MethodType getType = this.type();
* MethodType setType = getType.insertParameterType(getType.parameterCount(), getType.returnType()).changeReturnType(void.class);
* this.setter = MethodHandles.publicLookup().bind(this, set, setType);
* }
* }
* // class Main { public static void main(String... av) { ...
* final Number[] stuff = { 123, 456 };
* AssignableMethodHandle stuffPtr = new AssignableMethodHandle("get", "set") {
* public Number get(long i) { return stuff[(int)i]; }
* public void set(long i, Object x) { stuff[(int)i] = x; }
* }
* int x = (Integer) stuffPtr.<Number>invokeExact(1L); // 456
* stuffPtr.setter().<void>invokeExact(0L, (Number) 789); // replaces 123 with 789
* </pre></blockquote>
* @see MethodHandle
* @deprecated The JSR 292 EG intends to replace {@code JavaMethodHandle} with
* an interface-based API for mixing method handle behavior with other classes.
* @author John Rose, JSR 292 EG
*/
public
abstract
class
JavaMethodHandle
// Note: This is an implementation inheritance hack, and will be removed
// with a JVM change which moves the required hidden behavior onto this class.
extends
sun
.
dyn
.
BoundMethodHandle
{
private
static
final
Access
IMPL_TOKEN
=
Access
.
getToken
();
/**
* When creating a {@code JavaMethodHandle}, the actual method handle
* invocation behavior will be delegated to the specified {@code entryPoint}.
* This may be any method handle which can take the newly constructed object
* as a leading parameter.
* <p>
* The method handle type of {@code this} (i.e, the fully constructed object)
* will be {@code entryPoint}, minus the leading argument.
* The leading argument will be bound to {@code this} on every method
* handle invocation.
* @param entryPoint the method handle to handle calls
*/
protected
JavaMethodHandle
(
MethodHandle
entryPoint
)
{
super
(
entryPoint
);
}
}
src/share/classes/sun/dyn/MethodHandleImpl.java
浏览文件 @
5150d263
...
@@ -199,7 +199,7 @@ public abstract class MethodHandleImpl {
...
@@ -199,7 +199,7 @@ public abstract class MethodHandleImpl {
return
allocator
;
return
allocator
;
}
}
static
final
class
AllocateObject
<
C
>
extends
Java
MethodHandle
{
static
final
class
AllocateObject
<
C
>
extends
Bound
MethodHandle
{
private
static
final
Unsafe
unsafe
=
Unsafe
.
getUnsafe
();
private
static
final
Unsafe
unsafe
=
Unsafe
.
getUnsafe
();
private
final
Class
<
C
>
allocateClass
;
private
final
Class
<
C
>
allocateClass
;
...
@@ -207,7 +207,7 @@ public abstract class MethodHandleImpl {
...
@@ -207,7 +207,7 @@ public abstract class MethodHandleImpl {
private
AllocateObject
(
MethodHandle
invoker
,
private
AllocateObject
(
MethodHandle
invoker
,
Class
<
C
>
allocateClass
,
MethodHandle
rawConstructor
)
{
Class
<
C
>
allocateClass
,
MethodHandle
rawConstructor
)
{
super
(
invoker
);
super
(
Access
.
TOKEN
,
invoker
);
this
.
allocateClass
=
allocateClass
;
this
.
allocateClass
=
allocateClass
;
this
.
rawConstructor
=
rawConstructor
;
this
.
rawConstructor
=
rawConstructor
;
}
}
...
@@ -237,7 +237,7 @@ public abstract class MethodHandleImpl {
...
@@ -237,7 +237,7 @@ public abstract class MethodHandleImpl {
}
}
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
return
a
llocateClass
.
getSimpleName
(
);
return
a
ddTypeString
(
allocateClass
.
getSimpleName
(),
this
);
}
}
@SuppressWarnings
(
"unchecked"
)
@SuppressWarnings
(
"unchecked"
)
private
C
allocate
()
throws
InstantiationException
{
private
C
allocate
()
throws
InstantiationException
{
...
@@ -369,19 +369,19 @@ public abstract class MethodHandleImpl {
...
@@ -369,19 +369,19 @@ public abstract class MethodHandleImpl {
return
mhs
[
isSetter
?
1
:
0
];
return
mhs
[
isSetter
?
1
:
0
];
}
}
static
final
class
FieldAccessor
<
C
,
V
>
extends
Java
MethodHandle
{
static
final
class
FieldAccessor
<
C
,
V
>
extends
Bound
MethodHandle
{
private
static
final
Unsafe
unsafe
=
Unsafe
.
getUnsafe
();
private
static
final
Unsafe
unsafe
=
Unsafe
.
getUnsafe
();
final
Object
base
;
// for static refs only
final
Object
base
;
// for static refs only
final
long
offset
;
final
long
offset
;
final
String
name
;
final
String
name
;
public
FieldAccessor
(
Access
token
,
MemberName
field
,
boolean
isSetter
)
{
public
FieldAccessor
(
Access
token
,
MemberName
field
,
boolean
isSetter
)
{
super
(
fhandle
(
field
.
getDeclaringClass
(),
field
.
getFieldType
(),
isSetter
,
field
.
isStatic
()));
super
(
Access
.
TOKEN
,
fhandle
(
field
.
getDeclaringClass
(),
field
.
getFieldType
(),
isSetter
,
field
.
isStatic
()));
this
.
offset
=
(
long
)
field
.
getVMIndex
(
token
);
this
.
offset
=
(
long
)
field
.
getVMIndex
(
token
);
this
.
name
=
field
.
getName
();
this
.
name
=
field
.
getName
();
this
.
base
=
staticBase
(
field
);
this
.
base
=
staticBase
(
field
);
}
}
public
String
toString
()
{
return
name
;
}
public
String
toString
()
{
return
addTypeString
(
name
,
this
)
;
}
int
getFieldI
(
C
obj
)
{
return
unsafe
.
getInt
(
obj
,
offset
);
}
int
getFieldI
(
C
obj
)
{
return
unsafe
.
getInt
(
obj
,
offset
);
}
void
setFieldI
(
C
obj
,
int
x
)
{
unsafe
.
putInt
(
obj
,
offset
,
x
);
}
void
setFieldI
(
C
obj
,
int
x
)
{
unsafe
.
putInt
(
obj
,
offset
,
x
);
}
...
@@ -910,11 +910,11 @@ public abstract class MethodHandleImpl {
...
@@ -910,11 +910,11 @@ public abstract class MethodHandleImpl {
throw
new
UnsupportedOperationException
(
"NYI"
);
throw
new
UnsupportedOperationException
(
"NYI"
);
}
}
private
static
class
GuardWithTest
extends
Java
MethodHandle
{
private
static
class
GuardWithTest
extends
Bound
MethodHandle
{
private
final
MethodHandle
test
,
target
,
fallback
;
private
final
MethodHandle
test
,
target
,
fallback
;
private
GuardWithTest
(
MethodHandle
invoker
,
private
GuardWithTest
(
MethodHandle
invoker
,
MethodHandle
test
,
MethodHandle
target
,
MethodHandle
fallback
)
{
MethodHandle
test
,
MethodHandle
target
,
MethodHandle
fallback
)
{
super
(
invoker
);
super
(
Access
.
TOKEN
,
invoker
);
this
.
test
=
test
;
this
.
test
=
test
;
this
.
target
=
target
;
this
.
target
=
target
;
this
.
fallback
=
fallback
;
this
.
fallback
=
fallback
;
...
@@ -948,7 +948,7 @@ public abstract class MethodHandleImpl {
...
@@ -948,7 +948,7 @@ public abstract class MethodHandleImpl {
}
}
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
return
target
.
toString
(
);
return
addTypeString
(
target
,
this
);
}
}
private
Object
invoke_V
(
Object
...
av
)
throws
Throwable
{
private
Object
invoke_V
(
Object
...
av
)
throws
Throwable
{
if
(
test
.<
boolean
>
invokeExact
(
av
))
if
(
test
.<
boolean
>
invokeExact
(
av
))
...
@@ -1038,7 +1038,7 @@ public abstract class MethodHandleImpl {
...
@@ -1038,7 +1038,7 @@ public abstract class MethodHandleImpl {
return
GuardWithTest
.
make
(
token
,
test
,
target
,
fallback
);
return
GuardWithTest
.
make
(
token
,
test
,
target
,
fallback
);
}
}
private
static
class
GuardWithCatch
extends
Java
MethodHandle
{
private
static
class
GuardWithCatch
extends
Bound
MethodHandle
{
private
final
MethodHandle
target
;
private
final
MethodHandle
target
;
private
final
Class
<?
extends
Throwable
>
exType
;
private
final
Class
<?
extends
Throwable
>
exType
;
private
final
MethodHandle
catcher
;
private
final
MethodHandle
catcher
;
...
@@ -1047,14 +1047,14 @@ public abstract class MethodHandleImpl {
...
@@ -1047,14 +1047,14 @@ public abstract class MethodHandleImpl {
}
}
public
GuardWithCatch
(
MethodHandle
invoker
,
public
GuardWithCatch
(
MethodHandle
invoker
,
MethodHandle
target
,
Class
<?
extends
Throwable
>
exType
,
MethodHandle
catcher
)
{
MethodHandle
target
,
Class
<?
extends
Throwable
>
exType
,
MethodHandle
catcher
)
{
super
(
invoker
);
super
(
Access
.
TOKEN
,
invoker
);
this
.
target
=
target
;
this
.
target
=
target
;
this
.
exType
=
exType
;
this
.
exType
=
exType
;
this
.
catcher
=
catcher
;
this
.
catcher
=
catcher
;
}
}
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
return
target
.
toString
(
);
return
addTypeString
(
target
,
this
);
}
}
private
Object
invoke_V
(
Object
...
av
)
throws
Throwable
{
private
Object
invoke_V
(
Object
...
av
)
throws
Throwable
{
try
{
try
{
...
@@ -1219,21 +1219,24 @@ public abstract class MethodHandleImpl {
...
@@ -1219,21 +1219,24 @@ public abstract class MethodHandleImpl {
if
(
target
!=
null
)
if
(
target
!=
null
)
name
=
MethodHandleNatives
.
getMethodName
(
target
);
name
=
MethodHandleNatives
.
getMethodName
(
target
);
if
(
name
==
null
)
if
(
name
==
null
)
return
"
<unknown>"
;
return
"
invoke"
+
target
.
type
()
;
return
name
.
getName
();
return
name
.
getName
()
+
target
.
type
()
;
}
}
public
static
String
addTypeString
(
MethodHandle
target
)
{
static
String
addTypeString
(
Object
obj
,
MethodHandle
target
)
{
if
(
target
==
null
)
return
"null"
;
String
str
=
String
.
valueOf
(
obj
);
return
target
.
toString
()
+
target
.
type
();
if
(
target
==
null
)
return
str
;
int
paren
=
str
.
indexOf
(
'('
);
if
(
paren
>=
0
)
str
=
str
.
substring
(
0
,
paren
);
return
str
+
target
.
type
();
}
}
public
static
void
checkSpreadArgument
(
Object
av
,
int
n
)
{
static
void
checkSpreadArgument
(
Object
av
,
int
n
)
{
if
(
av
==
null
?
n
!=
0
:
((
Object
[])
av
).
length
!=
n
)
if
(
av
==
null
?
n
!=
0
:
((
Object
[])
av
).
length
!=
n
)
throw
newIllegalArgumentException
(
"Array is not of length "
+
n
);
throw
newIllegalArgumentException
(
"Array is not of length "
+
n
);
}
}
public
static
void
raiseException
(
int
code
,
Object
actual
,
Object
required
)
{
static
void
raiseException
(
int
code
,
Object
actual
,
Object
required
)
{
String
message
;
String
message
;
// disregard the identity of the actual object, if it is not a class:
// disregard the identity of the actual object, if it is not a class:
if
(!(
actual
instanceof
Class
)
&&
!(
actual
instanceof
MethodType
))
if
(!(
actual
instanceof
Class
)
&&
!(
actual
instanceof
MethodType
))
...
...
src/share/classes/sun/dyn/SpreadGeneric.java
浏览文件 @
5150d263
...
@@ -208,7 +208,7 @@ class SpreadGeneric {
...
@@ -208,7 +208,7 @@ class SpreadGeneric {
* The invoker is kept separate from the target because it can be
* The invoker is kept separate from the target because it can be
* generated once per type erasure family, and reused across adapters.
* generated once per type erasure family, and reused across adapters.
*/
*/
static
abstract
class
Adapter
extends
Java
MethodHandle
{
static
abstract
class
Adapter
extends
Bound
MethodHandle
{
/*
/*
* class X<<R,int M,int N>> extends Adapter {
* class X<<R,int M,int N>> extends Adapter {
* (Object**N)=>R target;
* (Object**N)=>R target;
...
@@ -221,21 +221,21 @@ class SpreadGeneric {
...
@@ -221,21 +221,21 @@ class SpreadGeneric {
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
return
target
.
toString
(
);
return
MethodHandleImpl
.
addTypeString
(
target
,
this
);
}
}
static
final
MethodHandle
NO_ENTRY
=
ValueConversions
.
identity
();
static
final
MethodHandle
NO_ENTRY
=
ValueConversions
.
identity
();
protected
boolean
isPrototype
()
{
return
target
==
null
;
}
protected
boolean
isPrototype
()
{
return
target
==
null
;
}
protected
Adapter
(
SpreadGeneric
outer
)
{
protected
Adapter
(
SpreadGeneric
outer
)
{
super
(
NO_ENTRY
);
super
(
Access
.
TOKEN
,
NO_ENTRY
);
this
.
outer
=
outer
;
this
.
outer
=
outer
;
this
.
target
=
null
;
this
.
target
=
null
;
assert
(
isPrototype
());
assert
(
isPrototype
());
}
}
protected
Adapter
(
SpreadGeneric
outer
,
MethodHandle
target
)
{
protected
Adapter
(
SpreadGeneric
outer
,
MethodHandle
target
)
{
super
(
outer
.
entryPoint
);
super
(
Access
.
TOKEN
,
outer
.
entryPoint
);
this
.
outer
=
outer
;
this
.
outer
=
outer
;
this
.
target
=
target
;
this
.
target
=
target
;
}
}
...
...
src/share/classes/sun/dyn/ToGeneric.java
浏览文件 @
5150d263
...
@@ -323,7 +323,7 @@ class ToGeneric {
...
@@ -323,7 +323,7 @@ class ToGeneric {
* via another method handle {@code convert}, which is responsible for
* via another method handle {@code convert}, which is responsible for
* converting the object result into the raw return value.
* converting the object result into the raw return value.
*/
*/
static
abstract
class
Adapter
extends
Java
MethodHandle
{
static
abstract
class
Adapter
extends
Bound
MethodHandle
{
/*
/*
* class X<<R,A...>> extends Adapter {
* class X<<R,A...>> extends Adapter {
* Object...=>Object target;
* Object...=>Object target;
...
@@ -337,13 +337,13 @@ class ToGeneric {
...
@@ -337,13 +337,13 @@ class ToGeneric {
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
return
target
==
null
?
"prototype:"
+
convert
:
target
.
toString
(
);
return
target
==
null
?
"prototype:"
+
convert
:
MethodHandleImpl
.
addTypeString
(
target
,
this
);
}
}
protected
boolean
isPrototype
()
{
return
target
==
null
;
}
protected
boolean
isPrototype
()
{
return
target
==
null
;
}
/* Prototype constructor. */
/* Prototype constructor. */
protected
Adapter
(
MethodHandle
entryPoint
)
{
protected
Adapter
(
MethodHandle
entryPoint
)
{
super
(
entryPoint
);
super
(
Access
.
TOKEN
,
entryPoint
);
this
.
invoker
=
null
;
this
.
invoker
=
null
;
this
.
convert
=
entryPoint
;
this
.
convert
=
entryPoint
;
this
.
target
=
null
;
this
.
target
=
null
;
...
@@ -355,7 +355,7 @@ class ToGeneric {
...
@@ -355,7 +355,7 @@ class ToGeneric {
}
}
protected
Adapter
(
MethodHandle
entryPoint
,
MethodHandle
invoker
,
MethodHandle
convert
,
MethodHandle
target
)
{
protected
Adapter
(
MethodHandle
entryPoint
,
MethodHandle
invoker
,
MethodHandle
convert
,
MethodHandle
target
)
{
super
(
entryPoint
);
super
(
Access
.
TOKEN
,
entryPoint
);
this
.
invoker
=
invoker
;
this
.
invoker
=
invoker
;
this
.
convert
=
convert
;
this
.
convert
=
convert
;
this
.
target
=
target
;
this
.
target
=
target
;
...
...
src/share/classes/sun/dyn/util/ValueConversions.java
浏览文件 @
5150d263
...
@@ -649,7 +649,9 @@ public class ValueConversions {
...
@@ -649,7 +649,9 @@ public class ValueConversions {
return
mh
;
return
mh
;
}
}
// slow path
// slow path
MethodType
type
=
MethodType
.
methodType
(
wrap
.
primitiveType
(),
wrap
.
primitiveType
());
MethodType
type
=
MethodType
.
methodType
(
wrap
.
primitiveType
());
if
(
wrap
!=
Wrapper
.
VOID
)
type
=
type
.
appendParameterTypes
(
wrap
.
primitiveType
());
try
{
try
{
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"identity"
,
type
);
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"identity"
,
type
);
}
catch
(
NoAccessException
ex
)
{
}
catch
(
NoAccessException
ex
)
{
...
@@ -677,7 +679,7 @@ public class ValueConversions {
...
@@ -677,7 +679,7 @@ public class ValueConversions {
}
}
private
static
MethodHandle
retype
(
MethodType
type
,
MethodHandle
mh
)
{
private
static
MethodHandle
retype
(
MethodType
type
,
MethodHandle
mh
)
{
return
AdapterMethodHandle
.
makeRetype
Only
(
IMPL_TOKEN
,
type
,
mh
);
return
AdapterMethodHandle
.
makeRetype
Raw
(
IMPL_TOKEN
,
type
,
mh
);
}
}
private
static
final
Object
[]
NO_ARGS_ARRAY
=
{};
private
static
final
Object
[]
NO_ARGS_ARRAY
=
{};
...
...
src/share/classes/sun/dyn/util/VerifyAccess.java
浏览文件 @
5150d263
...
@@ -25,7 +25,6 @@
...
@@ -25,7 +25,6 @@
package
sun.dyn.util
;
package
sun.dyn.util
;
import
java.dyn.LinkagePermission
;
import
java.dyn.NoAccessException
;
import
java.dyn.NoAccessException
;
import
java.lang.reflect.Modifier
;
import
java.lang.reflect.Modifier
;
import
sun.dyn.MemberName
;
import
sun.dyn.MemberName
;
...
@@ -43,6 +42,7 @@ public class VerifyAccess {
...
@@ -43,6 +42,7 @@ public class VerifyAccess {
private
static
final
int
PACKAGE_ONLY
=
0
;
private
static
final
int
PACKAGE_ONLY
=
0
;
private
static
final
int
ALL_ACCESS_MODES
=
(
PUBLIC
|
PRIVATE
|
PROTECTED
|
PACKAGE_ONLY
);
private
static
final
int
ALL_ACCESS_MODES
=
(
PUBLIC
|
PRIVATE
|
PROTECTED
|
PACKAGE_ONLY
);
private
static
final
boolean
ALLOW_NESTMATE_ACCESS
=
false
;
/**
/**
* Evaluate the JVM linkage rules for access to the given method
* Evaluate the JVM linkage rules for access to the given method
...
@@ -102,6 +102,8 @@ public class VerifyAccess {
...
@@ -102,6 +102,8 @@ public class VerifyAccess {
// a superclass of the lookup class.
// a superclass of the lookup class.
}
}
}
}
if
(
defc
==
lookupClass
)
return
true
;
// easy check; all self-access is OK
switch
(
mods
&
ALL_ACCESS_MODES
)
{
switch
(
mods
&
ALL_ACCESS_MODES
)
{
case
PUBLIC:
case
PUBLIC:
if
(
refc
!=
defc
)
return
true
;
// already checked above
if
(
refc
!=
defc
)
return
true
;
// already checked above
...
@@ -112,7 +114,8 @@ public class VerifyAccess {
...
@@ -112,7 +114,8 @@ public class VerifyAccess {
return
isSamePackage
(
defc
,
lookupClass
);
return
isSamePackage
(
defc
,
lookupClass
);
case
PRIVATE:
case
PRIVATE:
// Loosened rules for privates follows access rules for inner classes.
// Loosened rules for privates follows access rules for inner classes.
return
isSamePackageMember
(
defc
,
lookupClass
);
return
(
ALLOW_NESTMATE_ACCESS
&&
isSamePackageMember
(
defc
,
lookupClass
));
default
:
default
:
throw
new
IllegalArgumentException
(
"bad modifiers: "
+
Modifier
.
toString
(
mods
));
throw
new
IllegalArgumentException
(
"bad modifiers: "
+
Modifier
.
toString
(
mods
));
}
}
...
@@ -206,24 +209,4 @@ public class VerifyAccess {
...
@@ -206,24 +209,4 @@ public class VerifyAccess {
}
}
return
false
;
return
false
;
}
}
/**
* Ensure the requesting class have privileges to perform invokedynamic
* linkage operations on subjectClass. True if requestingClass is
* Access.class (meaning the request originates from the JVM) or if the
* classes are in the same package and have consistent class loaders.
* (The subject class loader must be identical with or be a child of
* the requesting class loader.)
* @param requestingClass
* @param subjectClass
*/
public
static
void
checkBootstrapPrivilege
(
Class
requestingClass
,
Class
subjectClass
,
String
permissionName
)
{
if
(
requestingClass
==
null
)
return
;
if
(
requestingClass
==
subjectClass
)
return
;
SecurityManager
security
=
System
.
getSecurityManager
();
if
(
security
==
null
)
return
;
// open season
if
(
isSamePackage
(
requestingClass
,
subjectClass
))
return
;
security
.
checkPermission
(
new
LinkagePermission
(
permissionName
,
requestingClass
));
}
}
}
src/share/classes/sun/dyn/util/Wrapper.java
浏览文件 @
5150d263
...
@@ -26,17 +26,19 @@
...
@@ -26,17 +26,19 @@
package
sun.dyn.util
;
package
sun.dyn.util
;
public
enum
Wrapper
{
public
enum
Wrapper
{
INT
(
Integer
.
class
,
int
.
class
,
'I'
,
(
Integer
)(
int
)
0
,
Format
.
signed
(
32
)),
BOOLEAN
(
Boolean
.
class
,
boolean
.
class
,
'Z'
,
(
Boolean
)
false
,
Format
.
unsigned
(
1
)),
LONG
(
Long
.
class
,
long
.
class
,
'J'
,
(
Long
)(
long
)
0
,
Format
.
signed
(
64
)),
// These must be in the order defined for widening primitive conversions in JLS 5.1.2
BYTE
(
Byte
.
class
,
byte
.
class
,
'B'
,
(
Byte
)(
byte
)
0
,
Format
.
signed
(
8
)),
BYTE
(
Byte
.
class
,
byte
.
class
,
'B'
,
(
Byte
)(
byte
)
0
,
Format
.
signed
(
8
)),
SHORT
(
Short
.
class
,
short
.
class
,
'S'
,
(
Short
)(
short
)
0
,
Format
.
signed
(
16
)),
SHORT
(
Short
.
class
,
short
.
class
,
'S'
,
(
Short
)(
short
)
0
,
Format
.
signed
(
16
)),
CHAR
(
Character
.
class
,
char
.
class
,
'C'
,
(
Character
)(
char
)
0
,
Format
.
unsigned
(
16
)),
CHAR
(
Character
.
class
,
char
.
class
,
'C'
,
(
Character
)(
char
)
0
,
Format
.
unsigned
(
16
)),
BOOLEAN
(
Boolean
.
class
,
boolean
.
class
,
'Z'
,
(
Boolean
)
false
,
Format
.
unsigned
(
1
)),
INT
(
Integer
.
class
,
int
.
class
,
'I'
,
(
Integer
)(
int
)
0
,
Format
.
signed
(
32
)),
LONG
(
Long
.
class
,
long
.
class
,
'J'
,
(
Long
)(
long
)
0
,
Format
.
signed
(
64
)),
FLOAT
(
Float
.
class
,
float
.
class
,
'F'
,
(
Float
)(
float
)
0
,
Format
.
floating
(
32
)),
FLOAT
(
Float
.
class
,
float
.
class
,
'F'
,
(
Float
)(
float
)
0
,
Format
.
floating
(
32
)),
DOUBLE
(
Double
.
class
,
double
.
class
,
'D'
,
(
Double
)(
double
)
0
,
Format
.
floating
(
64
)),
DOUBLE
(
Double
.
class
,
double
.
class
,
'D'
,
(
Double
)(
double
)
0
,
Format
.
floating
(
64
)),
VOID
(
Void
.
class
,
void
.
class
,
'V'
,
null
,
Format
.
other
(
0
)),
//NULL(Null.class, null.class, 'N', null, Format.other(1)),
//NULL(Null.class, null.class, 'N', null, Format.other(1)),
OBJECT
(
Object
.
class
,
Object
.
class
,
'L'
,
null
,
Format
.
other
(
1
)),
OBJECT
(
Object
.
class
,
Object
.
class
,
'L'
,
null
,
Format
.
other
(
1
)),
// VOID must be the last type, since it is "assignable" from any other type:
VOID
(
Void
.
class
,
void
.
class
,
'V'
,
null
,
Format
.
other
(
0
)),
;
;
private
final
Class
<?>
wrapperType
;
private
final
Class
<?>
wrapperType
;
...
@@ -76,9 +78,11 @@ public enum Wrapper {
...
@@ -76,9 +78,11 @@ public enum Wrapper {
false
);
false
);
return
kind
|
(
size
<<
SIZE_SHIFT
)
|
(
slots
<<
SLOT_SHIFT
);
return
kind
|
(
size
<<
SIZE_SHIFT
)
|
(
slots
<<
SLOT_SHIFT
);
}
}
static
int
static
final
int
INT
=
SIGNED
|
(
32
<<
SIZE_SHIFT
)
|
(
1
<<
SLOT_SHIFT
),
INT
=
SIGNED
|
(
32
<<
SIZE_SHIFT
)
|
(
1
<<
SLOT_SHIFT
),
SHORT
=
SIGNED
|
(
16
<<
SIZE_SHIFT
)
|
(
1
<<
SLOT_SHIFT
),
BOOLEAN
=
UNSIGNED
|
(
1
<<
SIZE_SHIFT
)
|
(
1
<<
SLOT_SHIFT
),
BOOLEAN
=
UNSIGNED
|
(
1
<<
SIZE_SHIFT
)
|
(
1
<<
SLOT_SHIFT
),
CHAR
=
UNSIGNED
|
(
16
<<
SIZE_SHIFT
)
|
(
1
<<
SLOT_SHIFT
),
FLOAT
=
FLOATING
|
(
32
<<
SIZE_SHIFT
)
|
(
1
<<
SLOT_SHIFT
),
FLOAT
=
FLOATING
|
(
32
<<
SIZE_SHIFT
)
|
(
1
<<
SLOT_SHIFT
),
VOID
=
UNSIGNED
|
(
0
<<
SIZE_SHIFT
)
|
(
0
<<
SLOT_SHIFT
),
VOID
=
UNSIGNED
|
(
0
<<
SIZE_SHIFT
)
|
(
0
<<
SLOT_SHIFT
),
NUM_MASK
=
(-
1
)
<<
SIZE_SHIFT
;
NUM_MASK
=
(-
1
)
<<
SIZE_SHIFT
;
...
@@ -111,6 +115,29 @@ public enum Wrapper {
...
@@ -111,6 +115,29 @@ public enum Wrapper {
/** Is the wrapped type either float or double? */
/** Is the wrapped type either float or double? */
public
boolean
isFloating
()
{
return
format
>=
Format
.
FLOAT
;
}
public
boolean
isFloating
()
{
return
format
>=
Format
.
FLOAT
;
}
/** Does the JVM verifier allow a variable of this wrapper's
* primitive type to be assigned from a value of the given wrapper's primitive type?
* Cases:
* <ul>
* <li>unboxing followed by widening primitive conversion
* <li>any type converted to {@code void}
* <li>boxing conversion followed by widening reference conversion to {@code Object}
* <li>conversion of {@code boolean} to any type
* </ul>
*/
public
boolean
isConvertibleFrom
(
Wrapper
source
)
{
if
(
this
==
source
)
return
true
;
if
(
this
.
compareTo
(
source
)
<
0
)
{
// At best, this is a narrowing conversion.
return
false
;
}
if
((
this
.
format
^
source
.
format
)
==
(
Format
.
SHORT
^
Format
.
CHAR
))
{
assert
(
this
==
SHORT
&&
source
==
CHAR
)
||
(
this
==
CHAR
&&
source
==
SHORT
);
return
false
;
}
return
true
;
}
/** Produce a zero value for the given wrapper type.
/** Produce a zero value for the given wrapper type.
* This will be a numeric zero for a number or character,
* This will be a numeric zero for a number or character,
* false for a boolean, and null for a reference or void.
* false for a boolean, and null for a reference or void.
...
@@ -122,10 +149,10 @@ public enum Wrapper {
...
@@ -122,10 +149,10 @@ public enum Wrapper {
public
Object
zero
()
{
return
zero
;
}
public
Object
zero
()
{
return
zero
;
}
/** Produce a zero value for the given wrapper type T.
/** Produce a zero value for the given wrapper type T.
* The opti
no
al argument must a type compatible with this wrapper.
* The opti
on
al argument must a type compatible with this wrapper.
* Equivalent to {@code this.cast(this.zero(), type)}.
* Equivalent to {@code this.cast(this.zero(), type)}.
*/
*/
public
<
T
>
T
zero
(
Class
<
T
>
type
)
{
return
c
as
t
(
zero
,
type
);
}
public
<
T
>
T
zero
(
Class
<
T
>
type
)
{
return
c
onver
t
(
zero
,
type
);
}
// /** Produce a wrapper for the given wrapper or primitive type. */
// /** Produce a wrapper for the given wrapper or primitive type. */
// public static Wrapper valueOf(Class<?> type) {
// public static Wrapper valueOf(Class<?> type) {
...
@@ -264,7 +291,11 @@ public enum Wrapper {
...
@@ -264,7 +291,11 @@ public enum Wrapper {
exampleType
.
isInterface
())
{
exampleType
.
isInterface
())
{
return
forceType
(
wrapperType
,
exampleType
);
return
forceType
(
wrapperType
,
exampleType
);
}
}
throw
new
ClassCastException
(
exampleType
+
" not <:"
+
wrapperType
);
throw
newClassCastException
(
exampleType
,
primitiveType
);
}
private
static
ClassCastException
newClassCastException
(
Class
<?>
actual
,
Class
<?>
expected
)
{
return
new
ClassCastException
(
actual
+
" is not compatible with "
+
expected
);
}
}
/** If {@code type} is a primitive type, return the corresponding
/** If {@code type} is a primitive type, return the corresponding
...
@@ -325,17 +356,55 @@ public enum Wrapper {
...
@@ -325,17 +356,55 @@ public enum Wrapper {
// }
// }
/** Cast a wrapped value to the given type, which may be either a primitive or wrapper type.
/** Cast a wrapped value to the given type, which may be either a primitive or wrapper type.
* The given target type must be this wrapper's primitive or wrapper type.
* If this wrapper is OBJECT, the target type may also be an interface, perform no runtime check.
* Performs standard primitive conversions, including truncation and float conversions.
* Performs standard primitive conversions, including truncation and float conversions.
* The given type must be compatible with this wrapper. That is, it must either
* The given type must be compatible with this wrapper. That is, it must either
* be the wrapper type (or a subtype, in the case of {@code OBJECT}) or else
* be the wrapper type (or a subtype, in the case of {@code OBJECT}) or else
* it must be the wrapper's primitive type.
* it must be the wrapper's primitive type.
* Primitive conversions are only performed if the given type is itself a primitive.
* @throws ClassCastException if the given type is not compatible with this wrapper
* @throws ClassCastException if the given type is not compatible with this wrapper
*/
*/
public
<
T
>
T
cast
(
Object
x
,
Class
<
T
>
type
)
{
public
<
T
>
T
cast
(
Object
x
,
Class
<
T
>
type
)
{
return
convert
(
x
,
type
,
true
);
}
/** Convert a wrapped value to the given type.
* The given target type must be this wrapper's primitive or wrapper type.
* This is equivalent to {@link #cast}, except that it refuses to perform
* narrowing primitive conversions.
*/
public
<
T
>
T
convert
(
Object
x
,
Class
<
T
>
type
)
{
return
convert
(
x
,
type
,
false
);
}
private
<
T
>
T
convert
(
Object
x
,
Class
<
T
>
type
,
boolean
isCast
)
{
if
(
this
==
OBJECT
)
{
// If the target wrapper is OBJECT, just do a reference cast.
// If the target type is an interface, perform no runtime check.
// (This loophole is safe, and is allowed by the JVM verifier.)
// If the target type is a primitive, change it to a wrapper.
@SuppressWarnings
(
"unchecked"
)
T
result
=
(
T
)
x
;
// unchecked warning is expected here
return
result
;
}
Class
<
T
>
wtype
=
wrapperType
(
type
);
Class
<
T
>
wtype
=
wrapperType
(
type
);
if
(
wtype
.
isInstance
(
x
))
if
(
wtype
.
isInstance
(
x
))
{
return
wtype
.
cast
(
x
);
@SuppressWarnings
(
"unchecked"
)
return
wtype
.
cast
(
wrap
(
x
));
T
result
=
(
T
)
x
;
// unchecked warning is expected here
return
result
;
}
Class
<?>
sourceType
=
x
.
getClass
();
// throw NPE if x is null
if
(!
isCast
)
{
Wrapper
source
=
findWrapperType
(
sourceType
);
if
(
source
==
null
||
!
this
.
isConvertibleFrom
(
source
))
{
throw
newClassCastException
(
wtype
,
sourceType
);
}
}
@SuppressWarnings
(
"unchecked"
)
T
result
=
(
T
)
wrap
(
x
);
// unchecked warning is expected here
assert
result
.
getClass
()
==
wtype
;
return
result
;
}
}
/** Cast a reference type to another reference type.
/** Cast a reference type to another reference type.
...
...
test/java/dyn/InvokeGenericTest.java
浏览文件 @
5150d263
...
@@ -398,7 +398,7 @@ public class InvokeGenericTest {
...
@@ -398,7 +398,7 @@ public class InvokeGenericTest {
case
4
:
case
4
:
junk
=
target
.
invokeGeneric
(
args
[
0
],
args
[
1
],
args
[
2
],
args
[
3
]);
break
;
junk
=
target
.
invokeGeneric
(
args
[
0
],
args
[
1
],
args
[
2
],
args
[
3
]);
break
;
default
:
default
:
junk
=
MethodHandles
.
invokeVarargs
(
target
,
args
);
break
;
junk
=
target
.
invokeWithArguments
(
args
);
break
;
}
}
}
catch
(
WrongMethodTypeException
ex
)
{
}
catch
(
WrongMethodTypeException
ex
)
{
return
;
return
;
...
...
test/java/dyn/JavaDocExamples.java
→
test/java/dyn/JavaDocExamples
Test
.java
浏览文件 @
5150d263
...
@@ -25,18 +25,18 @@
...
@@ -25,18 +25,18 @@
/* @test
/* @test
* @summary example code used in javadoc for java.dyn API
* @summary example code used in javadoc for java.dyn API
* @compile -XDallowTransitionalJSR292=no JavaDocExamples.java
* @compile -XDallowTransitionalJSR292=no JavaDocExamples
Test
.java
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.JavaDocExamples
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.JavaDocExamples
Test
*/
*/
/*
/*
---- To run outside jtreg:
---- To run outside jtreg:
$ $JAVA7X_HOME/bin/javac -cp $JUNIT4_JAR -d /tmp/Classes \
$ $JAVA7X_HOME/bin/javac -cp $JUNIT4_JAR -d /tmp/Classes \
$DAVINCI/sources/jdk/test/java/dyn/JavaDocExamples.java
$DAVINCI/sources/jdk/test/java/dyn/JavaDocExamples
Test
.java
$ $JAVA7X_HOME/bin/java -cp $JUNIT4_JAR:/tmp/Classes \
$ $JAVA7X_HOME/bin/java -cp $JUNIT4_JAR:/tmp/Classes \
-XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles \
-XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles \
-Dtest.java.dyn.JavaDocExamples.verbosity=1 \
-Dtest.java.dyn.JavaDocExamples
Test
.verbosity=1 \
test.java.dyn.JavaDocExamples
test.java.dyn.JavaDocExamples
Test
----
----
*/
*/
...
@@ -57,15 +57,15 @@ import static org.junit.Assume.*;
...
@@ -57,15 +57,15 @@ import static org.junit.Assume.*;
/**
/**
* @author jrose
* @author jrose
*/
*/
public
class
JavaDocExamples
{
public
class
JavaDocExamples
Test
{
/** Wrapper for running the JUnit tests in this module.
/** Wrapper for running the JUnit tests in this module.
* Put JUnit on the classpath!
* Put JUnit on the classpath!
*/
*/
public
static
void
main
(
String
...
ignore
)
{
public
static
void
main
(
String
...
ignore
)
{
org
.
junit
.
runner
.
JUnitCore
.
runClasses
(
JavaDocExamples
.
class
);
org
.
junit
.
runner
.
JUnitCore
.
runClasses
(
JavaDocExamples
Test
.
class
);
}
}
// How much output?
// How much output?
static
int
verbosity
=
Integer
.
getInteger
(
"test.java.dyn.JavaDocExamples.verbosity"
,
0
);
static
int
verbosity
=
Integer
.
getInteger
(
"test.java.dyn.JavaDocExamples
Test
.verbosity"
,
0
);
{}
{}
static
final
private
Lookup
LOOKUP
=
lookup
();
static
final
private
Lookup
LOOKUP
=
lookup
();
...
@@ -120,9 +120,79 @@ assertEquals("xz", /*(String)*/ d12.invokeExact("x", 12, true, "z"));
...
@@ -120,9 +120,79 @@ assertEquals("xz", /*(String)*/ d12.invokeExact("x", 12, true, "z"));
}}
}}
}
}
@Test
public
void
testFilterArguments
()
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)*/
MethodHandle
upcase
=
lookup
().
findVirtual
(
String
.
class
,
"toUpperCase"
,
methodType
(
String
.
class
));
assertEquals
(
"xy"
,
/*(String)*/
cat
.
invokeExact
(
"x"
,
"y"
));
// xy
MethodHandle
f0
=
filterArguments
(
cat
,
0
,
upcase
);
assertEquals
(
"Xy"
,
/*(String)*/
f0
.
invokeExact
(
"x"
,
"y"
));
// Xy
MethodHandle
f1
=
filterArguments
(
cat
,
1
,
upcase
);
assertEquals
(
"xY"
,
/*(String)*/
f1
.
invokeExact
(
"x"
,
"y"
));
// xY
MethodHandle
f2
=
filterArguments
(
cat
,
0
,
upcase
,
upcase
);
assertEquals
(
"XY"
,
/*(String)*/
f2
.
invokeExact
(
"x"
,
"y"
));
// XY
}}
}
static
void
assertEquals
(
Object
exp
,
Object
act
)
{
static
void
assertEquals
(
Object
exp
,
Object
act
)
{
if
(
verbosity
>
0
)
if
(
verbosity
>
0
)
System
.
out
.
println
(
"result: "
+
act
);
System
.
out
.
println
(
"result: "
+
act
);
Assert
.
assertEquals
(
exp
,
act
);
Assert
.
assertEquals
(
exp
,
act
);
}
}
@Test
public
void
testVolatileCallSite
()
throws
Throwable
{
{{
{}
/// JAVADOC
MethodHandle
strcat
=
MethodHandles
.
lookup
()
.
findVirtual
(
String
.
class
,
"concat"
,
MethodType
.
methodType
(
String
.
class
,
String
.
class
));
MethodHandle
trueCon
=
MethodHandles
.
constant
(
boolean
.
class
,
true
);
MethodHandle
falseCon
=
MethodHandles
.
constant
(
boolean
.
class
,
false
);
VolatileCallSite
switcher
=
new
VolatileCallSite
(
trueCon
,
falseCon
);
// following steps may be repeated to re-use the same switcher:
MethodHandle
worker1
=
strcat
;
MethodHandle
worker2
=
MethodHandles
.
permuteArguments
(
strcat
,
strcat
.
type
(),
1
,
0
);
MethodHandle
worker
=
MethodHandles
.
guardWithTest
(
switcher
.
dynamicInvoker
(),
worker1
,
worker2
);
System
.
out
.
println
((
String
)
worker
.
invokeExact
(
"met"
,
"hod"
));
// method
switcher
.
invalidate
();
System
.
out
.
println
((
String
)
worker
.
invokeExact
(
"met"
,
"hod"
));
// hodmet
}}
}
static
MethodHandle
asList
;
@Test
public
void
testWithTypeHandler
()
throws
Throwable
{
{{
{}
/// JAVADOC
MethodHandle
makeEmptyList
=
MethodHandles
.
constant
(
List
.
class
,
Arrays
.
asList
());
MethodHandle
asList
=
lookup
()
.
findStatic
(
Arrays
.
class
,
"asList"
,
methodType
(
List
.
class
,
Object
[].
class
));
JavaDocExamplesTest
.
asList
=
asList
;
/*
static MethodHandle collectingTypeHandler(MethodHandle base, MethodType newType) {
return asList.asCollector(Object[].class, newType.parameterCount()).asType(newType);
}
*/
MethodHandle
collectingTypeHandler
=
lookup
()
.
findStatic
(
lookup
().
lookupClass
(),
"collectingTypeHandler"
,
methodType
(
MethodHandle
.
class
,
MethodHandle
.
class
,
MethodType
.
class
));
MethodHandle
makeAnyList
=
makeEmptyList
.
withTypeHandler
(
collectingTypeHandler
);
System
.
out
.
println
(
makeAnyList
.
invokeGeneric
());
System
.
out
.
println
(
makeAnyList
.
invokeGeneric
(
1
));
System
.
out
.
println
(
makeAnyList
.
invokeGeneric
(
"two"
,
"too"
));
}}
}
static
MethodHandle
collectingTypeHandler
(
MethodHandle
base
,
MethodType
newType
)
{
//System.out.println("Converting "+asList+" to "+newType);
MethodHandle
conv
=
asList
.
asCollector
(
Object
[].
class
,
newType
.
parameterCount
()).
asType
(
newType
);
//System.out.println(" =>"+conv);
return
conv
;
}
}
}
test/java/dyn/MethodHandlesTest.java
浏览文件 @
5150d263
...
@@ -62,7 +62,6 @@ public class MethodHandlesTest {
...
@@ -62,7 +62,6 @@ public class MethodHandlesTest {
// lookups, without exercising the actual method handle.
// lookups, without exercising the actual method handle.
static
boolean
DO_MORE_CALLS
=
true
;
static
boolean
DO_MORE_CALLS
=
true
;
@Test
@Test
public
void
testFirst
()
throws
Throwable
{
public
void
testFirst
()
throws
Throwable
{
verbosity
+=
9
;
try
{
verbosity
+=
9
;
try
{
...
@@ -458,7 +457,7 @@ public class MethodHandlesTest {
...
@@ -458,7 +457,7 @@ public class MethodHandlesTest {
Exception
noAccess
=
null
;
Exception
noAccess
=
null
;
try
{
try
{
if
(
verbosity
>=
4
)
System
.
out
.
println
(
"lookup via "
+
lookup
+
" of "
+
defc
+
" "
+
name
+
type
);
if
(
verbosity
>=
4
)
System
.
out
.
println
(
"lookup via "
+
lookup
+
" of "
+
defc
+
" "
+
name
+
type
);
target
=
lookup
.
findStatic
(
defc
,
name
,
type
);
target
=
lookup
.
in
(
defc
).
findStatic
(
defc
,
name
,
type
);
}
catch
(
NoAccessException
ex
)
{
}
catch
(
NoAccessException
ex
)
{
noAccess
=
ex
;
noAccess
=
ex
;
}
}
...
@@ -469,16 +468,22 @@ public class MethodHandlesTest {
...
@@ -469,16 +468,22 @@ public class MethodHandlesTest {
assertEquals
(
positive
?
"positive test"
:
"negative test erroneously passed"
,
positive
,
target
!=
null
);
assertEquals
(
positive
?
"positive test"
:
"negative test erroneously passed"
,
positive
,
target
!=
null
);
if
(!
positive
)
return
;
// negative test failed as expected
if
(!
positive
)
return
;
// negative test failed as expected
assertEquals
(
type
,
target
.
type
());
assertEquals
(
type
,
target
.
type
());
assert
True
(
target
.
toString
().
contains
(
name
));
// rough check
assert
NameStringContains
(
target
,
name
);
if
(!
DO_MORE_CALLS
&&
lookup
!=
PRIVATE
)
return
;
if
(!
DO_MORE_CALLS
&&
lookup
!=
PRIVATE
)
return
;
Object
[]
args
=
randomArgs
(
params
);
Object
[]
args
=
randomArgs
(
params
);
printCalled
(
target
,
name
,
args
);
printCalled
(
target
,
name
,
args
);
target
.
invoke
Vararg
s
(
args
);
target
.
invoke
WithArgument
s
(
args
);
assertCalled
(
name
,
args
);
assertCalled
(
name
,
args
);
if
(
verbosity
>=
1
)
if
(
verbosity
>=
1
)
System
.
out
.
print
(
':'
);
System
.
out
.
print
(
':'
);
}
}
// rough check of name string
static
void
assertNameStringContains
(
Object
x
,
String
s
)
{
if
(
x
.
toString
().
contains
(
s
))
return
;
assertEquals
(
s
,
x
);
}
@Test
@Test
public
void
testFindVirtual
()
throws
Throwable
{
public
void
testFindVirtual
()
throws
Throwable
{
if
(
CAN_SKIP_WORKING
)
return
;
if
(
CAN_SKIP_WORKING
)
return
;
...
@@ -522,7 +527,7 @@ public class MethodHandlesTest {
...
@@ -522,7 +527,7 @@ public class MethodHandlesTest {
Exception
noAccess
=
null
;
Exception
noAccess
=
null
;
try
{
try
{
if
(
verbosity
>=
4
)
System
.
out
.
println
(
"lookup via "
+
lookup
+
" of "
+
defc
+
" "
+
name
+
type
);
if
(
verbosity
>=
4
)
System
.
out
.
println
(
"lookup via "
+
lookup
+
" of "
+
defc
+
" "
+
name
+
type
);
target
=
lookup
.
findVirtual
(
defc
,
methodName
,
type
);
target
=
lookup
.
in
(
defc
).
findVirtual
(
defc
,
methodName
,
type
);
}
catch
(
NoAccessException
ex
)
{
}
catch
(
NoAccessException
ex
)
{
noAccess
=
ex
;
noAccess
=
ex
;
}
}
...
@@ -535,12 +540,12 @@ public class MethodHandlesTest {
...
@@ -535,12 +540,12 @@ public class MethodHandlesTest {
Class
<?>[]
paramsWithSelf
=
cat
(
array
(
Class
[].
class
,
(
Class
)
defc
),
params
);
Class
<?>[]
paramsWithSelf
=
cat
(
array
(
Class
[].
class
,
(
Class
)
defc
),
params
);
MethodType
typeWithSelf
=
MethodType
.
methodType
(
ret
,
paramsWithSelf
);
MethodType
typeWithSelf
=
MethodType
.
methodType
(
ret
,
paramsWithSelf
);
assertEquals
(
typeWithSelf
,
target
.
type
());
assertEquals
(
typeWithSelf
,
target
.
type
());
assert
True
(
target
.
toString
().
contains
(
methodName
));
// rough check
assert
NameStringContains
(
target
,
methodName
);
if
(!
DO_MORE_CALLS
&&
lookup
!=
PRIVATE
)
return
;
if
(!
DO_MORE_CALLS
&&
lookup
!=
PRIVATE
)
return
;
Object
[]
argsWithSelf
=
randomArgs
(
paramsWithSelf
);
Object
[]
argsWithSelf
=
randomArgs
(
paramsWithSelf
);
if
(
rcvc
!=
defc
)
argsWithSelf
[
0
]
=
randomArg
(
rcvc
);
if
(
rcvc
!=
defc
)
argsWithSelf
[
0
]
=
randomArg
(
rcvc
);
printCalled
(
target
,
name
,
argsWithSelf
);
printCalled
(
target
,
name
,
argsWithSelf
);
target
.
invoke
Vararg
s
(
argsWithSelf
);
target
.
invoke
WithArgument
s
(
argsWithSelf
);
assertCalled
(
name
,
argsWithSelf
);
assertCalled
(
name
,
argsWithSelf
);
if
(
verbosity
>=
1
)
if
(
verbosity
>=
1
)
System
.
out
.
print
(
':'
);
System
.
out
.
print
(
':'
);
...
@@ -576,7 +581,8 @@ public class MethodHandlesTest {
...
@@ -576,7 +581,8 @@ public class MethodHandlesTest {
Exception
noAccess
=
null
;
Exception
noAccess
=
null
;
try
{
try
{
if
(
verbosity
>=
4
)
System
.
out
.
println
(
"lookup via "
+
lookup
+
" of "
+
defc
+
" "
+
name
+
type
);
if
(
verbosity
>=
4
)
System
.
out
.
println
(
"lookup via "
+
lookup
+
" of "
+
defc
+
" "
+
name
+
type
);
target
=
lookup
.
findSpecial
(
defc
,
name
,
type
,
specialCaller
);
if
(
verbosity
>=
5
)
System
.
out
.
println
(
" lookup => "
+
lookup
.
in
(
specialCaller
));
target
=
lookup
.
in
(
specialCaller
).
findSpecial
(
defc
,
name
,
type
,
specialCaller
);
}
catch
(
NoAccessException
ex
)
{
}
catch
(
NoAccessException
ex
)
{
noAccess
=
ex
;
noAccess
=
ex
;
}
}
...
@@ -591,11 +597,11 @@ public class MethodHandlesTest {
...
@@ -591,11 +597,11 @@ public class MethodHandlesTest {
assertEquals
(
type
,
target
.
type
().
dropParameterTypes
(
0
,
1
));
assertEquals
(
type
,
target
.
type
().
dropParameterTypes
(
0
,
1
));
Class
<?>[]
paramsWithSelf
=
cat
(
array
(
Class
[].
class
,
(
Class
)
specialCaller
),
params
);
Class
<?>[]
paramsWithSelf
=
cat
(
array
(
Class
[].
class
,
(
Class
)
specialCaller
),
params
);
MethodType
typeWithSelf
=
MethodType
.
methodType
(
ret
,
paramsWithSelf
);
MethodType
typeWithSelf
=
MethodType
.
methodType
(
ret
,
paramsWithSelf
);
assert
True
(
target
.
toString
().
contains
(
name
));
// rough check
assert
NameStringContains
(
target
,
name
);
if
(!
DO_MORE_CALLS
&&
lookup
!=
PRIVATE
&&
lookup
!=
EXAMPLE
)
return
;
if
(!
DO_MORE_CALLS
&&
lookup
!=
PRIVATE
&&
lookup
!=
EXAMPLE
)
return
;
Object
[]
args
=
randomArgs
(
paramsWithSelf
);
Object
[]
args
=
randomArgs
(
paramsWithSelf
);
printCalled
(
target
,
name
,
args
);
printCalled
(
target
,
name
,
args
);
target
.
invoke
Vararg
s
(
args
);
target
.
invoke
WithArgument
s
(
args
);
assertCalled
(
name
,
args
);
assertCalled
(
name
,
args
);
}
}
...
@@ -632,7 +638,7 @@ public class MethodHandlesTest {
...
@@ -632,7 +638,7 @@ public class MethodHandlesTest {
Exception
noAccess
=
null
;
Exception
noAccess
=
null
;
try
{
try
{
if
(
verbosity
>=
4
)
System
.
out
.
println
(
"lookup via "
+
lookup
+
" of "
+
defc
+
" "
+
name
+
type
);
if
(
verbosity
>=
4
)
System
.
out
.
println
(
"lookup via "
+
lookup
+
" of "
+
defc
+
" "
+
name
+
type
);
target
=
lookup
.
bind
(
receiver
,
methodName
,
type
);
target
=
lookup
.
in
(
defc
).
bind
(
receiver
,
methodName
,
type
);
}
catch
(
NoAccessException
ex
)
{
}
catch
(
NoAccessException
ex
)
{
noAccess
=
ex
;
noAccess
=
ex
;
}
}
...
@@ -645,7 +651,7 @@ public class MethodHandlesTest {
...
@@ -645,7 +651,7 @@ public class MethodHandlesTest {
assertEquals
(
type
,
target
.
type
());
assertEquals
(
type
,
target
.
type
());
Object
[]
args
=
randomArgs
(
params
);
Object
[]
args
=
randomArgs
(
params
);
printCalled
(
target
,
name
,
args
);
printCalled
(
target
,
name
,
args
);
target
.
invoke
Vararg
s
(
args
);
target
.
invoke
WithArgument
s
(
args
);
Object
[]
argsWithReceiver
=
cat
(
array
(
Object
[].
class
,
receiver
),
args
);
Object
[]
argsWithReceiver
=
cat
(
array
(
Object
[].
class
,
receiver
),
args
);
assertCalled
(
name
,
argsWithReceiver
);
assertCalled
(
name
,
argsWithReceiver
);
if
(
verbosity
>=
1
)
if
(
verbosity
>=
1
)
...
@@ -705,9 +711,9 @@ public class MethodHandlesTest {
...
@@ -705,9 +711,9 @@ public class MethodHandlesTest {
try
{
try
{
if
(
verbosity
>=
4
)
System
.
out
.
println
(
"lookup via "
+
lookup
+
" of "
+
defc
+
" "
+
name
+
type
);
if
(
verbosity
>=
4
)
System
.
out
.
println
(
"lookup via "
+
lookup
+
" of "
+
defc
+
" "
+
name
+
type
);
if
(
isSpecial
)
if
(
isSpecial
)
target
=
lookup
.
unreflectSpecial
(
rmethod
,
specialCaller
);
target
=
lookup
.
in
(
specialCaller
).
unreflectSpecial
(
rmethod
,
specialCaller
);
else
else
target
=
lookup
.
unreflect
(
rmethod
);
target
=
lookup
.
in
(
defc
).
unreflect
(
rmethod
);
}
catch
(
NoAccessException
ex
)
{
}
catch
(
NoAccessException
ex
)
{
noAccess
=
ex
;
noAccess
=
ex
;
}
}
...
@@ -737,7 +743,7 @@ public class MethodHandlesTest {
...
@@ -737,7 +743,7 @@ public class MethodHandlesTest {
}
}
Object
[]
argsMaybeWithSelf
=
randomArgs
(
paramsMaybeWithSelf
);
Object
[]
argsMaybeWithSelf
=
randomArgs
(
paramsMaybeWithSelf
);
printCalled
(
target
,
name
,
argsMaybeWithSelf
);
printCalled
(
target
,
name
,
argsMaybeWithSelf
);
target
.
invoke
Vararg
s
(
argsMaybeWithSelf
);
target
.
invoke
WithArgument
s
(
argsMaybeWithSelf
);
assertCalled
(
name
,
argsMaybeWithSelf
);
assertCalled
(
name
,
argsMaybeWithSelf
);
if
(
verbosity
>=
1
)
if
(
verbosity
>=
1
)
System
.
out
.
print
(
':'
);
System
.
out
.
print
(
':'
);
...
@@ -875,7 +881,7 @@ public class MethodHandlesTest {
...
@@ -875,7 +881,7 @@ public class MethodHandlesTest {
if
(
isStatic
)
expType
=
expType
.
dropParameterTypes
(
0
,
1
);
if
(
isStatic
)
expType
=
expType
.
dropParameterTypes
(
0
,
1
);
MethodHandle
mh
=
lookup
.
unreflectGetter
(
f
);
MethodHandle
mh
=
lookup
.
unreflectGetter
(
f
);
assertSame
(
mh
.
type
(),
expType
);
assertSame
(
mh
.
type
(),
expType
);
assert
Equals
(
mh
.
toString
()
,
fname
);
assert
NameStringContains
(
mh
,
fname
);
HasFields
fields
=
new
HasFields
();
HasFields
fields
=
new
HasFields
();
Object
sawValue
;
Object
sawValue
;
Class
<?>
rtype
=
type
;
Class
<?>
rtype
=
type
;
...
@@ -947,7 +953,7 @@ public class MethodHandlesTest {
...
@@ -947,7 +953,7 @@ public class MethodHandlesTest {
mh
=
lookup
.
findStaticSetter
(
fclass
,
fname
,
ftype
);
mh
=
lookup
.
findStaticSetter
(
fclass
,
fname
,
ftype
);
else
throw
new
InternalError
();
else
throw
new
InternalError
();
assertSame
(
mh
.
type
(),
expType
);
assertSame
(
mh
.
type
(),
expType
);
assert
Equals
(
mh
.
toString
()
,
fname
);
assert
NameStringContains
(
mh
,
fname
);
HasFields
fields
=
new
HasFields
();
HasFields
fields
=
new
HasFields
();
Object
sawValue
;
Object
sawValue
;
Class
<?>
vtype
=
type
;
Class
<?>
vtype
=
type
;
...
@@ -1102,6 +1108,18 @@ public class MethodHandlesTest {
...
@@ -1102,6 +1108,18 @@ public class MethodHandlesTest {
}
}
}
}
static
MethodHandle
typeHandler2
(
MethodHandle
target
,
MethodType
newType
)
{
MethodType
oldType
=
target
.
type
();
int
oldArity
=
oldType
.
parameterCount
();
int
newArity
=
newType
.
parameterCount
();
if
(
newArity
<
oldArity
)
return
MethodHandles
.
insertArguments
(
target
,
oldArity
,
"OPTIONAL"
);
else
if
(
newArity
>
oldArity
)
return
MethodHandles
.
dropArguments
(
target
,
oldArity
-
1
,
newType
.
parameterType
(
oldArity
-
1
));
else
return
target
;
// attempt no further conversions
}
@Test
@Test
public
void
testConvertArguments
()
throws
Throwable
{
public
void
testConvertArguments
()
throws
Throwable
{
if
(
CAN_SKIP_WORKING
)
return
;
if
(
CAN_SKIP_WORKING
)
return
;
...
@@ -1115,10 +1133,29 @@ public class MethodHandlesTest {
...
@@ -1115,10 +1133,29 @@ public class MethodHandlesTest {
}
}
void
testConvert
(
MethodHandle
id
,
Class
<?>
rtype
,
String
name
,
Class
<?>...
params
)
throws
Throwable
{
void
testConvert
(
MethodHandle
id
,
Class
<?>
rtype
,
String
name
,
Class
<?>...
params
)
throws
Throwable
{
testConvert
(
true
,
id
,
rtype
,
name
,
params
);
testConvert
(
true
,
false
,
id
,
rtype
,
name
,
params
);
testConvert
(
true
,
true
,
id
,
rtype
,
name
,
params
);
}
}
void
testConvert
(
boolean
positive
,
MethodHandle
id
,
Class
<?>
rtype
,
String
name
,
Class
<?>...
params
)
throws
Throwable
{
@Test
public
void
testTypeHandler
()
throws
Throwable
{
MethodHandle
id
=
Callee
.
ofType
(
1
);
MethodHandle
th2
=
PRIVATE
.
findStatic
(
MethodHandlesTest
.
class
,
"typeHandler2"
,
MethodType
.
methodType
(
MethodHandle
.
class
,
MethodHandle
.
class
,
MethodType
.
class
));
MethodHandle
id2
=
id
.
withTypeHandler
(
th2
);
testConvert
(
true
,
false
,
id2
,
null
,
"id"
,
Object
.
class
);
testConvert
(
true
,
true
,
id2
,
null
,
"id"
,
Object
.
class
);
if
(
true
)
return
;
//FIXME
testConvert
(
true
,
false
,
id2
,
null
,
"id"
,
String
.
class
);
// FIXME: throws WMT
testConvert
(
false
,
true
,
id2
,
null
,
"id"
,
String
.
class
);
// FIXME: should not succeed
testConvert
(
false
,
false
,
id2
,
null
,
"id"
,
Object
.
class
,
String
.
class
);
//FIXME: array[1] line 1164
testConvert
(
true
,
true
,
id2
,
null
,
"id"
,
Object
.
class
,
String
.
class
);
testConvert
(
false
,
false
,
id2
,
null
,
"id"
);
testConvert
(
true
,
true
,
id2
,
null
,
"id"
);
}
void
testConvert
(
boolean
positive
,
boolean
useAsType
,
MethodHandle
id
,
Class
<?>
rtype
,
String
name
,
Class
<?>...
params
)
throws
Throwable
{
countTest
(
positive
);
countTest
(
positive
);
MethodType
idType
=
id
.
type
();
MethodType
idType
=
id
.
type
();
if
(
rtype
==
null
)
rtype
=
idType
.
returnType
();
if
(
rtype
==
null
)
rtype
=
idType
.
returnType
();
...
@@ -1135,7 +1172,7 @@ public class MethodHandlesTest {
...
@@ -1135,7 +1172,7 @@ public class MethodHandlesTest {
if
(
src
!=
dst
)
if
(
src
!=
dst
)
convArgs
[
i
]
=
castToWrapper
(
convArgs
[
i
],
dst
);
convArgs
[
i
]
=
castToWrapper
(
convArgs
[
i
],
dst
);
}
}
Object
convResult
=
id
.
invoke
Vararg
s
(
convArgs
);
Object
convResult
=
id
.
invoke
WithArgument
s
(
convArgs
);
{
{
Class
<?>
dst
=
newType
.
returnType
();
Class
<?>
dst
=
newType
.
returnType
();
Class
<?>
src
=
idType
.
returnType
();
Class
<?>
src
=
idType
.
returnType
();
...
@@ -1145,7 +1182,10 @@ public class MethodHandlesTest {
...
@@ -1145,7 +1182,10 @@ public class MethodHandlesTest {
MethodHandle
target
=
null
;
MethodHandle
target
=
null
;
RuntimeException
error
=
null
;
RuntimeException
error
=
null
;
try
{
try
{
target
=
MethodHandles
.
convertArguments
(
id
,
newType
);
if
(
useAsType
)
target
=
MethodHandles
.
convertArguments
(
id
,
newType
);
else
target
=
id
.
asType
(
newType
);
}
catch
(
RuntimeException
ex
)
{
}
catch
(
RuntimeException
ex
)
{
error
=
ex
;
error
=
ex
;
}
}
...
@@ -1157,7 +1197,7 @@ public class MethodHandlesTest {
...
@@ -1157,7 +1197,7 @@ public class MethodHandlesTest {
if
(!
positive
)
return
;
// negative test failed as expected
if
(!
positive
)
return
;
// negative test failed as expected
assertEquals
(
newType
,
target
.
type
());
assertEquals
(
newType
,
target
.
type
());
printCalled
(
target
,
id
.
toString
(),
args
);
printCalled
(
target
,
id
.
toString
(),
args
);
Object
result
=
target
.
invoke
Vararg
s
(
args
);
Object
result
=
target
.
invoke
WithArgument
s
(
args
);
assertCalled
(
name
,
convArgs
);
assertCalled
(
name
,
convArgs
);
assertEquals
(
convResult
,
result
);
assertEquals
(
convResult
,
result
);
if
(
verbosity
>=
1
)
if
(
verbosity
>=
1
)
...
@@ -1279,7 +1319,7 @@ public class MethodHandlesTest {
...
@@ -1279,7 +1319,7 @@ public class MethodHandlesTest {
MethodType
outType
=
MethodType
.
methodType
(
Object
.
class
,
permTypes
);
MethodType
outType
=
MethodType
.
methodType
(
Object
.
class
,
permTypes
);
MethodHandle
target
=
MethodHandles
.
convertArguments
(
ValueConversions
.
varargsList
(
outargs
),
outType
);
MethodHandle
target
=
MethodHandles
.
convertArguments
(
ValueConversions
.
varargsList
(
outargs
),
outType
);
MethodHandle
newTarget
=
MethodHandles
.
permuteArguments
(
target
,
inType
,
reorder
);
MethodHandle
newTarget
=
MethodHandles
.
permuteArguments
(
target
,
inType
,
reorder
);
Object
result
=
newTarget
.
invoke
Vararg
s
(
args
);
Object
result
=
newTarget
.
invoke
WithArgument
s
(
args
);
Object
expected
=
Arrays
.
asList
(
permArgs
);
Object
expected
=
Arrays
.
asList
(
permArgs
);
assertEquals
(
expected
,
result
);
assertEquals
(
expected
,
result
);
}
}
...
@@ -1311,7 +1351,7 @@ public class MethodHandlesTest {
...
@@ -1311,7 +1351,7 @@ public class MethodHandlesTest {
Object
[]
args
=
randomArgs
(
target2
.
type
().
parameterArray
());
Object
[]
args
=
randomArgs
(
target2
.
type
().
parameterArray
());
// make sure the target does what we think it does:
// make sure the target does what we think it does:
if
(
pos
==
0
&&
nargs
<
5
)
{
if
(
pos
==
0
&&
nargs
<
5
)
{
Object
[]
check
=
(
Object
[])
target
.
invoke
Vararg
s
(
args
);
Object
[]
check
=
(
Object
[])
target
.
invoke
WithArgument
s
(
args
);
assertArrayEquals
(
args
,
check
);
assertArrayEquals
(
args
,
check
);
switch
(
nargs
)
{
switch
(
nargs
)
{
case
0
:
case
0
:
...
@@ -1342,7 +1382,7 @@ public class MethodHandlesTest {
...
@@ -1342,7 +1382,7 @@ public class MethodHandlesTest {
}
else
{
}
else
{
Object
[]
args1
=
Arrays
.
copyOfRange
(
args
,
0
,
pos
+
1
);
Object
[]
args1
=
Arrays
.
copyOfRange
(
args
,
0
,
pos
+
1
);
args1
[
pos
]
=
Arrays
.
copyOfRange
(
args
,
pos
,
args
.
length
);
args1
[
pos
]
=
Arrays
.
copyOfRange
(
args
,
pos
,
args
.
length
);
returnValue
=
(
Object
[])
result
.
invoke
Vararg
s
(
args1
);
returnValue
=
(
Object
[])
result
.
invoke
WithArgument
s
(
args1
);
}
}
assertArrayEquals
(
args
,
returnValue
);
assertArrayEquals
(
args
,
returnValue
);
}
}
...
@@ -1379,7 +1419,7 @@ public class MethodHandlesTest {
...
@@ -1379,7 +1419,7 @@ public class MethodHandlesTest {
if
(
verbosity
>=
3
)
if
(
verbosity
>=
3
)
System
.
out
.
println
(
"collect from "
+
Arrays
.
asList
(
args
)+
" ["
+
pos
+
".."
+
nargs
+
"]"
);
System
.
out
.
println
(
"collect from "
+
Arrays
.
asList
(
args
)+
" ["
+
pos
+
".."
+
nargs
+
"]"
);
MethodHandle
result
=
MethodHandles
.
collectArguments
(
target
,
newType
);
MethodHandle
result
=
MethodHandles
.
collectArguments
(
target
,
newType
);
Object
[]
returnValue
=
(
Object
[])
result
.
invoke
Vararg
s
(
args
);
Object
[]
returnValue
=
(
Object
[])
result
.
invoke
WithArgument
s
(
args
);
// assertTrue(returnValue.length == pos+1 && returnValue[pos] instanceof Object[]);
// assertTrue(returnValue.length == pos+1 && returnValue[pos] instanceof Object[]);
// returnValue[pos] = Arrays.asList((Object[]) returnValue[pos]);
// returnValue[pos] = Arrays.asList((Object[]) returnValue[pos]);
// collectedArgs[pos] = Arrays.asList((Object[]) collectedArgs[pos]);
// collectedArgs[pos] = Arrays.asList((Object[]) collectedArgs[pos]);
...
@@ -1412,7 +1452,7 @@ public class MethodHandlesTest {
...
@@ -1412,7 +1452,7 @@ public class MethodHandlesTest {
MethodHandle
target2
=
MethodHandles
.
insertArguments
(
target
,
pos
,
MethodHandle
target2
=
MethodHandles
.
insertArguments
(
target
,
pos
,
(
Object
[])
argsToInsert
.
toArray
());
(
Object
[])
argsToInsert
.
toArray
());
argsToInsert
.
clear
();
// remove from argsToInsert
argsToInsert
.
clear
();
// remove from argsToInsert
Object
res2
=
target2
.
invoke
Vararg
s
(
argsToPass
);
Object
res2
=
target2
.
invoke
WithArgument
s
(
argsToPass
);
Object
res2List
=
Arrays
.
asList
((
Object
[])
res2
);
Object
res2List
=
Arrays
.
asList
((
Object
[])
res2
);
if
(
verbosity
>=
3
)
if
(
verbosity
>=
3
)
System
.
out
.
println
(
"result: "
+
res2List
);
System
.
out
.
println
(
"result: "
+
res2List
);
...
@@ -1440,14 +1480,12 @@ public class MethodHandlesTest {
...
@@ -1440,14 +1480,12 @@ public class MethodHandlesTest {
Object
[]
argsToPass
=
randomArgs
(
nargs
,
Object
.
class
);
Object
[]
argsToPass
=
randomArgs
(
nargs
,
Object
.
class
);
if
(
verbosity
>=
3
)
if
(
verbosity
>=
3
)
System
.
out
.
println
(
"filter "
+
target
+
" at "
+
pos
+
" with "
+
filter
);
System
.
out
.
println
(
"filter "
+
target
+
" at "
+
pos
+
" with "
+
filter
);
MethodHandle
[]
filters
=
new
MethodHandle
[
pos
*
2
+
1
];
MethodHandle
target2
=
MethodHandles
.
filterArguments
(
target
,
pos
,
filter
);
filters
[
pos
]
=
filter
;
MethodHandle
target2
=
MethodHandles
.
filterArguments
(
target
,
filters
);
// Simulate expected effect of filter on arglist:
// Simulate expected effect of filter on arglist:
Object
[]
filteredArgs
=
argsToPass
.
clone
();
Object
[]
filteredArgs
=
argsToPass
.
clone
();
filteredArgs
[
pos
]
=
filter
.
invokeExact
(
filteredArgs
[
pos
]);
filteredArgs
[
pos
]
=
filter
.
invokeExact
(
filteredArgs
[
pos
]);
List
<
Object
>
expected
=
Arrays
.
asList
(
filteredArgs
);
List
<
Object
>
expected
=
Arrays
.
asList
(
filteredArgs
);
Object
result
=
target2
.
invoke
Vararg
s
(
argsToPass
);
Object
result
=
target2
.
invoke
WithArgument
s
(
argsToPass
);
if
(
verbosity
>=
3
)
if
(
verbosity
>=
3
)
System
.
out
.
println
(
"result: "
+
result
);
System
.
out
.
println
(
"result: "
+
result
);
if
(!
expected
.
equals
(
result
))
if
(!
expected
.
equals
(
result
))
...
@@ -1482,9 +1520,9 @@ public class MethodHandlesTest {
...
@@ -1482,9 +1520,9 @@ public class MethodHandlesTest {
List
<
Object
>
argsToFold
=
expected
.
subList
(
pos
,
pos
+
fold
);
List
<
Object
>
argsToFold
=
expected
.
subList
(
pos
,
pos
+
fold
);
if
(
verbosity
>=
3
)
if
(
verbosity
>=
3
)
System
.
out
.
println
(
"fold: "
+
argsToFold
+
" into "
+
target2
);
System
.
out
.
println
(
"fold: "
+
argsToFold
+
" into "
+
target2
);
Object
foldedArgs
=
combine
.
invoke
Vararg
s
(
argsToFold
);
Object
foldedArgs
=
combine
.
invoke
WithArgument
s
(
argsToFold
);
argsToFold
.
add
(
0
,
foldedArgs
);
argsToFold
.
add
(
0
,
foldedArgs
);
Object
result
=
target2
.
invoke
Vararg
s
(
argsToPass
);
Object
result
=
target2
.
invoke
WithArgument
s
(
argsToPass
);
if
(
verbosity
>=
3
)
if
(
verbosity
>=
3
)
System
.
out
.
println
(
"result: "
+
result
);
System
.
out
.
println
(
"result: "
+
result
);
if
(!
expected
.
equals
(
result
))
if
(!
expected
.
equals
(
result
))
...
@@ -1516,7 +1554,7 @@ public class MethodHandlesTest {
...
@@ -1516,7 +1554,7 @@ public class MethodHandlesTest {
for
(
int
i
=
drop
;
i
>
0
;
i
--)
{
for
(
int
i
=
drop
;
i
>
0
;
i
--)
{
argsToDrop
.
add
(
pos
,
"blort#"
+
i
);
argsToDrop
.
add
(
pos
,
"blort#"
+
i
);
}
}
Object
res2
=
target2
.
invoke
Vararg
s
(
argsToDrop
);
Object
res2
=
target2
.
invoke
WithArgument
s
(
argsToDrop
);
Object
res2List
=
Arrays
.
asList
((
Object
[])
res2
);
Object
res2List
=
Arrays
.
asList
((
Object
[])
res2
);
//if (!resList.equals(res2List))
//if (!resList.equals(res2List))
// System.out.println("*** fail at n/p/d = "+nargs+"/"+pos+"/"+drop+": "+argsToDrop+" => "+res2List);
// System.out.println("*** fail at n/p/d = "+nargs+"/"+pos+"/"+drop+": "+argsToDrop+" => "+res2List);
...
@@ -1572,7 +1610,7 @@ public class MethodHandlesTest {
...
@@ -1572,7 +1610,7 @@ public class MethodHandlesTest {
countTest
();
countTest
();
calledLog
.
clear
();
calledLog
.
clear
();
inv
=
MethodHandles
.
exactInvoker
(
type
);
inv
=
MethodHandles
.
exactInvoker
(
type
);
result
=
inv
.
invoke
Vararg
s
(
targetPlusArgs
);
result
=
inv
.
invoke
WithArgument
s
(
targetPlusArgs
);
if
(
testRetCode
)
assertEquals
(
code
,
result
);
if
(
testRetCode
)
assertEquals
(
code
,
result
);
assertCalled
(
"invokee"
,
args
);
assertCalled
(
"invokee"
,
args
);
// generic invoker
// generic invoker
...
@@ -1598,7 +1636,7 @@ public class MethodHandlesTest {
...
@@ -1598,7 +1636,7 @@ public class MethodHandlesTest {
assertCalled
(
"invokee"
,
args
);
assertCalled
(
"invokee"
,
args
);
}
}
calledLog
.
clear
();
calledLog
.
clear
();
result
=
inv
.
invoke
Vararg
s
(
targetPlusArgs
);
result
=
inv
.
invoke
WithArgument
s
(
targetPlusArgs
);
if
(
testRetCode
)
assertEquals
(
code
,
result
);
if
(
testRetCode
)
assertEquals
(
code
,
result
);
assertCalled
(
"invokee"
,
args
);
assertCalled
(
"invokee"
,
args
);
// varargs invoker #0
// varargs invoker #0
...
@@ -1640,17 +1678,29 @@ public class MethodHandlesTest {
...
@@ -1640,17 +1678,29 @@ public class MethodHandlesTest {
List
<
Object
>
tailList
=
targetPlusVarArgs
.
subList
(
1
+
k
,
1
+
nargs
);
List
<
Object
>
tailList
=
targetPlusVarArgs
.
subList
(
1
+
k
,
1
+
nargs
);
Object
[]
tail
=
tailList
.
toArray
();
Object
[]
tail
=
tailList
.
toArray
();
tailList
.
clear
();
tailList
.
add
(
tail
);
tailList
.
clear
();
tailList
.
add
(
tail
);
result
=
inv
.
invoke
Vararg
s
(
targetPlusVarArgs
);
result
=
inv
.
invoke
WithArgument
s
(
targetPlusVarArgs
);
if
(
testRetCode
)
assertEquals
(
code
,
result
);
if
(
testRetCode
)
assertEquals
(
code
,
result
);
assertCalled
(
"invokee"
,
args
);
assertCalled
(
"invokee"
,
args
);
}
}
// dynamic invoker
// dynamic invoker
countTest
();
countTest
();
CallSite
site
=
new
CallSite
(
MethodHandlesTest
.
class
,
"foo"
,
type
);
CallSite
site
=
new
CallSite
(
type
);
inv
=
MethodHandles
.
dynamicInvoker
(
site
);
inv
=
MethodHandles
.
dynamicInvoker
(
site
);
// see if we get the result of the original target:
try
{
result
=
inv
.
invokeWithArguments
(
args
);
assertTrue
(
"should not reach here"
,
false
);
}
catch
(
IllegalStateException
ex
)
{
String
msg
=
ex
.
getMessage
();
assertTrue
(
msg
,
msg
.
contains
(
"site"
));
}
// set new target after invoker is created, to make sure we track target
site
.
setTarget
(
target
);
site
.
setTarget
(
target
);
calledLog
.
clear
();
calledLog
.
clear
();
result
=
inv
.
invoke
Vararg
s
(
args
);
result
=
inv
.
invoke
WithArgument
s
(
args
);
if
(
testRetCode
)
assertEquals
(
code
,
result
);
if
(
testRetCode
)
assertEquals
(
code
,
result
);
assertCalled
(
"invokee"
,
args
);
assertCalled
(
"invokee"
,
args
);
}
}
...
@@ -1734,7 +1784,7 @@ public class MethodHandlesTest {
...
@@ -1734,7 +1784,7 @@ public class MethodHandlesTest {
String
willCall
=
(
equals
?
"targetIfEquals"
:
"fallbackIfNotEquals"
);
String
willCall
=
(
equals
?
"targetIfEquals"
:
"fallbackIfNotEquals"
);
if
(
verbosity
>=
3
)
if
(
verbosity
>=
3
)
System
.
out
.
println
(
logEntry
(
willCall
,
argList
));
System
.
out
.
println
(
logEntry
(
willCall
,
argList
));
Object
result
=
mh
.
invoke
Vararg
s
(
argList
);
Object
result
=
mh
.
invoke
WithArgument
s
(
argList
);
assertCalled
(
willCall
,
argList
);
assertCalled
(
willCall
,
argList
);
}
}
}
}
...
@@ -1776,7 +1826,7 @@ public class MethodHandlesTest {
...
@@ -1776,7 +1826,7 @@ public class MethodHandlesTest {
//System.out.println("catching with "+target+" : "+throwOrReturn);
//System.out.println("catching with "+target+" : "+throwOrReturn);
Object
[]
args
=
randomArgs
(
nargs
,
Object
.
class
);
Object
[]
args
=
randomArgs
(
nargs
,
Object
.
class
);
args
[
1
]
=
(
throwIt
?
thrown
:
null
);
args
[
1
]
=
(
throwIt
?
thrown
:
null
);
Object
returned
=
target
.
invoke
Vararg
s
(
args
);
Object
returned
=
target
.
invoke
WithArgument
s
(
args
);
//System.out.println("return from "+target+" : "+returned);
//System.out.println("return from "+target+" : "+returned);
if
(!
throwIt
)
{
if
(!
throwIt
)
{
assertSame
(
args
[
0
],
returned
);
assertSame
(
args
[
0
],
returned
);
...
@@ -1828,13 +1878,10 @@ public class MethodHandlesTest {
...
@@ -1828,13 +1878,10 @@ public class MethodHandlesTest {
testCastFailure
(
"unbox/return"
,
11000
);
testCastFailure
(
"unbox/return"
,
11000
);
}
}
static
class
Surprise
implements
MethodHandleProvider
{
static
class
Surprise
{
public
MethodHandle
asMethodHandle
()
{
public
MethodHandle
asMethodHandle
()
{
return
VALUE
.
bindTo
(
this
);
return
VALUE
.
bindTo
(
this
);
}
}
public
MethodHandle
asMethodHandle
(
MethodType
type
)
{
return
asMethodHandle
().
asType
(
type
);
}
Object
value
(
Object
x
)
{
Object
value
(
Object
x
)
{
trace
(
"value"
,
x
);
trace
(
"value"
,
x
);
if
(
boo
!=
null
)
return
boo
;
if
(
boo
!=
null
)
return
boo
;
...
@@ -1896,8 +1943,8 @@ public class MethodHandlesTest {
...
@@ -1896,8 +1943,8 @@ public class MethodHandlesTest {
}
}
if
(
callee
!=
null
)
{
if
(
callee
!=
null
)
{
callee
=
MethodHandles
.
convertArguments
(
callee
,
MethodType
.
genericMethodType
(
1
));
callee
=
MethodHandles
.
convertArguments
(
callee
,
MethodType
.
genericMethodType
(
1
));
surprise
=
MethodHandles
.
filterArguments
(
callee
,
surprise
);
surprise
=
MethodHandles
.
filterArguments
(
callee
,
0
,
surprise
);
identity
=
MethodHandles
.
filterArguments
(
callee
,
identity
);
identity
=
MethodHandles
.
filterArguments
(
callee
,
0
,
identity
);
}
}
}
}
assertNotSame
(
mode
,
surprise
,
surprise0
);
assertNotSame
(
mode
,
surprise
,
surprise0
);
...
@@ -1949,7 +1996,7 @@ public class MethodHandlesTest {
...
@@ -1949,7 +1996,7 @@ public class MethodHandlesTest {
assertEquals
(
mt
,
mh
.
type
());
assertEquals
(
mt
,
mh
.
type
());
assertEquals
(
Example
.
class
,
mh
.
type
().
returnType
());
assertEquals
(
Example
.
class
,
mh
.
type
().
returnType
());
args
=
randomArgs
(
mh
.
type
().
parameterArray
());
args
=
randomArgs
(
mh
.
type
().
parameterArray
());
mh
.
invoke
Vararg
s
(
args
);
mh
.
invoke
WithArgument
s
(
args
);
assertCalled
(
name
,
args
);
assertCalled
(
name
,
args
);
// Try a virtual method.
// Try a virtual method.
...
@@ -1959,7 +2006,7 @@ public class MethodHandlesTest {
...
@@ -1959,7 +2006,7 @@ public class MethodHandlesTest {
assertEquals
(
mt
,
mh
.
type
().
dropParameterTypes
(
0
,
1
));
assertEquals
(
mt
,
mh
.
type
().
dropParameterTypes
(
0
,
1
));
assertTrue
(
mh
.
type
().
parameterList
().
contains
(
Example
.
class
));
assertTrue
(
mh
.
type
().
parameterList
().
contains
(
Example
.
class
));
args
=
randomArgs
(
mh
.
type
().
parameterArray
());
args
=
randomArgs
(
mh
.
type
().
parameterArray
());
mh
.
invoke
Vararg
s
(
args
);
mh
.
invoke
WithArgument
s
(
args
);
assertCalled
(
name
,
args
);
assertCalled
(
name
,
args
);
}
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录