Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
237bbe7d
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看板
提交
237bbe7d
编写于
9月 10, 2014
作者:
V
vlivanov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
8037210: Get rid of char-based descriptions 'J' of basic types
Reviewed-by: jrose, psandoz, twisti
上级
6aadd150
变更
11
隐藏空白更改
内联
并排
Showing
11 changed file
with
827 addition
and
600 deletion
+827
-600
src/share/classes/java/lang/invoke/BoundMethodHandle.java
src/share/classes/java/lang/invoke/BoundMethodHandle.java
+206
-258
src/share/classes/java/lang/invoke/DirectMethodHandle.java
src/share/classes/java/lang/invoke/DirectMethodHandle.java
+4
-8
src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
...re/classes/java/lang/invoke/InvokerBytecodeGenerator.java
+122
-151
src/share/classes/java/lang/invoke/LambdaForm.java
src/share/classes/java/lang/invoke/LambdaForm.java
+353
-140
src/share/classes/java/lang/invoke/MethodHandle.java
src/share/classes/java/lang/invoke/MethodHandle.java
+5
-24
src/share/classes/java/lang/invoke/MethodHandleImpl.java
src/share/classes/java/lang/invoke/MethodHandleImpl.java
+1
-1
src/share/classes/java/lang/invoke/MethodHandleNatives.java
src/share/classes/java/lang/invoke/MethodHandleNatives.java
+36
-1
src/share/classes/java/lang/invoke/MethodHandleStatics.java
src/share/classes/java/lang/invoke/MethodHandleStatics.java
+13
-0
src/share/classes/java/lang/invoke/MethodHandles.java
src/share/classes/java/lang/invoke/MethodHandles.java
+7
-7
src/share/classes/java/lang/invoke/SimpleMethodHandle.java
src/share/classes/java/lang/invoke/SimpleMethodHandle.java
+2
-10
test/java/lang/invoke/LambdaFormTest.java
test/java/lang/invoke/LambdaFormTest.java
+78
-0
未找到文件。
src/share/classes/java/lang/invoke/BoundMethodHandle.java
浏览文件 @
237bbe7d
...
@@ -26,11 +26,10 @@
...
@@ -26,11 +26,10 @@
package
java.lang.invoke
;
package
java.lang.invoke
;
import
static
jdk
.
internal
.
org
.
objectweb
.
asm
.
Opcodes
.*;
import
static
jdk
.
internal
.
org
.
objectweb
.
asm
.
Opcodes
.*;
import
static
java
.
lang
.
invoke
.
LambdaForm
.
basicTypes
;
import
static
java
.
lang
.
invoke
.
LambdaForm
.
*
;
import
static
java
.
lang
.
invoke
.
MethodHandleNatives
.
Constants
.
REF_invokeStatic
;
import
static
java
.
lang
.
invoke
.
LambdaForm
.
BasicType
.*
;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
import
java.lang.invoke.LambdaForm.Name
;
import
java.lang.invoke.LambdaForm.NamedFunction
;
import
java.lang.invoke.LambdaForm.NamedFunction
;
import
java.lang.invoke.MethodHandles.Lookup
;
import
java.lang.invoke.MethodHandles.Lookup
;
import
java.lang.reflect.Field
;
import
java.lang.reflect.Field
;
...
@@ -61,22 +60,22 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -61,22 +60,22 @@ import jdk.internal.org.objectweb.asm.Type;
// BMH API and internals
// BMH API and internals
//
//
static
MethodHandle
bindSingle
(
MethodType
type
,
LambdaForm
form
,
char
xtype
,
Object
x
)
{
static
MethodHandle
bindSingle
(
MethodType
type
,
LambdaForm
form
,
BasicType
xtype
,
Object
x
)
{
// for some type signatures, there exist pre-defined concrete BMH classes
// for some type signatures, there exist pre-defined concrete BMH classes
try
{
try
{
switch
(
xtype
)
{
switch
(
xtype
)
{
case
'L'
:
case
L_TYPE
:
if
(
true
)
return
bindSingle
(
type
,
form
,
x
);
// Use known fast path.
if
(
true
)
return
bindSingle
(
type
,
form
,
x
);
// Use known fast path.
return
(
BoundMethodHandle
)
SpeciesData
.
EMPTY
.
extendWith
Type
(
'L'
).
constructor
[
0
].
invokeBasic
(
type
,
form
,
x
);
return
(
BoundMethodHandle
)
SpeciesData
.
EMPTY
.
extendWith
(
L_TYPE
).
constructor
[
0
].
invokeBasic
(
type
,
form
,
x
);
case
'I'
:
case
I_TYPE
:
return
(
BoundMethodHandle
)
SpeciesData
.
EMPTY
.
extendWith
Type
(
'I'
).
constructor
[
0
].
invokeBasic
(
type
,
form
,
ValueConversions
.
widenSubword
(
x
));
return
(
BoundMethodHandle
)
SpeciesData
.
EMPTY
.
extendWith
(
I_TYPE
).
constructor
[
0
].
invokeBasic
(
type
,
form
,
ValueConversions
.
widenSubword
(
x
));
case
'J'
:
case
J_TYPE
:
return
(
BoundMethodHandle
)
SpeciesData
.
EMPTY
.
extendWith
Type
(
'J'
).
constructor
[
0
].
invokeBasic
(
type
,
form
,
(
long
)
x
);
return
(
BoundMethodHandle
)
SpeciesData
.
EMPTY
.
extendWith
(
J_TYPE
).
constructor
[
0
].
invokeBasic
(
type
,
form
,
(
long
)
x
);
case
'F'
:
case
F_TYPE
:
return
(
BoundMethodHandle
)
SpeciesData
.
EMPTY
.
extendWith
Type
(
'F'
).
constructor
[
0
].
invokeBasic
(
type
,
form
,
(
float
)
x
);
return
(
BoundMethodHandle
)
SpeciesData
.
EMPTY
.
extendWith
(
F_TYPE
).
constructor
[
0
].
invokeBasic
(
type
,
form
,
(
float
)
x
);
case
'D'
:
case
D_TYPE
:
return
(
BoundMethodHandle
)
SpeciesData
.
EMPTY
.
extendWith
Type
(
'D'
).
constructor
[
0
].
invokeBasic
(
type
,
form
,
(
double
)
x
);
return
(
BoundMethodHandle
)
SpeciesData
.
EMPTY
.
extendWith
(
D_TYPE
).
constructor
[
0
].
invokeBasic
(
type
,
form
,
(
double
)
x
);
default
:
throw
new
InternalError
(
"unexpected xtype: "
+
xtype
);
default
:
throw
newInternalError
(
"unexpected xtype: "
+
xtype
);
}
}
}
catch
(
Throwable
t
)
{
}
catch
(
Throwable
t
)
{
throw
newInternalError
(
t
);
throw
newInternalError
(
t
);
...
@@ -87,23 +86,23 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -87,23 +86,23 @@ import jdk.internal.org.objectweb.asm.Type;
return
new
Species_L
(
type
,
form
,
x
);
return
new
Species_L
(
type
,
form
,
x
);
}
}
MethodHandle
cloneExtend
(
MethodType
type
,
LambdaForm
form
,
char
xtype
,
Object
x
)
{
MethodHandle
cloneExtend
(
MethodType
type
,
LambdaForm
form
,
BasicType
xtype
,
Object
x
)
{
try
{
try
{
switch
(
xtype
)
{
switch
(
xtype
)
{
case
'L'
:
return
clone
ExtendL
(
type
,
form
,
x
);
case
L_TYPE:
return
copyWith
ExtendL
(
type
,
form
,
x
);
case
'I'
:
return
clone
ExtendI
(
type
,
form
,
ValueConversions
.
widenSubword
(
x
));
case
I_TYPE:
return
copyWith
ExtendI
(
type
,
form
,
ValueConversions
.
widenSubword
(
x
));
case
'J'
:
return
clone
ExtendJ
(
type
,
form
,
(
long
)
x
);
case
J_TYPE:
return
copyWith
ExtendJ
(
type
,
form
,
(
long
)
x
);
case
'F'
:
return
clone
ExtendF
(
type
,
form
,
(
float
)
x
);
case
F_TYPE:
return
copyWith
ExtendF
(
type
,
form
,
(
float
)
x
);
case
'D'
:
return
clone
ExtendD
(
type
,
form
,
(
double
)
x
);
case
D_TYPE:
return
copyWith
ExtendD
(
type
,
form
,
(
double
)
x
);
}
}
}
catch
(
Throwable
t
)
{
}
catch
(
Throwable
t
)
{
throw
newInternalError
(
t
);
throw
newInternalError
(
t
);
}
}
throw
new
InternalError
(
"unexpected type: "
+
xtype
);
throw
newInternalError
(
"unexpected type: "
+
xtype
);
}
}
@Override
@Override
MethodHandle
bindArgument
(
int
pos
,
char
basicType
,
Object
value
)
{
MethodHandle
bindArgument
(
int
pos
,
BasicType
basicType
,
Object
value
)
{
MethodType
type
=
type
().
dropParameterTypes
(
pos
,
pos
+
1
);
MethodType
type
=
type
().
dropParameterTypes
(
pos
,
pos
+
1
);
LambdaForm
form
=
internalForm
().
bind
(
1
+
pos
,
speciesData
());
LambdaForm
form
=
internalForm
().
bind
(
1
+
pos
,
speciesData
());
return
cloneExtend
(
type
,
form
,
basicType
,
value
);
return
cloneExtend
(
type
,
form
,
basicType
,
value
);
...
@@ -111,9 +110,9 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -111,9 +110,9 @@ import jdk.internal.org.objectweb.asm.Type;
@Override
@Override
MethodHandle
dropArguments
(
MethodType
srcType
,
int
pos
,
int
drops
)
{
MethodHandle
dropArguments
(
MethodType
srcType
,
int
pos
,
int
drops
)
{
LambdaForm
form
=
internalForm
().
addArguments
(
pos
,
srcType
.
parameterList
().
subList
(
pos
,
pos
+
drops
));
LambdaForm
form
=
internalForm
().
addArguments
(
pos
,
srcType
.
parameterList
().
subList
(
pos
,
pos
+
drops
));
try
{
try
{
return
c
lone
(
srcType
,
form
);
return
c
opyWith
(
srcType
,
form
);
}
catch
(
Throwable
t
)
{
}
catch
(
Throwable
t
)
{
throw
newInternalError
(
t
);
throw
newInternalError
(
t
);
}
}
...
@@ -122,26 +121,23 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -122,26 +121,23 @@ import jdk.internal.org.objectweb.asm.Type;
@Override
@Override
MethodHandle
permuteArguments
(
MethodType
newType
,
int
[]
reorder
)
{
MethodHandle
permuteArguments
(
MethodType
newType
,
int
[]
reorder
)
{
try
{
try
{
return
c
lone
(
newType
,
form
.
permuteArguments
(
1
,
reorder
,
basicTypes
(
newType
.
parameterList
())));
return
c
opyWith
(
newType
,
form
.
permuteArguments
(
1
,
reorder
,
basicTypes
(
newType
.
parameterList
())));
}
catch
(
Throwable
t
)
{
}
catch
(
Throwable
t
)
{
throw
newInternalError
(
t
);
throw
newInternalError
(
t
);
}
}
}
}
static
final
String
EXTENSION_TYPES
=
"LIJFD"
;
static
final
byte
INDEX_L
=
0
,
INDEX_I
=
1
,
INDEX_J
=
2
,
INDEX_F
=
3
,
INDEX_D
=
4
;
static
byte
extensionIndex
(
char
type
)
{
int
i
=
EXTENSION_TYPES
.
indexOf
(
type
);
if
(
i
<
0
)
throw
new
InternalError
();
return
(
byte
)
i
;
}
/**
/**
* Return the {@link SpeciesData} instance representing this BMH species. All subclasses must provide a
* Return the {@link SpeciesData} instance representing this BMH species. All subclasses must provide a
* static field containing this value, and they must accordingly implement this method.
* static field containing this value, and they must accordingly implement this method.
*/
*/
/*non-public*/
abstract
SpeciesData
speciesData
();
/*non-public*/
abstract
SpeciesData
speciesData
();
/**
* Return the number of fields in this BMH. Equivalent to speciesData().fieldCount().
*/
/*non-public*/
abstract
int
fieldCount
();
@Override
@Override
final
Object
internalProperties
()
{
final
Object
internalProperties
()
{
return
"/BMH="
+
internalValues
();
return
"/BMH="
+
internalValues
();
...
@@ -159,38 +155,33 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -159,38 +155,33 @@ import jdk.internal.org.objectweb.asm.Type;
/*non-public*/
final
Object
arg
(
int
i
)
{
/*non-public*/
final
Object
arg
(
int
i
)
{
try
{
try
{
switch
(
speciesData
().
fieldType
(
i
))
{
switch
(
speciesData
().
fieldType
(
i
))
{
case
'L'
:
return
argL
(
i
);
case
L_TYPE:
return
speciesData
().
getters
[
i
].
invokeBasic
(
this
);
case
'I'
:
return
argI
(
i
);
case
I_TYPE:
return
(
int
)
speciesData
().
getters
[
i
].
invokeBasic
(
this
);
case
'F'
:
return
argF
(
i
);
case
J_TYPE:
return
(
long
)
speciesData
().
getters
[
i
].
invokeBasic
(
this
);
case
'D'
:
return
argD
(
i
);
case
F_TYPE:
return
(
float
)
speciesData
().
getters
[
i
].
invokeBasic
(
this
);
case
'J'
:
return
argJ
(
i
);
case
D_TYPE:
return
(
double
)
speciesData
().
getters
[
i
].
invokeBasic
(
this
);
}
}
}
catch
(
Throwable
ex
)
{
}
catch
(
Throwable
ex
)
{
throw
newInternalError
(
ex
);
throw
newInternalError
(
ex
);
}
}
throw
new
InternalError
(
"unexpected type: "
+
speciesData
().
types
+
"."
+
i
);
throw
new
InternalError
(
"unexpected type: "
+
speciesData
().
type
Char
s
+
"."
+
i
);
}
}
/*non-public*/
final
Object
argL
(
int
i
)
throws
Throwable
{
return
speciesData
().
getters
[
i
].
invokeBasic
(
this
);
}
/*non-public*/
final
int
argI
(
int
i
)
throws
Throwable
{
return
(
int
)
speciesData
().
getters
[
i
].
invokeBasic
(
this
);
}
/*non-public*/
final
float
argF
(
int
i
)
throws
Throwable
{
return
(
float
)
speciesData
().
getters
[
i
].
invokeBasic
(
this
);
}
/*non-public*/
final
double
argD
(
int
i
)
throws
Throwable
{
return
(
double
)
speciesData
().
getters
[
i
].
invokeBasic
(
this
);
}
/*non-public*/
final
long
argJ
(
int
i
)
throws
Throwable
{
return
(
long
)
speciesData
().
getters
[
i
].
invokeBasic
(
this
);
}
//
//
// cloning API
// cloning API
//
//
/*non-public*/
abstract
BoundMethodHandle
c
lone
(
MethodType
mt
,
LambdaForm
lf
)
throws
Throwable
;
/*non-public*/
abstract
BoundMethodHandle
c
opyWith
(
MethodType
mt
,
LambdaForm
lf
)
;
/*non-public*/
abstract
BoundMethodHandle
c
loneExtendL
(
MethodType
mt
,
LambdaForm
lf
,
Object
narg
)
throws
Throwable
;
/*non-public*/
abstract
BoundMethodHandle
c
opyWithExtendL
(
MethodType
mt
,
LambdaForm
lf
,
Object
narg
)
;
/*non-public*/
abstract
BoundMethodHandle
c
loneExtendI
(
MethodType
mt
,
LambdaForm
lf
,
int
narg
)
throws
Throwable
;
/*non-public*/
abstract
BoundMethodHandle
c
opyWithExtendI
(
MethodType
mt
,
LambdaForm
lf
,
int
narg
)
;
/*non-public*/
abstract
BoundMethodHandle
c
loneExtendJ
(
MethodType
mt
,
LambdaForm
lf
,
long
narg
)
throws
Throwable
;
/*non-public*/
abstract
BoundMethodHandle
c
opyWithExtendJ
(
MethodType
mt
,
LambdaForm
lf
,
long
narg
)
;
/*non-public*/
abstract
BoundMethodHandle
c
loneExtendF
(
MethodType
mt
,
LambdaForm
lf
,
float
narg
)
throws
Throwable
;
/*non-public*/
abstract
BoundMethodHandle
c
opyWithExtendF
(
MethodType
mt
,
LambdaForm
lf
,
float
narg
)
;
/*non-public*/
abstract
BoundMethodHandle
c
loneExtendD
(
MethodType
mt
,
LambdaForm
lf
,
double
narg
)
throws
Throwable
;
/*non-public*/
abstract
BoundMethodHandle
c
opyWithExtendD
(
MethodType
mt
,
LambdaForm
lf
,
double
narg
)
;
// The following is a grossly irregular hack:
// The following is a grossly irregular hack:
@Override
MethodHandle
reinvokerTarget
()
{
@Override
MethodHandle
reinvokerTarget
()
{
try
{
try
{
return
(
MethodHandle
)
arg
L
(
0
);
return
(
MethodHandle
)
arg
(
0
);
}
catch
(
Throwable
ex
)
{
}
catch
(
Throwable
ex
)
{
throw
newInternalError
(
ex
);
throw
newInternalError
(
ex
);
}
}
...
@@ -203,7 +194,7 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -203,7 +194,7 @@ import jdk.internal.org.objectweb.asm.Type;
private
// make it private to force users to access the enclosing class first
private
// make it private to force users to access the enclosing class first
static
final
class
Species_L
extends
BoundMethodHandle
{
static
final
class
Species_L
extends
BoundMethodHandle
{
final
Object
argL0
;
final
Object
argL0
;
/*non-public*/
Species_L
(
MethodType
mt
,
LambdaForm
lf
,
Object
argL0
)
{
private
Species_L
(
MethodType
mt
,
LambdaForm
lf
,
Object
argL0
)
{
super
(
mt
,
lf
);
super
(
mt
,
lf
);
this
.
argL0
=
argL0
;
this
.
argL0
=
argL0
;
}
}
...
@@ -213,140 +204,95 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -213,140 +204,95 @@ import jdk.internal.org.objectweb.asm.Type;
/*non-public*/
SpeciesData
speciesData
()
{
/*non-public*/
SpeciesData
speciesData
()
{
return
SPECIES_DATA
;
return
SPECIES_DATA
;
}
}
/*non-public*/
static
final
SpeciesData
SPECIES_DATA
=
SpeciesData
.
getForClass
(
"L"
,
Species_L
.
class
);
@Override
/*non-public*/
final
BoundMethodHandle
clone
(
MethodType
mt
,
LambdaForm
lf
)
throws
Throwable
{
return
new
Species_L
(
mt
,
lf
,
argL0
);
}
@Override
/*non-public*/
final
BoundMethodHandle
cloneExtendL
(
MethodType
mt
,
LambdaForm
lf
,
Object
narg
)
throws
Throwable
{
return
(
BoundMethodHandle
)
SPECIES_DATA
.
extendWithIndex
(
INDEX_L
).
constructor
[
0
].
invokeBasic
(
mt
,
lf
,
argL0
,
narg
);
}
@Override
@Override
/*non-public*/
final
BoundMethodHandle
cloneExtendI
(
MethodType
mt
,
LambdaForm
lf
,
int
narg
)
throws
Throwable
{
/*non-public*/
int
fieldCount
()
{
return
(
BoundMethodHandle
)
SPECIES_DATA
.
extendWithIndex
(
INDEX_I
).
constructor
[
0
].
invokeBasic
(
mt
,
lf
,
argL0
,
narg
);
return
1
;
}
@Override
/*non-public*/
final
BoundMethodHandle
cloneExtendJ
(
MethodType
mt
,
LambdaForm
lf
,
long
narg
)
throws
Throwable
{
return
(
BoundMethodHandle
)
SPECIES_DATA
.
extendWithIndex
(
INDEX_J
).
constructor
[
0
].
invokeBasic
(
mt
,
lf
,
argL0
,
narg
);
}
@Override
/*non-public*/
final
BoundMethodHandle
cloneExtendF
(
MethodType
mt
,
LambdaForm
lf
,
float
narg
)
throws
Throwable
{
return
(
BoundMethodHandle
)
SPECIES_DATA
.
extendWithIndex
(
INDEX_F
).
constructor
[
0
].
invokeBasic
(
mt
,
lf
,
argL0
,
narg
);
}
@Override
/*non-public*/
final
BoundMethodHandle
cloneExtendD
(
MethodType
mt
,
LambdaForm
lf
,
double
narg
)
throws
Throwable
{
return
(
BoundMethodHandle
)
SPECIES_DATA
.
extendWithIndex
(
INDEX_D
).
constructor
[
0
].
invokeBasic
(
mt
,
lf
,
argL0
,
narg
);
}
}
/*
static final class Species_LL extends BoundMethodHandle {
final Object argL0;
final Object argL1;
public Species_LL(MethodType mt, LambdaForm lf, Object argL0, Object argL1) {
super(mt, lf);
this.argL0 = argL0;
this.argL1 = argL1;
}
@Override
public SpeciesData speciesData() {
return SPECIES_DATA;
}
public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LL", Species_LL.class);
@Override
public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
return new Species_LL(mt, lf, argL0, argL1);
}
@Override
public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
}
@Override
public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
}
@Override
public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
}
@Override
public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
}
@Override
public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
}
}
static final class Species_JL extends BoundMethodHandle {
final long argJ0;
final Object argL1;
public Species_JL(MethodType mt, LambdaForm lf, long argJ0, Object argL1) {
super(mt, lf);
this.argJ0 = argJ0;
this.argL1 = argL1;
}
}
@Override
/*non-public*/
static
final
SpeciesData
SPECIES_DATA
=
SpeciesData
.
getForClass
(
"L"
,
Species_L
.
class
);
public SpeciesData speciesData(
) {
/*non-public*/
static
BoundMethodHandle
make
(
MethodType
mt
,
LambdaForm
lf
,
Object
argL0
)
{
return
SPECIES_DATA
;
return
new
Species_L
(
mt
,
lf
,
argL0
)
;
}
}
public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("JL", Species_JL.class);
@Override public final long argJ0() { return argJ0; }
@Override public final Object argL1() { return argL1; }
@Override
@Override
public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable
{
/*non-public*/
final
BoundMethodHandle
copyWith
(
MethodType
mt
,
LambdaForm
lf
)
{
return new Species_
JL(mt, lf, argJ0, argL1
);
return
new
Species_
L
(
mt
,
lf
,
argL0
);
}
}
@Override
@Override
public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
/*non-public*/
final
BoundMethodHandle
copyWithExtendL
(
MethodType
mt
,
LambdaForm
lf
,
Object
narg
)
{
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
try
{
return
(
BoundMethodHandle
)
SPECIES_DATA
.
extendWith
(
L_TYPE
).
constructor
[
0
].
invokeBasic
(
mt
,
lf
,
argL0
,
narg
);
}
catch
(
Throwable
ex
)
{
throw
uncaughtException
(
ex
);
}
}
}
@Override
@Override
public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
/*non-public*/
final
BoundMethodHandle
copyWithExtendI
(
MethodType
mt
,
LambdaForm
lf
,
int
narg
)
{
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
try
{
return
(
BoundMethodHandle
)
SPECIES_DATA
.
extendWith
(
I_TYPE
).
constructor
[
0
].
invokeBasic
(
mt
,
lf
,
argL0
,
narg
);
}
catch
(
Throwable
ex
)
{
throw
uncaughtException
(
ex
);
}
}
}
@Override
@Override
public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
/*non-public*/
final
BoundMethodHandle
copyWithExtendJ
(
MethodType
mt
,
LambdaForm
lf
,
long
narg
)
{
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
try
{
return
(
BoundMethodHandle
)
SPECIES_DATA
.
extendWith
(
J_TYPE
).
constructor
[
0
].
invokeBasic
(
mt
,
lf
,
argL0
,
narg
);
}
catch
(
Throwable
ex
)
{
throw
uncaughtException
(
ex
);
}
}
}
@Override
@Override
public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
/*non-public*/
final
BoundMethodHandle
copyWithExtendF
(
MethodType
mt
,
LambdaForm
lf
,
float
narg
)
{
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
try
{
return
(
BoundMethodHandle
)
SPECIES_DATA
.
extendWith
(
F_TYPE
).
constructor
[
0
].
invokeBasic
(
mt
,
lf
,
argL0
,
narg
);
}
catch
(
Throwable
ex
)
{
throw
uncaughtException
(
ex
);
}
}
}
@Override
@Override
public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
/*non-public*/
final
BoundMethodHandle
copyWithExtendD
(
MethodType
mt
,
LambdaForm
lf
,
double
narg
)
{
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
try
{
return
(
BoundMethodHandle
)
SPECIES_DATA
.
extendWith
(
D_TYPE
).
constructor
[
0
].
invokeBasic
(
mt
,
lf
,
argL0
,
narg
);
}
catch
(
Throwable
ex
)
{
throw
uncaughtException
(
ex
);
}
}
}
}
}
*/
//
//
// BMH species meta-data
// BMH species meta-data
//
//
/**
/**
* Meta-data wrapper for concrete BMH classes.
* Meta-data wrapper for concrete BMH types.
* Each BMH type corresponds to a given sequence of basic field types (LIJFD).
* The fields are immutable; their values are fully specified at object construction.
* Each BMH type supplies an array of getter functions which may be used in lambda forms.
* A BMH is constructed by cloning a shorter BMH and adding one or more new field values.
* As a degenerate and common case, the "shorter BMH" can be missing, and contributes zero prior fields.
*/
*/
static
class
SpeciesData
{
static
class
SpeciesData
{
final
String
types
;
final
String
typeChars
;
final
BasicType
[]
typeCodes
;
final
Class
<?
extends
BoundMethodHandle
>
clazz
;
final
Class
<?
extends
BoundMethodHandle
>
clazz
;
// Bootstrapping requires circular relations MH -> BMH -> SpeciesData -> MH
// Bootstrapping requires circular relations MH -> BMH -> SpeciesData -> MH
// Therefore, we need a non-final link in the chain. Use array elements.
// Therefore, we need a non-final link in the chain. Use array elements.
final
MethodHandle
[]
constructor
;
final
MethodHandle
[]
constructor
;
final
MethodHandle
[]
getters
;
final
MethodHandle
[]
getters
;
final
NamedFunction
[]
nominalGetters
;
final
SpeciesData
[]
extensions
;
final
SpeciesData
[]
extensions
;
/*non-public*/
int
fieldCount
()
{
/*non-public*/
int
fieldCount
()
{
return
types
.
length
();
return
typeCodes
.
length
;
}
/*non-public*/
BasicType
fieldType
(
int
i
)
{
return
typeCodes
[
i
];
}
}
/*non-public*/
char
fieldType
(
int
i
)
{
/*non-public*/
char
fieldType
Char
(
int
i
)
{
return
types
.
charAt
(
i
);
return
type
Char
s
.
charAt
(
i
);
}
}
public
String
toString
()
{
public
String
toString
()
{
return
"SpeciesData["
+(
isPlaceholder
()
?
"<placeholder>"
:
clazz
.
getSimpleName
())+
":"
+
types
+
"]"
;
return
"SpeciesData["
+(
isPlaceholder
()
?
"<placeholder>"
:
clazz
.
getSimpleName
())+
":"
+
type
Char
s
+
"]"
;
}
}
/**
/**
...
@@ -354,45 +300,46 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -354,45 +300,46 @@ import jdk.internal.org.objectweb.asm.Type;
* represents a MH bound to a generic invoker, which in turn forwards to the corresponding
* represents a MH bound to a generic invoker, which in turn forwards to the corresponding
* getter.
* getter.
*/
*/
Name
getterName
(
Name
mhName
,
int
i
)
{
MethodHandle
mh
=
getters
[
i
];
assert
(
mh
!=
null
)
:
this
+
"."
+
i
;
return
new
Name
(
mh
,
mhName
);
}
NamedFunction
getterFunction
(
int
i
)
{
NamedFunction
getterFunction
(
int
i
)
{
return
n
ew
NamedFunction
(
getters
[
i
])
;
return
n
ominalGetters
[
i
]
;
}
}
static
final
SpeciesData
EMPTY
=
new
SpeciesData
(
""
,
BoundMethodHandle
.
class
);
static
final
SpeciesData
EMPTY
=
new
SpeciesData
(
""
,
BoundMethodHandle
.
class
);
private
SpeciesData
(
String
types
,
Class
<?
extends
BoundMethodHandle
>
clazz
)
{
private
SpeciesData
(
String
types
,
Class
<?
extends
BoundMethodHandle
>
clazz
)
{
this
.
types
=
types
;
this
.
typeChars
=
types
;
this
.
typeCodes
=
basicTypes
(
types
);
this
.
clazz
=
clazz
;
this
.
clazz
=
clazz
;
if
(!
INIT_DONE
)
{
if
(!
INIT_DONE
)
{
this
.
constructor
=
new
MethodHandle
[
1
];
this
.
constructor
=
new
MethodHandle
[
1
];
// only one ctor
this
.
getters
=
new
MethodHandle
[
types
.
length
()];
this
.
getters
=
new
MethodHandle
[
types
.
length
()];
this
.
nominalGetters
=
new
NamedFunction
[
types
.
length
()];
}
else
{
}
else
{
this
.
constructor
=
Factory
.
makeCtors
(
clazz
,
types
,
null
);
this
.
constructor
=
Factory
.
makeCtors
(
clazz
,
types
,
null
);
this
.
getters
=
Factory
.
makeGetters
(
clazz
,
types
,
null
);
this
.
getters
=
Factory
.
makeGetters
(
clazz
,
types
,
null
);
this
.
nominalGetters
=
Factory
.
makeNominalGetters
(
types
,
null
,
this
.
getters
);
}
}
this
.
extensions
=
new
SpeciesData
[
EXTENSION_TYPES
.
length
()
];
this
.
extensions
=
new
SpeciesData
[
ARG_TYPE_LIMIT
];
}
}
private
void
initForBootstrap
()
{
private
void
initForBootstrap
()
{
assert
(!
INIT_DONE
);
assert
(!
INIT_DONE
);
if
(
constructor
[
0
]
==
null
)
{
if
(
constructor
[
0
]
==
null
)
{
String
types
=
typeChars
;
Factory
.
makeCtors
(
clazz
,
types
,
this
.
constructor
);
Factory
.
makeCtors
(
clazz
,
types
,
this
.
constructor
);
Factory
.
makeGetters
(
clazz
,
types
,
this
.
getters
);
Factory
.
makeGetters
(
clazz
,
types
,
this
.
getters
);
Factory
.
makeNominalGetters
(
types
,
this
.
nominalGetters
,
this
.
getters
);
}
}
}
}
private
SpeciesData
(
String
types
)
{
private
SpeciesData
(
String
type
Char
s
)
{
// Placeholder only.
// Placeholder only.
this
.
types
=
types
;
this
.
typeChars
=
typeChars
;
this
.
typeCodes
=
basicTypes
(
typeChars
);
this
.
clazz
=
null
;
this
.
clazz
=
null
;
this
.
constructor
=
null
;
this
.
constructor
=
null
;
this
.
getters
=
null
;
this
.
getters
=
null
;
this
.
nominalGetters
=
null
;
this
.
extensions
=
null
;
this
.
extensions
=
null
;
}
}
private
boolean
isPlaceholder
()
{
return
clazz
==
null
;
}
private
boolean
isPlaceholder
()
{
return
clazz
==
null
;
}
...
@@ -401,18 +348,15 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -401,18 +348,15 @@ import jdk.internal.org.objectweb.asm.Type;
static
{
CACHE
.
put
(
""
,
EMPTY
);
}
// make bootstrap predictable
static
{
CACHE
.
put
(
""
,
EMPTY
);
}
// make bootstrap predictable
private
static
final
boolean
INIT_DONE
;
// set after <clinit> finishes...
private
static
final
boolean
INIT_DONE
;
// set after <clinit> finishes...
SpeciesData
extendWithType
(
char
type
)
{
SpeciesData
extendWith
(
byte
type
)
{
int
i
=
extensionIndex
(
type
);
return
extendWith
(
BasicType
.
basicType
(
type
));
SpeciesData
d
=
extensions
[
i
];
if
(
d
!=
null
)
return
d
;
extensions
[
i
]
=
d
=
get
(
types
+
type
);
return
d
;
}
}
SpeciesData
extendWithIndex
(
byte
index
)
{
SpeciesData
extendWith
(
BasicType
type
)
{
SpeciesData
d
=
extensions
[
index
];
int
ord
=
type
.
ordinal
();
SpeciesData
d
=
extensions
[
ord
];
if
(
d
!=
null
)
return
d
;
if
(
d
!=
null
)
return
d
;
extensions
[
index
]
=
d
=
get
(
types
+
EXTENSION_TYPES
.
charAt
(
index
));
extensions
[
ord
]
=
d
=
get
(
typeChars
+
type
.
basicTypeChar
(
));
return
d
;
return
d
;
}
}
...
@@ -456,8 +400,6 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -456,8 +400,6 @@ import jdk.internal.org.objectweb.asm.Type;
static
{
static
{
// pre-fill the BMH speciesdata cache with BMH's inner classes
// pre-fill the BMH speciesdata cache with BMH's inner classes
final
Class
<
BoundMethodHandle
>
rootCls
=
BoundMethodHandle
.
class
;
final
Class
<
BoundMethodHandle
>
rootCls
=
BoundMethodHandle
.
class
;
SpeciesData
d0
=
BoundMethodHandle
.
SPECIES_DATA
;
// trigger class init
assert
(
d0
==
null
||
d0
==
lookupCache
(
""
))
:
d0
;
try
{
try
{
for
(
Class
<?>
c
:
rootCls
.
getDeclaredClasses
())
{
for
(
Class
<?>
c
:
rootCls
.
getDeclaredClasses
())
{
if
(
rootCls
.
isAssignableFrom
(
c
))
{
if
(
rootCls
.
isAssignableFrom
(
c
))
{
...
@@ -465,7 +407,7 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -465,7 +407,7 @@ import jdk.internal.org.objectweb.asm.Type;
SpeciesData
d
=
Factory
.
speciesDataFromConcreteBMHClass
(
cbmh
);
SpeciesData
d
=
Factory
.
speciesDataFromConcreteBMHClass
(
cbmh
);
assert
(
d
!=
null
)
:
cbmh
.
getName
();
assert
(
d
!=
null
)
:
cbmh
.
getName
();
assert
(
d
.
clazz
==
cbmh
);
assert
(
d
.
clazz
==
cbmh
);
assert
(
d
==
lookupCache
(
d
.
types
));
assert
(
d
==
lookupCache
(
d
.
type
Char
s
));
}
}
}
}
}
catch
(
Throwable
e
)
{
}
catch
(
Throwable
e
)
{
...
@@ -516,11 +458,10 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -516,11 +458,10 @@ import jdk.internal.org.objectweb.asm.Type;
static
final
String
BMHSPECIES_DATA_GFC_SIG
=
"("
+
JLS_SIG
+
JLC_SIG
+
")"
+
SPECIES_DATA_SIG
;
static
final
String
BMHSPECIES_DATA_GFC_SIG
=
"("
+
JLS_SIG
+
JLC_SIG
+
")"
+
SPECIES_DATA_SIG
;
static
final
String
MYSPECIES_DATA_SIG
=
"()"
+
SPECIES_DATA_SIG
;
static
final
String
MYSPECIES_DATA_SIG
=
"()"
+
SPECIES_DATA_SIG
;
static
final
String
VOID_SIG
=
"()V"
;
static
final
String
VOID_SIG
=
"()V"
;
static
final
String
INT_SIG
=
"()I"
;
static
final
String
SIG_INCIPIT
=
"(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;"
;
static
final
String
SIG_INCIPIT
=
"(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;"
;
static
final
Class
<?>[]
TYPES
=
new
Class
<?>[]
{
Object
.
class
,
int
.
class
,
long
.
class
,
float
.
class
,
double
.
class
};
static
final
String
[]
E_THROWABLE
=
new
String
[]
{
"java/lang/Throwable"
};
static
final
String
[]
E_THROWABLE
=
new
String
[]
{
"java/lang/Throwable"
};
/**
/**
...
@@ -551,31 +492,35 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -551,31 +492,35 @@ import jdk.internal.org.objectweb.asm.Type;
* final Object argL0;
* final Object argL0;
* final Object argL1;
* final Object argL1;
* final int argI2;
* final int argI2;
* Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
*
private
Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
* super(mt, lf);
* super(mt, lf);
* this.argL0 = argL0;
* this.argL0 = argL0;
* this.argL1 = argL1;
* this.argL1 = argL1;
* this.argI2 = argI2;
* this.argI2 = argI2;
* }
* }
* final SpeciesData speciesData() { return SPECIES_DATA; }
* final SpeciesData speciesData() { return SPECIES_DATA; }
* final int fieldCount() { return 3; }
* static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LLI", Species_LLI.class);
* static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LLI", Species_LLI.class);
* final BoundMethodHandle clone(MethodType mt, LambdaForm lf) {
* static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
* return SPECIES_DATA.constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2);
* return new Species_LLI(mt, lf, argL0, argL1, argI2);
* }
* final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
* return new Species_LLI(mt, lf, argL0, argL1, argI2);
* }
* }
* final BoundMethodHandle c
lone
ExtendL(MethodType mt, LambdaForm lf, Object narg) {
* final BoundMethodHandle c
opyWith
ExtendL(MethodType mt, LambdaForm lf, Object narg) {
* return SPECIES_DATA.extendWith
Index(INDEX_L
).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* return SPECIES_DATA.extendWith
(L_TYPE
).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* }
* }
* final BoundMethodHandle c
lone
ExtendI(MethodType mt, LambdaForm lf, int narg) {
* final BoundMethodHandle c
opyWith
ExtendI(MethodType mt, LambdaForm lf, int narg) {
* return SPECIES_DATA.extendWith
Index(INDEX_I
).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* return SPECIES_DATA.extendWith
(I_TYPE
).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* }
* }
* final BoundMethodHandle c
lone
ExtendJ(MethodType mt, LambdaForm lf, long narg) {
* final BoundMethodHandle c
opyWith
ExtendJ(MethodType mt, LambdaForm lf, long narg) {
* return SPECIES_DATA.extendWith
Index(INDEX_J
).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* return SPECIES_DATA.extendWith
(J_TYPE
).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* }
* }
* final BoundMethodHandle c
lone
ExtendF(MethodType mt, LambdaForm lf, float narg) {
* final BoundMethodHandle c
opyWith
ExtendF(MethodType mt, LambdaForm lf, float narg) {
* return SPECIES_DATA.extendWith
Index(INDEX_F
).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* return SPECIES_DATA.extendWith
(F_TYPE
).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* }
* }
*
final BoundMethodHandle clone
ExtendD(MethodType mt, LambdaForm lf, double narg) {
*
public final BoundMethodHandle copyWith
ExtendD(MethodType mt, LambdaForm lf, double narg) {
* return SPECIES_DATA.extendWith
Index(INDEX_D
).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* return SPECIES_DATA.extendWith
(D_TYPE
).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* }
* }
* }
* }
* </pre>
* </pre>
...
@@ -586,8 +531,9 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -586,8 +531,9 @@ import jdk.internal.org.objectweb.asm.Type;
static
Class
<?
extends
BoundMethodHandle
>
generateConcreteBMHClass
(
String
types
)
{
static
Class
<?
extends
BoundMethodHandle
>
generateConcreteBMHClass
(
String
types
)
{
final
ClassWriter
cw
=
new
ClassWriter
(
ClassWriter
.
COMPUTE_MAXS
+
ClassWriter
.
COMPUTE_FRAMES
);
final
ClassWriter
cw
=
new
ClassWriter
(
ClassWriter
.
COMPUTE_MAXS
+
ClassWriter
.
COMPUTE_FRAMES
);
final
String
className
=
SPECIES_PREFIX_PATH
+
types
;
String
shortTypes
=
LambdaForm
.
shortenSignature
(
types
);
final
String
sourceFile
=
SPECIES_PREFIX_NAME
+
types
;
final
String
className
=
SPECIES_PREFIX_PATH
+
shortTypes
;
final
String
sourceFile
=
SPECIES_PREFIX_NAME
+
shortTypes
;
final
int
NOT_ACC_PUBLIC
=
0
;
// not ACC_PUBLIC
final
int
NOT_ACC_PUBLIC
=
0
;
// not ACC_PUBLIC
cw
.
visit
(
V1_6
,
NOT_ACC_PUBLIC
+
ACC_FINAL
+
ACC_SUPER
,
className
,
null
,
BMH
,
null
);
cw
.
visit
(
V1_6
,
NOT_ACC_PUBLIC
+
ACC_FINAL
+
ACC_SUPER
,
className
,
null
,
BMH
,
null
);
cw
.
visitSource
(
sourceFile
,
null
);
cw
.
visitSource
(
sourceFile
,
null
);
...
@@ -606,11 +552,11 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -606,11 +552,11 @@ import jdk.internal.org.objectweb.asm.Type;
MethodVisitor
mv
;
MethodVisitor
mv
;
// emit constructor
// emit constructor
mv
=
cw
.
visitMethod
(
NOT_ACC_PUBLIC
,
"<init>"
,
makeSignature
(
types
,
true
),
null
,
null
);
mv
=
cw
.
visitMethod
(
ACC_PRIVATE
,
"<init>"
,
makeSignature
(
types
,
true
),
null
,
null
);
mv
.
visitCode
();
mv
.
visitCode
();
mv
.
visitVarInsn
(
ALOAD
,
0
);
mv
.
visitVarInsn
(
ALOAD
,
0
);
// this
mv
.
visitVarInsn
(
ALOAD
,
1
);
mv
.
visitVarInsn
(
ALOAD
,
1
);
// type
mv
.
visitVarInsn
(
ALOAD
,
2
);
mv
.
visitVarInsn
(
ALOAD
,
2
);
// form
mv
.
visitMethodInsn
(
INVOKESPECIAL
,
BMH
,
"<init>"
,
makeSignature
(
""
,
true
),
false
);
mv
.
visitMethodInsn
(
INVOKESPECIAL
,
BMH
,
"<init>"
,
makeSignature
(
""
,
true
),
false
);
...
@@ -647,39 +593,73 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -647,39 +593,73 @@ import jdk.internal.org.objectweb.asm.Type;
mv
.
visitMaxs
(
0
,
0
);
mv
.
visitMaxs
(
0
,
0
);
mv
.
visitEnd
();
mv
.
visitEnd
();
// emit
clone
()
// emit
implementation of fieldCount
()
mv
=
cw
.
visitMethod
(
NOT_ACC_PUBLIC
+
ACC_FINAL
,
"
clone"
,
makeSignature
(
""
,
false
),
null
,
E_THROWABLE
);
mv
=
cw
.
visitMethod
(
NOT_ACC_PUBLIC
+
ACC_FINAL
,
"
fieldCount"
,
INT_SIG
,
null
,
null
);
mv
.
visitCode
();
mv
.
visitCode
();
// return speciesData().constructor[0].invokeBasic(mt, lf, argL0, ...)
int
fc
=
types
.
length
();
// obtain constructor
if
(
fc
<=
(
ICONST_5
-
ICONST_0
))
{
mv
.
visitVarInsn
(
ALOAD
,
0
);
mv
.
visitInsn
(
ICONST_0
+
fc
);
mv
.
visitFieldInsn
(
GETSTATIC
,
className
,
"SPECIES_DATA"
,
SPECIES_DATA_SIG
);
}
else
{
mv
.
visitFieldInsn
(
GETFIELD
,
SPECIES_DATA
,
"constructor"
,
"["
+
MH_SIG
);
mv
.
visitIntInsn
(
SIPUSH
,
fc
);
mv
.
visitInsn
(
ICONST_0
);
}
mv
.
visitInsn
(
AALOAD
);
mv
.
visitInsn
(
IRETURN
);
mv
.
visitMaxs
(
0
,
0
);
mv
.
visitEnd
();
// emit make() ...factory method wrapping constructor
mv
=
cw
.
visitMethod
(
NOT_ACC_PUBLIC
+
ACC_STATIC
,
"make"
,
makeSignature
(
types
,
false
),
null
,
null
);
mv
.
visitCode
();
// make instance
mv
.
visitTypeInsn
(
NEW
,
className
);
mv
.
visitInsn
(
DUP
);
// load mt, lf
mv
.
visitVarInsn
(
ALOAD
,
0
);
// type
mv
.
visitVarInsn
(
ALOAD
,
1
);
// form
// load factory method arguments
for
(
int
i
=
0
,
j
=
0
;
i
<
types
.
length
();
++
i
,
++
j
)
{
// i counts the arguments, j counts corresponding argument slots
char
t
=
types
.
charAt
(
i
);
mv
.
visitVarInsn
(
typeLoadOp
(
t
),
j
+
2
);
// parameters start at 3
if
(
t
==
'J'
||
t
==
'D'
)
{
++
j
;
// adjust argument register access
}
}
// finally, invoke the constructor and return
mv
.
visitMethodInsn
(
INVOKESPECIAL
,
className
,
"<init>"
,
makeSignature
(
types
,
true
),
false
);
mv
.
visitInsn
(
ARETURN
);
mv
.
visitMaxs
(
0
,
0
);
mv
.
visitEnd
();
// emit copyWith()
mv
=
cw
.
visitMethod
(
NOT_ACC_PUBLIC
+
ACC_FINAL
,
"copyWith"
,
makeSignature
(
""
,
false
),
null
,
null
);
mv
.
visitCode
();
// make instance
mv
.
visitTypeInsn
(
NEW
,
className
);
mv
.
visitInsn
(
DUP
);
// load mt, lf
// load mt, lf
mv
.
visitVarInsn
(
ALOAD
,
1
);
mv
.
visitVarInsn
(
ALOAD
,
1
);
mv
.
visitVarInsn
(
ALOAD
,
2
);
mv
.
visitVarInsn
(
ALOAD
,
2
);
// put fields on the stack
// put fields on the stack
emitPushFields
(
types
,
className
,
mv
);
emitPushFields
(
types
,
className
,
mv
);
// finally, invoke the constructor and return
// finally, invoke the constructor and return
mv
.
visitMethodInsn
(
INVOKE
VIRTUAL
,
MH
,
"invokeBasic"
,
makeSignature
(
types
,
fals
e
),
false
);
mv
.
visitMethodInsn
(
INVOKE
SPECIAL
,
className
,
"<init>"
,
makeSignature
(
types
,
tru
e
),
false
);
mv
.
visitInsn
(
ARETURN
);
mv
.
visitInsn
(
ARETURN
);
mv
.
visitMaxs
(
0
,
0
);
mv
.
visitMaxs
(
0
,
0
);
mv
.
visitEnd
();
mv
.
visitEnd
();
// for each type, emit cloneExtendT()
// for each type, emit copyWithExtendT()
for
(
Class
<?>
c
:
TYPES
)
{
for
(
BasicType
type
:
BasicType
.
ARG_TYPES
)
{
char
t
=
Wrapper
.
basicTypeChar
(
c
);
int
ord
=
type
.
ordinal
();
mv
=
cw
.
visitMethod
(
NOT_ACC_PUBLIC
+
ACC_FINAL
,
"cloneExtend"
+
t
,
makeSignature
(
String
.
valueOf
(
t
),
false
),
null
,
E_THROWABLE
);
char
btChar
=
type
.
basicTypeChar
();
mv
=
cw
.
visitMethod
(
NOT_ACC_PUBLIC
+
ACC_FINAL
,
"copyWithExtend"
+
btChar
,
makeSignature
(
String
.
valueOf
(
btChar
),
false
),
null
,
E_THROWABLE
);
mv
.
visitCode
();
mv
.
visitCode
();
// return SPECIES_DATA.extendWith
Index(extensionIndex(t)
).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
// return SPECIES_DATA.extendWith
(t
).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
// obtain constructor
// obtain constructor
mv
.
visitFieldInsn
(
GETSTATIC
,
className
,
"SPECIES_DATA"
,
SPECIES_DATA_SIG
);
mv
.
visitFieldInsn
(
GETSTATIC
,
className
,
"SPECIES_DATA"
,
SPECIES_DATA_SIG
);
int
iconstInsn
=
ICONST_0
+
extensionIndex
(
t
)
;
int
iconstInsn
=
ICONST_0
+
ord
;
assert
(
iconstInsn
<=
ICONST_5
);
assert
(
iconstInsn
<=
ICONST_5
);
mv
.
visitInsn
(
iconstInsn
);
mv
.
visitInsn
(
iconstInsn
);
mv
.
visitMethodInsn
(
INVOKEVIRTUAL
,
SPECIES_DATA
,
"extendWith
Index
"
,
BMHSPECIES_DATA_EWI_SIG
,
false
);
mv
.
visitMethodInsn
(
INVOKEVIRTUAL
,
SPECIES_DATA
,
"extendWith"
,
BMHSPECIES_DATA_EWI_SIG
,
false
);
mv
.
visitFieldInsn
(
GETFIELD
,
SPECIES_DATA
,
"constructor"
,
"["
+
MH_SIG
);
mv
.
visitFieldInsn
(
GETFIELD
,
SPECIES_DATA
,
"constructor"
,
"["
+
MH_SIG
);
mv
.
visitInsn
(
ICONST_0
);
mv
.
visitInsn
(
ICONST_0
);
mv
.
visitInsn
(
AALOAD
);
mv
.
visitInsn
(
AALOAD
);
...
@@ -689,9 +669,9 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -689,9 +669,9 @@ import jdk.internal.org.objectweb.asm.Type;
// put fields on the stack
// put fields on the stack
emitPushFields
(
types
,
className
,
mv
);
emitPushFields
(
types
,
className
,
mv
);
// put narg on stack
// put narg on stack
mv
.
visitVarInsn
(
typeLoadOp
(
t
),
3
);
mv
.
visitVarInsn
(
typeLoadOp
(
btChar
),
3
);
// finally, invoke the constructor and return
// finally, invoke the constructor and return
mv
.
visitMethodInsn
(
INVOKEVIRTUAL
,
MH
,
"invokeBasic"
,
makeSignature
(
types
+
t
,
false
),
false
);
mv
.
visitMethodInsn
(
INVOKEVIRTUAL
,
MH
,
"invokeBasic"
,
makeSignature
(
types
+
btChar
,
false
),
false
);
mv
.
visitInsn
(
ARETURN
);
mv
.
visitInsn
(
ARETURN
);
mv
.
visitMaxs
(
0
,
0
);
mv
.
visitMaxs
(
0
,
0
);
mv
.
visitEnd
();
mv
.
visitEnd
();
...
@@ -730,7 +710,7 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -730,7 +710,7 @@ import jdk.internal.org.objectweb.asm.Type;
case
'J'
:
return
LLOAD
;
case
'J'
:
return
LLOAD
;
case
'F'
:
return
FLOAD
;
case
'F'
:
return
FLOAD
;
case
'D'
:
return
DLOAD
;
case
'D'
:
return
DLOAD
;
default
:
throw
new
InternalError
(
"unrecognized type "
+
t
);
default
:
throw
newInternalError
(
"unrecognized type "
+
t
);
}
}
}
}
...
@@ -771,10 +751,19 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -771,10 +751,19 @@ import jdk.internal.org.objectweb.asm.Type;
static
MethodHandle
[]
makeCtors
(
Class
<?
extends
BoundMethodHandle
>
cbmh
,
String
types
,
MethodHandle
mhs
[])
{
static
MethodHandle
[]
makeCtors
(
Class
<?
extends
BoundMethodHandle
>
cbmh
,
String
types
,
MethodHandle
mhs
[])
{
if
(
mhs
==
null
)
mhs
=
new
MethodHandle
[
1
];
if
(
mhs
==
null
)
mhs
=
new
MethodHandle
[
1
];
if
(
types
.
equals
(
""
))
return
mhs
;
// hack for empty BMH species
mhs
[
0
]
=
makeCbmhCtor
(
cbmh
,
types
);
mhs
[
0
]
=
makeCbmhCtor
(
cbmh
,
types
);
return
mhs
;
return
mhs
;
}
}
static
NamedFunction
[]
makeNominalGetters
(
String
types
,
NamedFunction
[]
nfs
,
MethodHandle
[]
getters
)
{
if
(
nfs
==
null
)
nfs
=
new
NamedFunction
[
types
.
length
()];
for
(
int
i
=
0
;
i
<
nfs
.
length
;
++
i
)
{
nfs
[
i
]
=
new
NamedFunction
(
getters
[
i
]);
}
return
nfs
;
}
//
//
// Auxiliary methods.
// Auxiliary methods.
//
//
...
@@ -808,52 +797,11 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -808,52 +797,11 @@ import jdk.internal.org.objectweb.asm.Type;
static
MethodHandle
makeCbmhCtor
(
Class
<?
extends
BoundMethodHandle
>
cbmh
,
String
types
)
{
static
MethodHandle
makeCbmhCtor
(
Class
<?
extends
BoundMethodHandle
>
cbmh
,
String
types
)
{
try
{
try
{
return
linkConstructor
(
LOOKUP
.
findConstructor
(
cbmh
,
MethodType
.
fromMethodDescriptorString
(
makeSignature
(
types
,
true
),
null
)
));
return
LOOKUP
.
findStatic
(
cbmh
,
"make"
,
MethodType
.
fromMethodDescriptorString
(
makeSignature
(
types
,
false
),
null
));
}
catch
(
NoSuchMethodException
|
IllegalAccessException
|
IllegalArgumentException
|
TypeNotPresentException
e
)
{
}
catch
(
NoSuchMethodException
|
IllegalAccessException
|
IllegalArgumentException
|
TypeNotPresentException
e
)
{
throw
newInternalError
(
e
);
throw
newInternalError
(
e
);
}
}
}
}
/**
* Wrap a constructor call in a {@link LambdaForm}.
*
* If constructors ({@code <init>} methods) are called in LFs, problems might arise if the LFs
* are turned into bytecode, because the call to the allocator is routed through an MH, and the
* verifier cannot find a {@code NEW} instruction preceding the {@code INVOKESPECIAL} to
* {@code <init>}. To avoid this, we add an indirection by invoking {@code <init>} through
* {@link MethodHandle#linkToSpecial}.
*
* The last {@link LambdaForm.Name Name} in the argument's form is expected to be the {@code void}
* result of the {@code <init>} invocation. This entry is replaced.
*/
private
static
MethodHandle
linkConstructor
(
MethodHandle
cmh
)
{
final
LambdaForm
lf
=
cmh
.
form
;
final
int
initNameIndex
=
lf
.
names
.
length
-
1
;
final
Name
initName
=
lf
.
names
[
initNameIndex
];
final
MemberName
ctorMN
=
initName
.
function
.
member
;
final
MethodType
ctorMT
=
ctorMN
.
getInvocationType
();
// obtain function member (call target)
// linker method type replaces initial parameter (BMH species) with BMH to avoid naming a species (anonymous class!)
final
MethodType
linkerMT
=
ctorMT
.
changeParameterType
(
0
,
BoundMethodHandle
.
class
).
appendParameterTypes
(
MemberName
.
class
);
MemberName
linkerMN
=
new
MemberName
(
MethodHandle
.
class
,
"linkToSpecial"
,
linkerMT
,
REF_invokeStatic
);
try
{
linkerMN
=
MemberName
.
getFactory
().
resolveOrFail
(
REF_invokeStatic
,
linkerMN
,
null
,
NoSuchMethodException
.
class
);
assert
(
linkerMN
.
isStatic
());
}
catch
(
ReflectiveOperationException
ex
)
{
throw
newInternalError
(
ex
);
}
// extend arguments array
Object
[]
newArgs
=
Arrays
.
copyOf
(
initName
.
arguments
,
initName
.
arguments
.
length
+
1
);
newArgs
[
newArgs
.
length
-
1
]
=
ctorMN
;
// replace function
final
NamedFunction
nf
=
new
NamedFunction
(
linkerMN
);
final
Name
linkedCtor
=
new
Name
(
nf
,
newArgs
);
linkedCtor
.
initIndex
(
initNameIndex
);
lf
.
names
[
initNameIndex
]
=
linkedCtor
;
return
cmh
;
}
}
}
private
static
final
Lookup
LOOKUP
=
Lookup
.
IMPL_LOOKUP
;
private
static
final
Lookup
LOOKUP
=
Lookup
.
IMPL_LOOKUP
;
...
...
src/share/classes/java/lang/invoke/DirectMethodHandle.java
浏览文件 @
237bbe7d
...
@@ -31,6 +31,7 @@ import java.util.Arrays;
...
@@ -31,6 +31,7 @@ import java.util.Arrays;
import
sun.invoke.util.VerifyAccess
;
import
sun.invoke.util.VerifyAccess
;
import
static
java
.
lang
.
invoke
.
MethodHandleNatives
.
Constants
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleNatives
.
Constants
.*;
import
static
java
.
lang
.
invoke
.
LambdaForm
.*;
import
static
java
.
lang
.
invoke
.
LambdaForm
.*;
import
static
java
.
lang
.
invoke
.
LambdaForm
.
BasicType
.*;
import
static
java
.
lang
.
invoke
.
MethodTypeForm
.*;
import
static
java
.
lang
.
invoke
.
MethodTypeForm
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
import
java.lang.ref.WeakReference
;
import
java.lang.ref.WeakReference
;
...
@@ -124,11 +125,6 @@ class DirectMethodHandle extends MethodHandle {
...
@@ -124,11 +125,6 @@ class DirectMethodHandle extends MethodHandle {
return
new
Constructor
(
mtype
,
lform
,
ctor
,
init
,
instanceClass
);
return
new
Constructor
(
mtype
,
lform
,
ctor
,
init
,
instanceClass
);
}
}
@Override
MethodHandle
copyWith
(
MethodType
mt
,
LambdaForm
lf
)
{
return
new
DirectMethodHandle
(
mt
,
lf
,
member
);
}
@Override
@Override
String
internalProperties
()
{
String
internalProperties
()
{
return
"/DMH="
+
member
.
toString
();
return
"/DMH="
+
member
.
toString
();
...
@@ -146,9 +142,9 @@ class DirectMethodHandle extends MethodHandle {
...
@@ -146,9 +142,9 @@ class DirectMethodHandle extends MethodHandle {
}
}
@Override
@Override
MethodHandle
bindArgument
(
int
pos
,
char
basicType
,
Object
value
)
{
MethodHandle
bindArgument
(
int
pos
,
BasicType
basicType
,
Object
value
)
{
// If the member needs dispatching, do so.
// If the member needs dispatching, do so.
if
(
pos
==
0
&&
basicType
==
'L'
)
{
if
(
pos
==
0
&&
basicType
==
L_TYPE
)
{
DirectMethodHandle
concrete
=
maybeRebind
(
value
);
DirectMethodHandle
concrete
=
maybeRebind
(
value
);
if
(
concrete
!=
null
)
if
(
concrete
!=
null
)
return
concrete
.
bindReceiver
(
value
);
return
concrete
.
bindReceiver
(
value
);
...
@@ -274,7 +270,7 @@ class DirectMethodHandle extends MethodHandle {
...
@@ -274,7 +270,7 @@ class DirectMethodHandle extends MethodHandle {
result
=
NEW_OBJ
;
result
=
NEW_OBJ
;
}
}
names
[
LINKER_CALL
]
=
new
Name
(
linker
,
outArgs
);
names
[
LINKER_CALL
]
=
new
Name
(
linker
,
outArgs
);
lambdaName
+=
"_"
+
LambdaForm
.
basicTypeSignature
(
mtype
);
lambdaName
+=
"_"
+
shortenSignature
(
basicTypeSignature
(
mtype
)
);
LambdaForm
lform
=
new
LambdaForm
(
lambdaName
,
ARG_LIMIT
,
names
,
result
);
LambdaForm
lform
=
new
LambdaForm
(
lambdaName
,
ARG_LIMIT
,
names
,
result
);
// This is a tricky bit of code. Don't send it through the LF interpreter.
// This is a tricky bit of code. Don't send it through the LF interpreter.
lform
.
compileToBytecode
();
lform
.
compileToBytecode
();
...
...
src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
浏览文件 @
237bbe7d
...
@@ -26,7 +26,7 @@
...
@@ -26,7 +26,7 @@
package
java.lang.invoke
;
package
java.lang.invoke
;
import
sun.invoke.util.VerifyAccess
;
import
sun.invoke.util.VerifyAccess
;
import
java.lang.invoke.LambdaForm.Name
;
import
static
java
.
lang
.
invoke
.
LambdaForm
.*
;
import
sun.invoke.util.Wrapper
;
import
sun.invoke.util.Wrapper
;
...
@@ -38,6 +38,7 @@ import jdk.internal.org.objectweb.asm.*;
...
@@ -38,6 +38,7 @@ import jdk.internal.org.objectweb.asm.*;
import
java.lang.reflect.*
;
import
java.lang.reflect.*
;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleNatives
.
Constants
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleNatives
.
Constants
.*;
import
static
java
.
lang
.
invoke
.
LambdaForm
.
BasicType
.*;
import
sun.invoke.util.VerifyType
;
import
sun.invoke.util.VerifyType
;
import
sun.reflect.misc.ReflectUtil
;
import
sun.reflect.misc.ReflectUtil
;
...
@@ -116,7 +117,7 @@ class InvokerBytecodeGenerator {
...
@@ -116,7 +117,7 @@ class InvokerBytecodeGenerator {
Name
[]
names
=
form
.
names
;
Name
[]
names
=
form
.
names
;
for
(
int
i
=
0
,
index
=
0
;
i
<
localsMap
.
length
;
i
++)
{
for
(
int
i
=
0
,
index
=
0
;
i
<
localsMap
.
length
;
i
++)
{
localsMap
[
i
]
=
index
;
localsMap
[
i
]
=
index
;
index
+=
Wrapper
.
forBasicType
(
names
[
i
].
type
).
stack
Slots
();
index
+=
names
[
i
].
type
.
basicType
Slots
();
}
}
}
}
...
@@ -359,47 +360,52 @@ class InvokerBytecodeGenerator {
...
@@ -359,47 +360,52 @@ class InvokerBytecodeGenerator {
/*
/*
* NOTE: These load/store methods use the localsMap to find the correct index!
* NOTE: These load/store methods use the localsMap to find the correct index!
*/
*/
private
void
emitLoadInsn
(
char
type
,
int
index
)
{
private
void
emitLoadInsn
(
BasicType
type
,
int
index
)
{
int
opcode
;
int
opcode
=
loadInsnOpcode
(
type
);
mv
.
visitVarInsn
(
opcode
,
localsMap
[
index
]);
}
private
int
loadInsnOpcode
(
BasicType
type
)
throws
InternalError
{
switch
(
type
)
{
switch
(
type
)
{
case
'I'
:
opcode
=
Opcodes
.
ILOAD
;
break
;
case
I_TYPE:
return
Opcodes
.
ILOAD
;
case
'J'
:
opcode
=
Opcodes
.
LLOAD
;
break
;
case
J_TYPE:
return
Opcodes
.
LLOAD
;
case
'F'
:
opcode
=
Opcodes
.
FLOAD
;
break
;
case
F_TYPE:
return
Opcodes
.
FLOAD
;
case
'D'
:
opcode
=
Opcodes
.
DLOAD
;
break
;
case
D_TYPE:
return
Opcodes
.
DLOAD
;
case
'L'
:
opcode
=
Opcodes
.
ALOAD
;
break
;
case
L_TYPE:
return
Opcodes
.
ALOAD
;
default
:
default
:
throw
new
InternalError
(
"unknown type: "
+
type
);
throw
new
InternalError
(
"unknown type: "
+
type
);
}
}
mv
.
visitVarInsn
(
opcode
,
localsMap
[
index
]);
}
}
private
void
emitAloadInsn
(
int
index
)
{
private
void
emitAloadInsn
(
int
index
)
{
emitLoadInsn
(
'L'
,
index
);
emitLoadInsn
(
L_TYPE
,
index
);
}
}
private
void
emitStoreInsn
(
char
type
,
int
index
)
{
private
void
emitStoreInsn
(
BasicType
type
,
int
index
)
{
int
opcode
;
int
opcode
=
storeInsnOpcode
(
type
);
mv
.
visitVarInsn
(
opcode
,
localsMap
[
index
]);
}
private
int
storeInsnOpcode
(
BasicType
type
)
throws
InternalError
{
switch
(
type
)
{
switch
(
type
)
{
case
'I'
:
opcode
=
Opcodes
.
ISTORE
;
break
;
case
I_TYPE:
return
Opcodes
.
ISTORE
;
case
'J'
:
opcode
=
Opcodes
.
LSTORE
;
break
;
case
J_TYPE:
return
Opcodes
.
LSTORE
;
case
'F'
:
opcode
=
Opcodes
.
FSTORE
;
break
;
case
F_TYPE:
return
Opcodes
.
FSTORE
;
case
'D'
:
opcode
=
Opcodes
.
DSTORE
;
break
;
case
D_TYPE:
return
Opcodes
.
DSTORE
;
case
'L'
:
opcode
=
Opcodes
.
ASTORE
;
break
;
case
L_TYPE:
return
Opcodes
.
ASTORE
;
default
:
default
:
throw
new
InternalError
(
"unknown type: "
+
type
);
throw
new
InternalError
(
"unknown type: "
+
type
);
}
}
mv
.
visitVarInsn
(
opcode
,
localsMap
[
index
]);
}
}
private
void
emitAstoreInsn
(
int
index
)
{
private
void
emitAstoreInsn
(
int
index
)
{
emitStoreInsn
(
'L'
,
index
);
emitStoreInsn
(
L_TYPE
,
index
);
}
}
/**
/**
* Emit a boxing call.
* Emit a boxing call.
*
*
* @param
type
primitive type class to box.
* @param
wrapper
primitive type class to box.
*/
*/
private
void
emitBoxing
(
Class
<?>
type
)
{
private
void
emitBoxing
(
Wrapper
wrapper
)
{
Wrapper
wrapper
=
Wrapper
.
forPrimitiveType
(
type
);
String
owner
=
"java/lang/"
+
wrapper
.
wrapperType
().
getSimpleName
();
String
owner
=
"java/lang/"
+
wrapper
.
wrapperType
().
getSimpleName
();
String
name
=
"valueOf"
;
String
name
=
"valueOf"
;
String
desc
=
"("
+
wrapper
.
basicTypeChar
()
+
")L"
+
owner
+
";"
;
String
desc
=
"("
+
wrapper
.
basicTypeChar
()
+
")L"
+
owner
+
";"
;
...
@@ -409,10 +415,9 @@ class InvokerBytecodeGenerator {
...
@@ -409,10 +415,9 @@ class InvokerBytecodeGenerator {
/**
/**
* Emit an unboxing call (plus preceding checkcast).
* Emit an unboxing call (plus preceding checkcast).
*
*
* @param
type
wrapper type class to unbox.
* @param
wrapper
wrapper type class to unbox.
*/
*/
private
void
emitUnboxing
(
Class
<?>
type
)
{
private
void
emitUnboxing
(
Wrapper
wrapper
)
{
Wrapper
wrapper
=
Wrapper
.
forWrapperType
(
type
);
String
owner
=
"java/lang/"
+
wrapper
.
wrapperType
().
getSimpleName
();
String
owner
=
"java/lang/"
+
wrapper
.
wrapperType
().
getSimpleName
();
String
name
=
wrapper
.
primitiveSimpleName
()
+
"Value"
;
String
name
=
wrapper
.
primitiveSimpleName
()
+
"Value"
;
String
desc
=
"()"
+
wrapper
.
basicTypeChar
();
String
desc
=
"()"
+
wrapper
.
basicTypeChar
();
...
@@ -426,9 +431,12 @@ class InvokerBytecodeGenerator {
...
@@ -426,9 +431,12 @@ class InvokerBytecodeGenerator {
* @param ptype type of value present on stack
* @param ptype type of value present on stack
* @param pclass type of value required on stack
* @param pclass type of value required on stack
*/
*/
private
void
emitImplicitConversion
(
char
ptype
,
Class
<?>
pclass
)
{
private
void
emitImplicitConversion
(
BasicType
ptype
,
Class
<?>
pclass
)
{
assert
(
basicType
(
pclass
)
==
ptype
);
// boxing/unboxing handled by caller
if
(
pclass
==
ptype
.
basicTypeClass
()
&&
ptype
!=
L_TYPE
)
return
;
// nothing to do
switch
(
ptype
)
{
switch
(
ptype
)
{
case
'L'
:
case
L_TYPE
:
if
(
VerifyType
.
isNullConversion
(
Object
.
class
,
pclass
))
if
(
VerifyType
.
isNullConversion
(
Object
.
class
,
pclass
))
return
;
return
;
if
(
isStaticallyNameable
(
pclass
))
{
if
(
isStaticallyNameable
(
pclass
))
{
...
@@ -442,18 +450,9 @@ class InvokerBytecodeGenerator {
...
@@ -442,18 +450,9 @@ class InvokerBytecodeGenerator {
mv
.
visitTypeInsn
(
Opcodes
.
CHECKCAST
,
OBJARY
);
mv
.
visitTypeInsn
(
Opcodes
.
CHECKCAST
,
OBJARY
);
}
}
return
;
return
;
case
'I'
:
case
I_TYPE
:
if
(!
VerifyType
.
isNullConversion
(
int
.
class
,
pclass
))
if
(!
VerifyType
.
isNullConversion
(
int
.
class
,
pclass
))
emitPrimCast
(
ptype
,
Wrapper
.
basicTypeChar
(
pclass
));
emitPrimCast
(
ptype
.
basicTypeWrapper
(),
Wrapper
.
forPrimitiveType
(
pclass
));
return
;
case
'J'
:
assert
(
pclass
==
long
.
class
);
return
;
case
'F'
:
assert
(
pclass
==
float
.
class
);
return
;
case
'D'
:
assert
(
pclass
==
double
.
class
);
return
;
return
;
}
}
throw
new
InternalError
(
"bad implicit conversion: tc="
+
ptype
+
": "
+
pclass
);
throw
new
InternalError
(
"bad implicit conversion: tc="
+
ptype
+
": "
+
pclass
);
...
@@ -462,15 +461,15 @@ class InvokerBytecodeGenerator {
...
@@ -462,15 +461,15 @@ class InvokerBytecodeGenerator {
/**
/**
* Emits an actual return instruction conforming to the given return type.
* Emits an actual return instruction conforming to the given return type.
*/
*/
private
void
emitReturnInsn
(
Class
<?>
type
)
{
private
void
emitReturnInsn
(
BasicType
type
)
{
int
opcode
;
int
opcode
;
switch
(
Wrapper
.
basicTypeChar
(
type
)
)
{
switch
(
type
)
{
case
'I'
:
opcode
=
Opcodes
.
IRETURN
;
break
;
case
I_TYPE
:
opcode
=
Opcodes
.
IRETURN
;
break
;
case
'J'
:
opcode
=
Opcodes
.
LRETURN
;
break
;
case
J_TYPE
:
opcode
=
Opcodes
.
LRETURN
;
break
;
case
'F'
:
opcode
=
Opcodes
.
FRETURN
;
break
;
case
F_TYPE
:
opcode
=
Opcodes
.
FRETURN
;
break
;
case
'D'
:
opcode
=
Opcodes
.
DRETURN
;
break
;
case
D_TYPE
:
opcode
=
Opcodes
.
DRETURN
;
break
;
case
'L'
:
opcode
=
Opcodes
.
ARETURN
;
break
;
case
L_TYPE
:
opcode
=
Opcodes
.
ARETURN
;
break
;
case
'V'
:
opcode
=
Opcodes
.
RETURN
;
break
;
case
V_TYPE
:
opcode
=
Opcodes
.
RETURN
;
break
;
default
:
default
:
throw
new
InternalError
(
"unknown return type: "
+
type
);
throw
new
InternalError
(
"unknown return type: "
+
type
);
}
}
...
@@ -532,7 +531,7 @@ class InvokerBytecodeGenerator {
...
@@ -532,7 +531,7 @@ class InvokerBytecodeGenerator {
// avoid store/load/return and just return)
// avoid store/load/return and just return)
if
(
i
==
lambdaForm
.
names
.
length
-
1
&&
i
==
lambdaForm
.
result
)
{
if
(
i
==
lambdaForm
.
names
.
length
-
1
&&
i
==
lambdaForm
.
result
)
{
// return value - do nothing
// return value - do nothing
}
else
if
(
name
.
type
!=
'V'
)
{
}
else
if
(
name
.
type
!=
V_TYPE
)
{
// non-void: actually assign
// non-void: actually assign
emitStoreInsn
(
name
.
type
,
name
.
index
());
emitStoreInsn
(
name
.
type
,
name
.
index
());
}
}
...
@@ -870,20 +869,24 @@ class InvokerBytecodeGenerator {
...
@@ -870,20 +869,24 @@ class InvokerBytecodeGenerator {
private
void
emitPushArgument
(
Name
name
,
int
paramIndex
)
{
private
void
emitPushArgument
(
Name
name
,
int
paramIndex
)
{
Object
arg
=
name
.
arguments
[
paramIndex
];
Object
arg
=
name
.
arguments
[
paramIndex
];
char
ptype
=
name
.
function
.
parameterType
(
paramIndex
);
Class
<?>
ptype
=
name
.
function
.
methodType
().
parameterType
(
paramIndex
);
MethodType
mtype
=
name
.
function
.
methodType
();
emitPushArgument
(
ptype
,
arg
);
}
private
void
emitPushArgument
(
Class
<?>
ptype
,
Object
arg
)
{
BasicType
bptype
=
basicType
(
ptype
);
if
(
arg
instanceof
Name
)
{
if
(
arg
instanceof
Name
)
{
Name
n
=
(
Name
)
arg
;
Name
n
=
(
Name
)
arg
;
emitLoadInsn
(
n
.
type
,
n
.
index
());
emitLoadInsn
(
n
.
type
,
n
.
index
());
emitImplicitConversion
(
n
.
type
,
mtype
.
parameterType
(
paramIndex
)
);
emitImplicitConversion
(
n
.
type
,
ptype
);
}
else
if
((
arg
==
null
||
arg
instanceof
String
)
&&
ptype
==
'L'
)
{
}
else
if
((
arg
==
null
||
arg
instanceof
String
)
&&
bptype
==
L_TYPE
)
{
emitConst
(
arg
);
emitConst
(
arg
);
}
else
{
}
else
{
if
(
Wrapper
.
isWrapperType
(
arg
.
getClass
())
&&
ptype
!=
'L'
)
{
if
(
Wrapper
.
isWrapperType
(
arg
.
getClass
())
&&
bptype
!=
L_TYPE
)
{
emitConst
(
arg
);
emitConst
(
arg
);
}
else
{
}
else
{
mv
.
visitLdcInsn
(
constantPlaceholder
(
arg
));
mv
.
visitLdcInsn
(
constantPlaceholder
(
arg
));
emitImplicitConversion
(
'L'
,
mtype
.
parameterType
(
paramIndex
)
);
emitImplicitConversion
(
L_TYPE
,
ptype
);
}
}
}
}
}
}
...
@@ -893,52 +896,33 @@ class InvokerBytecodeGenerator {
...
@@ -893,52 +896,33 @@ class InvokerBytecodeGenerator {
*/
*/
private
void
emitReturn
()
{
private
void
emitReturn
()
{
// return statement
// return statement
if
(
lambdaForm
.
result
==
-
1
)
{
Class
<?>
rclass
=
invokerType
.
returnType
();
BasicType
rtype
=
lambdaForm
.
returnType
();
assert
(
rtype
==
basicType
(
rclass
));
// must agree
if
(
rtype
==
V_TYPE
)
{
// void
// void
mv
.
visitInsn
(
Opcodes
.
RETURN
);
mv
.
visitInsn
(
Opcodes
.
RETURN
);
// it doesn't matter what rclass is; the JVM will discard any value
}
else
{
}
else
{
LambdaForm
.
Name
rn
=
lambdaForm
.
names
[
lambdaForm
.
result
];
LambdaForm
.
Name
rn
=
lambdaForm
.
names
[
lambdaForm
.
result
];
char
rtype
=
Wrapper
.
basicTypeChar
(
invokerType
.
returnType
());
// put return value on the stack if it is not already there
// put return value on the stack if it is not already there
if
(
lambdaForm
.
result
!=
lambdaForm
.
names
.
length
-
1
)
{
if
(
lambdaForm
.
result
!=
lambdaForm
.
names
.
length
-
1
||
lambdaForm
.
result
<
lambdaForm
.
arity
)
{
emitLoadInsn
(
rn
.
type
,
lambdaForm
.
result
);
emitLoadInsn
(
rn
.
type
,
lambdaForm
.
result
);
}
}
// potentially generate cast
emitImplicitConversion
(
rtype
,
rclass
);
// rtype is the return type of the invoker - generated code must conform to this
// rn.type is the type of the result Name in the LF
if
(
rtype
!=
rn
.
type
)
{
// need cast
if
(
rtype
==
'L'
)
{
// possibly cast the primitive to the correct type for boxing
char
boxedType
=
Wrapper
.
forWrapperType
(
invokerType
.
returnType
()).
basicTypeChar
();
if
(
boxedType
!=
rn
.
type
)
{
emitPrimCast
(
rn
.
type
,
boxedType
);
}
// cast primitive to reference ("boxing")
emitBoxing
(
invokerType
.
returnType
());
}
else
{
// to-primitive cast
if
(
rn
.
type
!=
'L'
)
{
// prim-to-prim cast
emitPrimCast
(
rn
.
type
,
rtype
);
}
else
{
// ref-to-prim cast ("unboxing")
throw
new
InternalError
(
"no ref-to-prim (unboxing) casts supported right now"
);
}
}
}
// generate actual return statement
// generate actual return statement
emitReturnInsn
(
invokerType
.
returnType
()
);
emitReturnInsn
(
rtype
);
}
}
}
}
/**
/**
* Emit a type conversion bytecode casting from "from" to "to".
* Emit a type conversion bytecode casting from "from" to "to".
*/
*/
private
void
emitPrimCast
(
char
from
,
cha
r
to
)
{
private
void
emitPrimCast
(
Wrapper
from
,
Wrappe
r
to
)
{
// Here's how.
// Here's how.
// - indicates forbidden
// - indicates forbidden
// <-> indicates implicit
// <-> indicates implicit
...
@@ -955,17 +939,15 @@ class InvokerBytecodeGenerator {
...
@@ -955,17 +939,15 @@ class InvokerBytecodeGenerator {
// no cast required, should be dead code anyway
// no cast required, should be dead code anyway
return
;
return
;
}
}
Wrapper
wfrom
=
Wrapper
.
forBasicType
(
from
);
if
(
from
.
isSubwordOrInt
())
{
Wrapper
wto
=
Wrapper
.
forBasicType
(
to
);
if
(
wfrom
.
isSubwordOrInt
())
{
// cast from {byte,short,char,int} to anything
// cast from {byte,short,char,int} to anything
emitI2X
(
to
);
emitI2X
(
to
);
}
else
{
}
else
{
// cast from {long,float,double} to anything
// cast from {long,float,double} to anything
if
(
w
to
.
isSubwordOrInt
())
{
if
(
to
.
isSubwordOrInt
())
{
// cast to {byte,short,char,int}
// cast to {byte,short,char,int}
emitX2I
(
from
);
emitX2I
(
from
);
if
(
w
to
.
bitWidth
()
<
32
)
{
if
(
to
.
bitWidth
()
<
32
)
{
// targets other than int require another conversion
// targets other than int require another conversion
emitI2X
(
to
);
emitI2X
(
to
);
}
}
...
@@ -973,20 +955,26 @@ class InvokerBytecodeGenerator {
...
@@ -973,20 +955,26 @@ class InvokerBytecodeGenerator {
// cast to {long,float,double} - this is verbose
// cast to {long,float,double} - this is verbose
boolean
error
=
false
;
boolean
error
=
false
;
switch
(
from
)
{
switch
(
from
)
{
case
'J'
:
case
LONG:
if
(
to
==
'F'
)
{
mv
.
visitInsn
(
Opcodes
.
L2F
);
}
switch
(
to
)
{
else
if
(
to
==
'D'
)
{
mv
.
visitInsn
(
Opcodes
.
L2D
);
}
case
FLOAT:
mv
.
visitInsn
(
Opcodes
.
L2F
);
break
;
else
error
=
true
;
case
DOUBLE:
mv
.
visitInsn
(
Opcodes
.
L2D
);
break
;
default
:
error
=
true
;
break
;
}
break
;
break
;
case
'F'
:
case
FLOAT:
if
(
to
==
'J'
)
{
mv
.
visitInsn
(
Opcodes
.
F2L
);
}
switch
(
to
)
{
else
if
(
to
==
'D'
)
{
mv
.
visitInsn
(
Opcodes
.
F2D
);
}
case
LONG
:
mv
.
visitInsn
(
Opcodes
.
F2L
);
break
;
else
error
=
true
;
case
DOUBLE:
mv
.
visitInsn
(
Opcodes
.
F2D
);
break
;
default
:
error
=
true
;
break
;
}
break
;
break
;
case
'D'
:
case
DOUBLE:
if
(
to
==
'J'
)
{
mv
.
visitInsn
(
Opcodes
.
D2L
);
}
switch
(
to
)
{
else
if
(
to
==
'F'
)
{
mv
.
visitInsn
(
Opcodes
.
D2F
);
}
case
LONG
:
mv
.
visitInsn
(
Opcodes
.
D2L
);
break
;
else
error
=
true
;
case
FLOAT:
mv
.
visitInsn
(
Opcodes
.
D2F
);
break
;
default
:
error
=
true
;
break
;
}
break
;
break
;
default
:
default
:
error
=
true
;
error
=
true
;
...
@@ -999,16 +987,16 @@ class InvokerBytecodeGenerator {
...
@@ -999,16 +987,16 @@ class InvokerBytecodeGenerator {
}
}
}
}
private
void
emitI2X
(
cha
r
type
)
{
private
void
emitI2X
(
Wrappe
r
type
)
{
switch
(
type
)
{
switch
(
type
)
{
case
'B'
:
mv
.
visitInsn
(
Opcodes
.
I2B
);
break
;
case
BYTE:
mv
.
visitInsn
(
Opcodes
.
I2B
);
break
;
case
'S'
:
mv
.
visitInsn
(
Opcodes
.
I2S
);
break
;
case
SHORT:
mv
.
visitInsn
(
Opcodes
.
I2S
);
break
;
case
'C'
:
mv
.
visitInsn
(
Opcodes
.
I2C
);
break
;
case
CHAR:
mv
.
visitInsn
(
Opcodes
.
I2C
);
break
;
case
'I'
:
/* naught */
break
;
case
INT:
/* naught */
break
;
case
'J'
:
mv
.
visitInsn
(
Opcodes
.
I2L
);
break
;
case
LONG:
mv
.
visitInsn
(
Opcodes
.
I2L
);
break
;
case
'F'
:
mv
.
visitInsn
(
Opcodes
.
I2F
);
break
;
case
FLOAT:
mv
.
visitInsn
(
Opcodes
.
I2F
);
break
;
case
'D'
:
mv
.
visitInsn
(
Opcodes
.
I2D
);
break
;
case
DOUBLE
:
mv
.
visitInsn
(
Opcodes
.
I2D
);
break
;
case
'Z'
:
case
BOOLEAN
:
// For compatibility with ValueConversions and explicitCastArguments:
// For compatibility with ValueConversions and explicitCastArguments:
mv
.
visitInsn
(
Opcodes
.
ICONST_1
);
mv
.
visitInsn
(
Opcodes
.
ICONST_1
);
mv
.
visitInsn
(
Opcodes
.
IAND
);
mv
.
visitInsn
(
Opcodes
.
IAND
);
...
@@ -1017,39 +1005,24 @@ class InvokerBytecodeGenerator {
...
@@ -1017,39 +1005,24 @@ class InvokerBytecodeGenerator {
}
}
}
}
private
void
emitX2I
(
cha
r
type
)
{
private
void
emitX2I
(
Wrappe
r
type
)
{
switch
(
type
)
{
switch
(
type
)
{
case
'J'
:
mv
.
visitInsn
(
Opcodes
.
L2I
);
break
;
case
LONG:
mv
.
visitInsn
(
Opcodes
.
L2I
);
break
;
case
'F'
:
mv
.
visitInsn
(
Opcodes
.
F2I
);
break
;
case
FLOAT:
mv
.
visitInsn
(
Opcodes
.
F2I
);
break
;
case
'D'
:
mv
.
visitInsn
(
Opcodes
.
D2I
);
break
;
case
DOUBLE
:
mv
.
visitInsn
(
Opcodes
.
D2I
);
break
;
default
:
throw
new
InternalError
(
"unknown type: "
+
type
);
default
:
throw
new
InternalError
(
"unknown type: "
+
type
);
}
}
}
}
private
static
String
basicTypeCharSignature
(
String
prefix
,
MethodType
type
)
{
StringBuilder
buf
=
new
StringBuilder
(
prefix
);
for
(
Class
<?>
ptype
:
type
.
parameterList
())
buf
.
append
(
Wrapper
.
forBasicType
(
ptype
).
basicTypeChar
());
buf
.
append
(
'_'
).
append
(
Wrapper
.
forBasicType
(
type
.
returnType
()).
basicTypeChar
());
return
buf
.
toString
();
}
/**
/**
* Generate bytecode for a LambdaForm.vmentry which calls interpretWithArguments.
* Generate bytecode for a LambdaForm.vmentry which calls interpretWithArguments.
*/
*/
static
MemberName
generateLambdaFormInterpreterEntryPoint
(
String
sig
)
{
static
MemberName
generateLambdaFormInterpreterEntryPoint
(
String
sig
)
{
assert
(
LambdaForm
.
isValidSignature
(
sig
));
assert
(
isValidSignature
(
sig
));
//System.out.println("generateExactInvoker "+sig);
String
name
=
"interpret_"
+
signatureReturn
(
sig
).
basicTypeChar
();
// compute method type
MethodType
type
=
signatureType
(
sig
);
// sig includes leading argument
// first parameter and return type
type
=
type
.
changeParameterType
(
0
,
MethodHandle
.
class
);
char
tret
=
LambdaForm
.
signatureReturn
(
sig
);
InvokerBytecodeGenerator
g
=
new
InvokerBytecodeGenerator
(
"LFI"
,
name
,
type
);
MethodType
type
=
MethodType
.
methodType
(
LambdaForm
.
typeClass
(
tret
),
MethodHandle
.
class
);
// other parameter types
int
arity
=
LambdaForm
.
signatureArity
(
sig
);
for
(
int
i
=
1
;
i
<
arity
;
i
++)
{
type
=
type
.
appendParameterTypes
(
LambdaForm
.
typeClass
(
sig
.
charAt
(
i
)));
}
InvokerBytecodeGenerator
g
=
new
InvokerBytecodeGenerator
(
"LFI"
,
"interpret_"
+
tret
,
type
);
return
g
.
loadMethod
(
g
.
generateLambdaFormInterpreterEntryPointBytes
());
return
g
.
loadMethod
(
g
.
generateLambdaFormInterpreterEntryPointBytes
());
}
}
...
@@ -1071,10 +1044,10 @@ class InvokerBytecodeGenerator {
...
@@ -1071,10 +1044,10 @@ class InvokerBytecodeGenerator {
Class
<?>
ptype
=
invokerType
.
parameterType
(
i
);
Class
<?>
ptype
=
invokerType
.
parameterType
(
i
);
mv
.
visitInsn
(
Opcodes
.
DUP
);
mv
.
visitInsn
(
Opcodes
.
DUP
);
emitIconstInsn
(
i
);
emitIconstInsn
(
i
);
emitLoadInsn
(
Wrapper
.
basicTypeChar
(
ptype
),
i
);
emitLoadInsn
(
basicType
(
ptype
),
i
);
// box if primitive type
// box if primitive type
if
(
ptype
.
isPrimitive
())
{
if
(
ptype
.
isPrimitive
())
{
emitBoxing
(
ptype
);
emitBoxing
(
Wrapper
.
forPrimitiveType
(
ptype
)
);
}
}
mv
.
visitInsn
(
Opcodes
.
AASTORE
);
mv
.
visitInsn
(
Opcodes
.
AASTORE
);
}
}
...
@@ -1087,11 +1060,11 @@ class InvokerBytecodeGenerator {
...
@@ -1087,11 +1060,11 @@ class InvokerBytecodeGenerator {
// maybe unbox
// maybe unbox
Class
<?>
rtype
=
invokerType
.
returnType
();
Class
<?>
rtype
=
invokerType
.
returnType
();
if
(
rtype
.
isPrimitive
()
&&
rtype
!=
void
.
class
)
{
if
(
rtype
.
isPrimitive
()
&&
rtype
!=
void
.
class
)
{
emitUnboxing
(
Wrapper
.
asWrapper
Type
(
rtype
));
emitUnboxing
(
Wrapper
.
forPrimitive
Type
(
rtype
));
}
}
// return statement
// return statement
emitReturnInsn
(
rtype
);
emitReturnInsn
(
basicType
(
rtype
)
);
classFileEpilogue
();
classFileEpilogue
();
bogusMethod
(
invokerType
);
bogusMethod
(
invokerType
);
...
@@ -1105,14 +1078,12 @@ class InvokerBytecodeGenerator {
...
@@ -1105,14 +1078,12 @@ class InvokerBytecodeGenerator {
* Generate bytecode for a NamedFunction invoker.
* Generate bytecode for a NamedFunction invoker.
*/
*/
static
MemberName
generateNamedFunctionInvoker
(
MethodTypeForm
typeForm
)
{
static
MemberName
generateNamedFunctionInvoker
(
MethodTypeForm
typeForm
)
{
MethodType
invokerType
=
LambdaForm
.
NamedFunction
.
INVOKER_METHOD_TYPE
;
MethodType
invokerType
=
NamedFunction
.
INVOKER_METHOD_TYPE
;
String
invokerName
=
basicTypeCharSignature
(
"invoke_"
,
typeForm
.
erasedType
(
));
String
invokerName
=
"invoke_"
+
shortenSignature
(
basicTypeSignature
(
typeForm
.
erasedType
()
));
InvokerBytecodeGenerator
g
=
new
InvokerBytecodeGenerator
(
"NFI"
,
invokerName
,
invokerType
);
InvokerBytecodeGenerator
g
=
new
InvokerBytecodeGenerator
(
"NFI"
,
invokerName
,
invokerType
);
return
g
.
loadMethod
(
g
.
generateNamedFunctionInvokerImpl
(
typeForm
));
return
g
.
loadMethod
(
g
.
generateNamedFunctionInvokerImpl
(
typeForm
));
}
}
static
int
nfi
=
0
;
private
byte
[]
generateNamedFunctionInvokerImpl
(
MethodTypeForm
typeForm
)
{
private
byte
[]
generateNamedFunctionInvokerImpl
(
MethodTypeForm
typeForm
)
{
MethodType
dstType
=
typeForm
.
erasedType
();
MethodType
dstType
=
typeForm
.
erasedType
();
classFilePrologue
();
classFilePrologue
();
...
@@ -1138,8 +1109,8 @@ class InvokerBytecodeGenerator {
...
@@ -1138,8 +1109,8 @@ class InvokerBytecodeGenerator {
Class
<?>
sptype
=
dstType
.
basicType
().
wrap
().
parameterType
(
i
);
Class
<?>
sptype
=
dstType
.
basicType
().
wrap
().
parameterType
(
i
);
Wrapper
dstWrapper
=
Wrapper
.
forBasicType
(
dptype
);
Wrapper
dstWrapper
=
Wrapper
.
forBasicType
(
dptype
);
Wrapper
srcWrapper
=
dstWrapper
.
isSubwordOrInt
()
?
Wrapper
.
INT
:
dstWrapper
;
// narrow subword from int
Wrapper
srcWrapper
=
dstWrapper
.
isSubwordOrInt
()
?
Wrapper
.
INT
:
dstWrapper
;
// narrow subword from int
emitUnboxing
(
srcWrapper
.
wrapperType
()
);
emitUnboxing
(
srcWrapper
);
emitPrimCast
(
srcWrapper
.
basicTypeChar
(),
dstWrapper
.
basicTypeChar
()
);
emitPrimCast
(
srcWrapper
,
dstWrapper
);
}
}
}
}
...
@@ -1153,15 +1124,15 @@ class InvokerBytecodeGenerator {
...
@@ -1153,15 +1124,15 @@ class InvokerBytecodeGenerator {
Wrapper
srcWrapper
=
Wrapper
.
forBasicType
(
rtype
);
Wrapper
srcWrapper
=
Wrapper
.
forBasicType
(
rtype
);
Wrapper
dstWrapper
=
srcWrapper
.
isSubwordOrInt
()
?
Wrapper
.
INT
:
srcWrapper
;
// widen subword to int
Wrapper
dstWrapper
=
srcWrapper
.
isSubwordOrInt
()
?
Wrapper
.
INT
:
srcWrapper
;
// widen subword to int
// boolean casts not allowed
// boolean casts not allowed
emitPrimCast
(
srcWrapper
.
basicTypeChar
(),
dstWrapper
.
basicTypeChar
()
);
emitPrimCast
(
srcWrapper
,
dstWrapper
);
emitBoxing
(
dstWrapper
.
primitiveType
()
);
emitBoxing
(
dstWrapper
);
}
}
// If the return type is void we return a null reference.
// If the return type is void we return a null reference.
if
(
rtype
==
void
.
class
)
{
if
(
rtype
==
void
.
class
)
{
mv
.
visitInsn
(
Opcodes
.
ACONST_NULL
);
mv
.
visitInsn
(
Opcodes
.
ACONST_NULL
);
}
}
emitReturnInsn
(
Object
.
class
);
// NOTE: NamedFunction invokers always return a reference value.
emitReturnInsn
(
L_TYPE
);
// NOTE: NamedFunction invokers always return a reference value.
classFileEpilogue
();
classFileEpilogue
();
bogusMethod
(
dstType
);
bogusMethod
(
dstType
);
...
...
src/share/classes/java/lang/invoke/LambdaForm.java
浏览文件 @
237bbe7d
...
@@ -30,14 +30,14 @@ import java.lang.reflect.Method;
...
@@ -30,14 +30,14 @@ import java.lang.reflect.Method;
import
java.util.Map
;
import
java.util.Map
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.HashMap
;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.ConcurrentHashMap
;
import
sun.invoke.util.Wrapper
;
import
sun.invoke.util.Wrapper
;
import
java.lang.reflect.Field
;
import
static
java
.
lang
.
invoke
.
LambdaForm
.
BasicType
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleNatives
.
Constants
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleNatives
.
Constants
.*;
import
java.lang.reflect.Field
;
import
java.util.Objects
;
/**
/**
* The symbolic, non-executable form of a method handle's invocation semantics.
* The symbolic, non-executable form of a method handle's invocation semantics.
...
@@ -130,13 +130,119 @@ class LambdaForm {
...
@@ -130,13 +130,119 @@ class LambdaForm {
public
static
final
int
VOID_RESULT
=
-
1
,
LAST_RESULT
=
-
2
;
public
static
final
int
VOID_RESULT
=
-
1
,
LAST_RESULT
=
-
2
;
enum
BasicType
{
L_TYPE
(
'L'
,
Object
.
class
,
Wrapper
.
OBJECT
),
// all reference types
I_TYPE
(
'I'
,
int
.
class
,
Wrapper
.
INT
),
J_TYPE
(
'J'
,
long
.
class
,
Wrapper
.
LONG
),
F_TYPE
(
'F'
,
float
.
class
,
Wrapper
.
FLOAT
),
D_TYPE
(
'D'
,
double
.
class
,
Wrapper
.
DOUBLE
),
// all primitive types
V_TYPE
(
'V'
,
void
.
class
,
Wrapper
.
VOID
);
// not valid in all contexts
static
final
BasicType
[]
ALL_TYPES
=
BasicType
.
values
();
static
final
BasicType
[]
ARG_TYPES
=
Arrays
.
copyOf
(
ALL_TYPES
,
ALL_TYPES
.
length
-
1
);
static
final
int
ARG_TYPE_LIMIT
=
ARG_TYPES
.
length
;
static
final
int
TYPE_LIMIT
=
ALL_TYPES
.
length
;
private
final
char
btChar
;
private
final
Class
<?>
btClass
;
private
final
Wrapper
btWrapper
;
private
BasicType
(
char
btChar
,
Class
<?>
btClass
,
Wrapper
wrapper
)
{
this
.
btChar
=
btChar
;
this
.
btClass
=
btClass
;
this
.
btWrapper
=
wrapper
;
}
char
basicTypeChar
()
{
return
btChar
;
}
Class
<?>
basicTypeClass
()
{
return
btClass
;
}
Wrapper
basicTypeWrapper
()
{
return
btWrapper
;
}
int
basicTypeSlots
()
{
return
btWrapper
.
stackSlots
();
}
static
BasicType
basicType
(
byte
type
)
{
return
ALL_TYPES
[
type
];
}
static
BasicType
basicType
(
char
type
)
{
switch
(
type
)
{
case
'L'
:
return
L_TYPE
;
case
'I'
:
return
I_TYPE
;
case
'J'
:
return
J_TYPE
;
case
'F'
:
return
F_TYPE
;
case
'D'
:
return
D_TYPE
;
case
'V'
:
return
V_TYPE
;
// all subword types are represented as ints
case
'Z'
:
case
'B'
:
case
'S'
:
case
'C'
:
return
I_TYPE
;
default
:
throw
newInternalError
(
"Unknown type char: '"
+
type
+
"'"
);
}
}
static
BasicType
basicType
(
Wrapper
type
)
{
char
c
=
type
.
basicTypeChar
();
return
basicType
(
c
);
}
static
BasicType
basicType
(
Class
<?>
type
)
{
if
(!
type
.
isPrimitive
())
return
L_TYPE
;
return
basicType
(
Wrapper
.
forPrimitiveType
(
type
));
}
static
char
basicTypeChar
(
Class
<?>
type
)
{
return
basicType
(
type
).
btChar
;
}
static
BasicType
[]
basicTypes
(
List
<
Class
<?>>
types
)
{
BasicType
[]
btypes
=
new
BasicType
[
types
.
size
()];
for
(
int
i
=
0
;
i
<
btypes
.
length
;
i
++)
{
btypes
[
i
]
=
basicType
(
types
.
get
(
i
));
}
return
btypes
;
}
static
BasicType
[]
basicTypes
(
String
types
)
{
BasicType
[]
btypes
=
new
BasicType
[
types
.
length
()];
for
(
int
i
=
0
;
i
<
btypes
.
length
;
i
++)
{
btypes
[
i
]
=
basicType
(
types
.
charAt
(
i
));
}
return
btypes
;
}
static
boolean
isBasicTypeChar
(
char
c
)
{
return
"LIJFDV"
.
indexOf
(
c
)
>=
0
;
}
static
boolean
isArgBasicTypeChar
(
char
c
)
{
return
"LIJFD"
.
indexOf
(
c
)
>=
0
;
}
static
{
assert
(
checkBasicType
());
}
private
static
boolean
checkBasicType
()
{
for
(
int
i
=
0
;
i
<
ARG_TYPE_LIMIT
;
i
++)
{
assert
ARG_TYPES
[
i
].
ordinal
()
==
i
;
assert
ARG_TYPES
[
i
]
==
ALL_TYPES
[
i
];
}
for
(
int
i
=
0
;
i
<
TYPE_LIMIT
;
i
++)
{
assert
ALL_TYPES
[
i
].
ordinal
()
==
i
;
}
assert
ALL_TYPES
[
TYPE_LIMIT
-
1
]
==
V_TYPE
;
assert
!
Arrays
.
asList
(
ARG_TYPES
).
contains
(
V_TYPE
);
return
true
;
}
}
LambdaForm
(
String
debugName
,
LambdaForm
(
String
debugName
,
int
arity
,
Name
[]
names
,
int
result
)
{
int
arity
,
Name
[]
names
,
int
result
)
{
assert
(
namesOK
(
arity
,
names
));
assert
(
namesOK
(
arity
,
names
));
this
.
arity
=
arity
;
this
.
arity
=
arity
;
this
.
result
=
fixResult
(
result
,
names
);
this
.
result
=
fixResult
(
result
,
names
);
this
.
names
=
names
.
clone
();
this
.
names
=
names
.
clone
();
this
.
debugName
=
debugName
;
this
.
debugName
=
fixDebugName
(
debugName
)
;
normalize
();
normalize
();
}
}
...
@@ -168,12 +274,12 @@ class LambdaForm {
...
@@ -168,12 +274,12 @@ class LambdaForm {
// Called only from getPreparedForm.
// Called only from getPreparedForm.
assert
(
isValidSignature
(
sig
));
assert
(
isValidSignature
(
sig
));
this
.
arity
=
signatureArity
(
sig
);
this
.
arity
=
signatureArity
(
sig
);
this
.
result
=
(
signatureReturn
(
sig
)
==
'V'
?
-
1
:
arity
);
this
.
result
=
(
signatureReturn
(
sig
)
==
V_TYPE
?
-
1
:
arity
);
this
.
names
=
buildEmptyNames
(
arity
,
sig
);
this
.
names
=
buildEmptyNames
(
arity
,
sig
);
this
.
debugName
=
"LF.zero"
;
this
.
debugName
=
"LF.zero"
;
assert
(
nameRefsAreLegal
());
assert
(
nameRefsAreLegal
());
assert
(
isEmpty
());
assert
(
isEmpty
());
assert
(
sig
.
equals
(
basicTypeSignature
()));
assert
(
sig
.
equals
(
basicTypeSignature
()))
:
sig
+
" != "
+
basicTypeSignature
()
;
}
}
private
static
Name
[]
buildEmptyNames
(
int
arity
,
String
basicTypeSignature
)
{
private
static
Name
[]
buildEmptyNames
(
int
arity
,
String
basicTypeSignature
)
{
...
@@ -181,24 +287,55 @@ class LambdaForm {
...
@@ -181,24 +287,55 @@ class LambdaForm {
int
resultPos
=
arity
+
1
;
// skip '_'
int
resultPos
=
arity
+
1
;
// skip '_'
if
(
arity
<
0
||
basicTypeSignature
.
length
()
!=
resultPos
+
1
)
if
(
arity
<
0
||
basicTypeSignature
.
length
()
!=
resultPos
+
1
)
throw
new
IllegalArgumentException
(
"bad arity for "
+
basicTypeSignature
);
throw
new
IllegalArgumentException
(
"bad arity for "
+
basicTypeSignature
);
int
numRes
=
(
basicType
Signature
.
charAt
(
resultPos
)
==
'V'
?
0
:
1
);
int
numRes
=
(
basicType
(
basicTypeSignature
.
charAt
(
resultPos
))
==
V_TYPE
?
0
:
1
);
Name
[]
names
=
arguments
(
numRes
,
basicTypeSignature
.
substring
(
0
,
arity
));
Name
[]
names
=
arguments
(
numRes
,
basicTypeSignature
.
substring
(
0
,
arity
));
for
(
int
i
=
0
;
i
<
numRes
;
i
++)
{
for
(
int
i
=
0
;
i
<
numRes
;
i
++)
{
names
[
arity
+
i
]
=
constantZero
(
arity
+
i
,
basicTypeSignature
.
charAt
(
resultPos
+
i
));
Name
zero
=
new
Name
(
constantZero
(
basicType
(
basicTypeSignature
.
charAt
(
resultPos
+
i
))));
names
[
arity
+
i
]
=
zero
.
newIndex
(
arity
+
i
);
}
}
return
names
;
return
names
;
}
}
private
static
int
fixResult
(
int
result
,
Name
[]
names
)
{
private
static
int
fixResult
(
int
result
,
Name
[]
names
)
{
if
(
result
>=
0
)
{
if
(
result
==
LAST_RESULT
)
if
(
names
[
result
].
type
==
'V'
)
result
=
names
.
length
-
1
;
// might still be void
return
-
1
;
if
(
result
>=
0
&&
names
[
result
].
type
==
V_TYPE
)
}
else
if
(
result
==
LAST_RESULT
)
{
result
=
VOID_RESULT
;
return
names
.
length
-
1
;
}
return
result
;
return
result
;
}
}
private
static
String
fixDebugName
(
String
debugName
)
{
if
(
DEBUG_NAME_COUNTERS
!=
null
)
{
int
under
=
debugName
.
indexOf
(
'_'
);
int
length
=
debugName
.
length
();
if
(
under
<
0
)
under
=
length
;
String
debugNameStem
=
debugName
.
substring
(
0
,
under
);
Integer
ctr
;
synchronized
(
DEBUG_NAME_COUNTERS
)
{
ctr
=
DEBUG_NAME_COUNTERS
.
get
(
debugNameStem
);
if
(
ctr
==
null
)
ctr
=
0
;
DEBUG_NAME_COUNTERS
.
put
(
debugNameStem
,
ctr
+
1
);
}
StringBuilder
buf
=
new
StringBuilder
(
debugNameStem
);
buf
.
append
(
'_'
);
int
leadingZero
=
buf
.
length
();
buf
.
append
((
int
)
ctr
);
for
(
int
i
=
buf
.
length
()
-
leadingZero
;
i
<
3
;
i
++)
buf
.
insert
(
leadingZero
,
'0'
);
if
(
under
<
length
)
{
++
under
;
// skip "_"
while
(
under
<
length
&&
Character
.
isDigit
(
debugName
.
charAt
(
under
)))
{
++
under
;
}
if
(
under
<
length
&&
debugName
.
charAt
(
under
)
==
'_'
)
++
under
;
if
(
under
<
length
)
buf
.
append
(
'_'
).
append
(
debugName
,
under
,
length
);
}
return
buf
.
toString
();
}
return
debugName
;
}
private
static
boolean
namesOK
(
int
arity
,
Name
[]
names
)
{
private
static
boolean
namesOK
(
int
arity
,
Name
[]
names
)
{
for
(
int
i
=
0
;
i
<
names
.
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
names
.
length
;
i
++)
{
Name
n
=
names
[
i
];
Name
n
=
names
[
i
];
...
@@ -294,14 +431,14 @@ class LambdaForm {
...
@@ -294,14 +431,14 @@ class LambdaForm {
// }
// }
/** Report the return type. */
/** Report the return type. */
char
returnType
()
{
BasicType
returnType
()
{
if
(
result
<
0
)
return
'V'
;
if
(
result
<
0
)
return
V_TYPE
;
Name
n
=
names
[
result
];
Name
n
=
names
[
result
];
return
n
.
type
;
return
n
.
type
;
}
}
/** Report the N-th argument type. */
/** Report the N-th argument type. */
char
parameterType
(
int
n
)
{
BasicType
parameterType
(
int
n
)
{
assert
(
n
<
arity
);
assert
(
n
<
arity
);
return
names
[
n
].
type
;
return
names
[
n
].
type
;
}
}
...
@@ -319,15 +456,15 @@ class LambdaForm {
...
@@ -319,15 +456,15 @@ class LambdaForm {
final
String
basicTypeSignature
()
{
final
String
basicTypeSignature
()
{
StringBuilder
buf
=
new
StringBuilder
(
arity
()
+
3
);
StringBuilder
buf
=
new
StringBuilder
(
arity
()
+
3
);
for
(
int
i
=
0
,
a
=
arity
();
i
<
a
;
i
++)
for
(
int
i
=
0
,
a
=
arity
();
i
<
a
;
i
++)
buf
.
append
(
parameterType
(
i
));
buf
.
append
(
parameterType
(
i
)
.
basicTypeChar
()
);
return
buf
.
append
(
'_'
).
append
(
returnType
()).
toString
();
return
buf
.
append
(
'_'
).
append
(
returnType
()
.
basicTypeChar
()
).
toString
();
}
}
static
int
signatureArity
(
String
sig
)
{
static
int
signatureArity
(
String
sig
)
{
assert
(
isValidSignature
(
sig
));
assert
(
isValidSignature
(
sig
));
return
sig
.
indexOf
(
'_'
);
return
sig
.
indexOf
(
'_'
);
}
}
static
char
signatureReturn
(
String
sig
)
{
static
BasicType
signatureReturn
(
String
sig
)
{
return
sig
.
charAt
(
signatureArity
(
sig
)+
1
);
return
basicType
(
sig
.
charAt
(
signatureArity
(
sig
)+
1
)
);
}
}
static
boolean
isValidSignature
(
String
sig
)
{
static
boolean
isValidSignature
(
String
sig
)
{
int
arity
=
sig
.
indexOf
(
'_'
);
int
arity
=
sig
.
indexOf
(
'_'
);
...
@@ -339,27 +476,15 @@ class LambdaForm {
...
@@ -339,27 +476,15 @@ class LambdaForm {
char
c
=
sig
.
charAt
(
i
);
char
c
=
sig
.
charAt
(
i
);
if
(
c
==
'V'
)
if
(
c
==
'V'
)
return
(
i
==
siglen
-
1
&&
arity
==
siglen
-
2
);
return
(
i
==
siglen
-
1
&&
arity
==
siglen
-
2
);
if
(
ALL_TYPES
.
indexOf
(
c
)
<
0
)
return
false
;
// must be [LIJFD]
if
(
!
isArgBasicTypeChar
(
c
)
)
return
false
;
// must be [LIJFD]
}
}
return
true
;
// [LIJFD]*_[LIJFDV]
return
true
;
// [LIJFD]*_[LIJFDV]
}
}
static
Class
<?>
typeClass
(
char
t
)
{
switch
(
t
)
{
case
'I'
:
return
int
.
class
;
case
'J'
:
return
long
.
class
;
case
'F'
:
return
float
.
class
;
case
'D'
:
return
double
.
class
;
case
'L'
:
return
Object
.
class
;
case
'V'
:
return
void
.
class
;
default
:
assert
false
;
}
return
null
;
}
static
MethodType
signatureType
(
String
sig
)
{
static
MethodType
signatureType
(
String
sig
)
{
Class
<?>[]
ptypes
=
new
Class
<?>[
signatureArity
(
sig
)];
Class
<?>[]
ptypes
=
new
Class
<?>[
signatureArity
(
sig
)];
for
(
int
i
=
0
;
i
<
ptypes
.
length
;
i
++)
for
(
int
i
=
0
;
i
<
ptypes
.
length
;
i
++)
ptypes
[
i
]
=
typeClass
(
sig
.
charAt
(
i
))
;
ptypes
[
i
]
=
basicType
(
sig
.
charAt
(
i
)).
btClass
;
Class
<?>
rtype
=
typeClass
(
signatureReturn
(
sig
))
;
Class
<?>
rtype
=
signatureReturn
(
sig
).
btClass
;
return
MethodType
.
methodType
(
rtype
,
ptypes
);
return
MethodType
.
methodType
(
rtype
,
ptypes
);
}
}
...
@@ -543,21 +668,21 @@ class LambdaForm {
...
@@ -543,21 +668,21 @@ class LambdaForm {
assert
(
mt
.
parameterCount
()
==
arity
-
1
);
assert
(
mt
.
parameterCount
()
==
arity
-
1
);
for
(
int
i
=
0
;
i
<
av
.
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
av
.
length
;
i
++)
{
Class
<?>
pt
=
(
i
==
0
?
MethodHandle
.
class
:
mt
.
parameterType
(
i
-
1
));
Class
<?>
pt
=
(
i
==
0
?
MethodHandle
.
class
:
mt
.
parameterType
(
i
-
1
));
assert
(
valueMatches
(
sig
.
charAt
(
i
),
pt
,
av
[
i
]));
assert
(
valueMatches
(
basicType
(
sig
.
charAt
(
i
)
),
pt
,
av
[
i
]));
}
}
return
true
;
return
true
;
}
}
private
static
boolean
valueMatches
(
char
tc
,
Class
<?>
type
,
Object
x
)
{
private
static
boolean
valueMatches
(
BasicType
tc
,
Class
<?>
type
,
Object
x
)
{
// The following line is needed because (...)void method handles can use non-void invokers
// The following line is needed because (...)void method handles can use non-void invokers
if
(
type
==
void
.
class
)
tc
=
'V'
;
// can drop any kind of value
if
(
type
==
void
.
class
)
tc
=
V_TYPE
;
// can drop any kind of value
assert
tc
==
basicType
(
type
)
:
tc
+
" == basicType("
+
type
+
")="
+
basicType
(
type
);
assert
tc
==
basicType
(
type
)
:
tc
+
" == basicType("
+
type
+
")="
+
basicType
(
type
);
switch
(
tc
)
{
switch
(
tc
)
{
case
'I'
:
assert
checkInt
(
type
,
x
)
:
"checkInt("
+
type
+
","
+
x
+
")"
;
break
;
case
I_TYPE
:
assert
checkInt
(
type
,
x
)
:
"checkInt("
+
type
+
","
+
x
+
")"
;
break
;
case
'J'
:
assert
x
instanceof
Long
:
"instanceof Long: "
+
x
;
break
;
case
J_TYPE
:
assert
x
instanceof
Long
:
"instanceof Long: "
+
x
;
break
;
case
'F'
:
assert
x
instanceof
Float
:
"instanceof Float: "
+
x
;
break
;
case
F_TYPE
:
assert
x
instanceof
Float
:
"instanceof Float: "
+
x
;
break
;
case
'D'
:
assert
x
instanceof
Double
:
"instanceof Double: "
+
x
;
break
;
case
D_TYPE
:
assert
x
instanceof
Double
:
"instanceof Double: "
+
x
;
break
;
case
'L'
:
assert
checkRef
(
type
,
x
)
:
"checkRef("
+
type
+
","
+
x
+
")"
;
break
;
case
L_TYPE
:
assert
checkRef
(
type
,
x
)
:
"checkRef("
+
type
+
","
+
x
+
")"
;
break
;
case
'V'
:
break
;
// allow anything here; will be dropped
case
V_TYPE
:
break
;
// allow anything here; will be dropped
default
:
assert
(
false
);
default
:
assert
(
false
);
}
}
return
true
;
return
true
;
...
@@ -736,7 +861,7 @@ class LambdaForm {
...
@@ -736,7 +861,7 @@ class LambdaForm {
* The first parameter to a LambdaForm, a0:L, always represents the form's method handle, so 0 is not
* The first parameter to a LambdaForm, a0:L, always represents the form's method handle, so 0 is not
* accepted as valid.
* accepted as valid.
*/
*/
LambdaForm
bindImmediate
(
int
pos
,
char
basicType
,
Object
value
)
{
LambdaForm
bindImmediate
(
int
pos
,
BasicType
basicType
,
Object
value
)
{
// must be an argument, and the types must match
// must be an argument, and the types must match
assert
pos
>
0
&&
pos
<
arity
&&
names
[
pos
].
type
==
basicType
&&
Name
.
typesMatch
(
basicType
,
value
);
assert
pos
>
0
&&
pos
<
arity
&&
names
[
pos
].
type
==
basicType
&&
Name
.
typesMatch
(
basicType
,
value
);
...
@@ -782,8 +907,8 @@ class LambdaForm {
...
@@ -782,8 +907,8 @@ class LambdaForm {
LambdaForm
bind
(
int
namePos
,
BoundMethodHandle
.
SpeciesData
oldData
)
{
LambdaForm
bind
(
int
namePos
,
BoundMethodHandle
.
SpeciesData
oldData
)
{
Name
name
=
names
[
namePos
];
Name
name
=
names
[
namePos
];
BoundMethodHandle
.
SpeciesData
newData
=
oldData
.
extendWith
Type
(
name
.
type
);
BoundMethodHandle
.
SpeciesData
newData
=
oldData
.
extendWith
(
name
.
type
);
return
bind
(
name
,
new
Data
.
getterName
(
names
[
0
],
oldData
.
fieldCount
()
),
oldData
,
newData
);
return
bind
(
name
,
new
Name
(
newData
.
getterFunction
(
oldData
.
fieldCount
()),
names
[
0
]
),
oldData
,
newData
);
}
}
LambdaForm
bind
(
Name
name
,
Name
binding
,
LambdaForm
bind
(
Name
name
,
Name
binding
,
BoundMethodHandle
.
SpeciesData
oldData
,
BoundMethodHandle
.
SpeciesData
oldData
,
...
@@ -874,7 +999,7 @@ class LambdaForm {
...
@@ -874,7 +999,7 @@ class LambdaForm {
return
false
;
return
false
;
}
}
LambdaForm
addArguments
(
int
pos
,
char
...
types
)
{
LambdaForm
addArguments
(
int
pos
,
BasicType
...
types
)
{
assert
(
pos
<=
arity
);
assert
(
pos
<=
arity
);
int
length
=
names
.
length
;
int
length
=
names
.
length
;
int
inTypes
=
types
.
length
;
int
inTypes
=
types
.
length
;
...
@@ -895,13 +1020,10 @@ class LambdaForm {
...
@@ -895,13 +1020,10 @@ class LambdaForm {
}
}
LambdaForm
addArguments
(
int
pos
,
List
<
Class
<?>>
types
)
{
LambdaForm
addArguments
(
int
pos
,
List
<
Class
<?>>
types
)
{
char
[]
basicTypes
=
new
char
[
types
.
size
()];
return
addArguments
(
pos
,
basicTypes
(
types
));
for
(
int
i
=
0
;
i
<
basicTypes
.
length
;
i
++)
basicTypes
[
i
]
=
basicType
(
types
.
get
(
i
));
return
addArguments
(
pos
,
basicTypes
);
}
}
LambdaForm
permuteArguments
(
int
skip
,
int
[]
reorder
,
char
[]
types
)
{
LambdaForm
permuteArguments
(
int
skip
,
int
[]
reorder
,
BasicType
[]
types
)
{
// Note: When inArg = reorder[outArg], outArg is fed by a copy of inArg.
// Note: When inArg = reorder[outArg], outArg is fed by a copy of inArg.
// The types are the types of the new (incoming) arguments.
// The types are the types of the new (incoming) arguments.
int
length
=
names
.
length
;
int
length
=
names
.
length
;
...
@@ -960,7 +1082,7 @@ class LambdaForm {
...
@@ -960,7 +1082,7 @@ class LambdaForm {
return
new
LambdaForm
(
debugName
,
arity2
,
names2
,
result2
);
return
new
LambdaForm
(
debugName
,
arity2
,
names2
,
result2
);
}
}
static
boolean
permutedTypesMatch
(
int
[]
reorder
,
char
[]
types
,
Name
[]
names
,
int
skip
)
{
static
boolean
permutedTypesMatch
(
int
[]
reorder
,
BasicType
[]
types
,
Name
[]
names
,
int
skip
)
{
int
inTypes
=
types
.
length
;
int
inTypes
=
types
.
length
;
int
outArgs
=
reorder
.
length
;
int
outArgs
=
reorder
.
length
;
for
(
int
i
=
0
;
i
<
outArgs
;
i
++)
{
for
(
int
i
=
0
;
i
<
outArgs
;
i
++)
{
...
@@ -1044,7 +1166,7 @@ class LambdaForm {
...
@@ -1044,7 +1166,7 @@ class LambdaForm {
String
sig
=
m
.
getName
().
substring
(
"invoke_"
.
length
());
String
sig
=
m
.
getName
().
substring
(
"invoke_"
.
length
());
int
arity
=
LambdaForm
.
signatureArity
(
sig
);
int
arity
=
LambdaForm
.
signatureArity
(
sig
);
MethodType
srcType
=
MethodType
.
genericMethodType
(
arity
);
MethodType
srcType
=
MethodType
.
genericMethodType
(
arity
);
if
(
LambdaForm
.
signatureReturn
(
sig
)
==
'V'
)
if
(
LambdaForm
.
signatureReturn
(
sig
)
==
V_TYPE
)
srcType
=
srcType
.
changeReturnType
(
void
.
class
);
srcType
=
srcType
.
changeReturnType
(
void
.
class
);
MethodTypeForm
typeForm
=
srcType
.
form
();
MethodTypeForm
typeForm
=
srcType
.
form
();
typeForm
.
namedFunctionInvoker
=
DirectMethodHandle
.
make
(
m
);
typeForm
.
namedFunctionInvoker
=
DirectMethodHandle
.
make
(
m
);
...
@@ -1134,7 +1256,7 @@ class LambdaForm {
...
@@ -1134,7 +1256,7 @@ class LambdaForm {
MethodHandle
mh2
=
typeForm
.
namedFunctionInvoker
;
MethodHandle
mh2
=
typeForm
.
namedFunctionInvoker
;
if
(
mh2
!=
null
)
return
mh2
;
// benign race
if
(
mh2
!=
null
)
return
mh2
;
// benign race
if
(!
mh
.
type
().
equals
(
INVOKER_METHOD_TYPE
))
if
(!
mh
.
type
().
equals
(
INVOKER_METHOD_TYPE
))
throw
new
InternalError
(
mh
.
debugString
());
throw
newInternalError
(
mh
.
debugString
());
return
typeForm
.
namedFunctionInvoker
=
mh
;
return
typeForm
.
namedFunctionInvoker
=
mh
;
}
}
...
@@ -1193,11 +1315,6 @@ class LambdaForm {
...
@@ -1193,11 +1315,6 @@ class LambdaForm {
return
true
;
return
true
;
}
}
String
basicTypeSignature
()
{
//return LambdaForm.basicTypeSignature(resolvedHandle.type());
return
LambdaForm
.
basicTypeSignature
(
methodType
());
}
MethodType
methodType
()
{
MethodType
methodType
()
{
if
(
resolvedHandle
!=
null
)
if
(
resolvedHandle
!=
null
)
return
resolvedHandle
.
type
();
return
resolvedHandle
.
type
();
...
@@ -1224,18 +1341,15 @@ class LambdaForm {
...
@@ -1224,18 +1341,15 @@ class LambdaForm {
return
(
member
==
null
)
?
null
:
member
.
getDeclaringClass
();
return
(
member
==
null
)
?
null
:
member
.
getDeclaringClass
();
}
}
char
returnType
()
{
BasicType
returnType
()
{
return
basicType
(
methodType
().
returnType
());
return
basicType
(
methodType
().
returnType
());
}
}
char
parameterType
(
int
n
)
{
BasicType
parameterType
(
int
n
)
{
return
basicType
(
methodType
().
parameterType
(
n
));
return
basicType
(
methodType
().
parameterType
(
n
));
}
}
int
arity
()
{
int
arity
()
{
//int siglen = member.getMethodType().parameterCount();
//if (!member.isStatic()) siglen += 1;
//return siglen;
return
methodType
().
parameterCount
();
return
methodType
().
parameterCount
();
}
}
...
@@ -1243,44 +1357,63 @@ class LambdaForm {
...
@@ -1243,44 +1357,63 @@ class LambdaForm {
if
(
member
==
null
)
return
String
.
valueOf
(
resolvedHandle
);
if
(
member
==
null
)
return
String
.
valueOf
(
resolvedHandle
);
return
member
.
getDeclaringClass
().
getSimpleName
()+
"."
+
member
.
getName
();
return
member
.
getDeclaringClass
().
getSimpleName
()+
"."
+
member
.
getName
();
}
}
}
void
resolve
()
{
public
boolean
isIdentity
()
{
for
(
Name
n
:
names
)
n
.
resolve
(
);
return
this
.
equals
(
identity
(
returnType
())
);
}
}
public
static
char
basicType
(
Class
<?>
type
)
{
public
boolean
isConstantZero
()
{
char
c
=
Wrapper
.
basicTypeChar
(
type
);
return
this
.
equals
(
constantZero
(
returnType
()));
if
(
"ZBSC"
.
indexOf
(
c
)
>=
0
)
c
=
'I'
;
assert
(
"LIJFDV"
.
indexOf
(
c
)
>=
0
);
return
c
;
}
public
static
char
[]
basicTypes
(
List
<
Class
<?>>
types
)
{
char
[]
btypes
=
new
char
[
types
.
size
()];
for
(
int
i
=
0
;
i
<
btypes
.
length
;
i
++)
{
btypes
[
i
]
=
basicType
(
types
.
get
(
i
));
}
}
return
btypes
;
}
}
public
static
String
basicTypeSignature
(
MethodType
type
)
{
public
static
String
basicTypeSignature
(
MethodType
type
)
{
char
[]
sig
=
new
char
[
type
.
parameterCount
()
+
2
];
char
[]
sig
=
new
char
[
type
.
parameterCount
()
+
2
];
int
sigp
=
0
;
int
sigp
=
0
;
for
(
Class
<?>
pt
:
type
.
parameterList
())
{
for
(
Class
<?>
pt
:
type
.
parameterList
())
{
sig
[
sigp
++]
=
basicType
(
pt
);
sig
[
sigp
++]
=
basicType
Char
(
pt
);
}
}
sig
[
sigp
++]
=
'_'
;
sig
[
sigp
++]
=
'_'
;
sig
[
sigp
++]
=
basicType
(
type
.
returnType
());
sig
[
sigp
++]
=
basicType
Char
(
type
.
returnType
());
assert
(
sigp
==
sig
.
length
);
assert
(
sigp
==
sig
.
length
);
return
String
.
valueOf
(
sig
);
return
String
.
valueOf
(
sig
);
}
}
public
static
String
shortenSignature
(
String
signature
)
{
// Hack to make signatures more readable when they show up in method names.
final
int
NO_CHAR
=
-
1
,
MIN_RUN
=
3
;
int
c0
,
c1
=
NO_CHAR
,
c1reps
=
0
;
StringBuilder
buf
=
null
;
int
len
=
signature
.
length
();
if
(
len
<
MIN_RUN
)
return
signature
;
for
(
int
i
=
0
;
i
<=
len
;
i
++)
{
// shift in the next char:
c0
=
c1
;
c1
=
(
i
==
len
?
NO_CHAR
:
signature
.
charAt
(
i
));
if
(
c1
==
c0
)
{
++
c1reps
;
continue
;
}
// shift in the next count:
int
c0reps
=
c1reps
;
c1reps
=
1
;
// end of a character run
if
(
c0reps
<
MIN_RUN
)
{
if
(
buf
!=
null
)
{
while
(--
c0reps
>=
0
)
buf
.
append
((
char
)
c0
);
}
continue
;
}
// found three or more in a row
if
(
buf
==
null
)
buf
=
new
StringBuilder
().
append
(
signature
,
0
,
i
-
c0reps
);
buf
.
append
((
char
)
c0
).
append
(
c0reps
);
}
return
(
buf
==
null
)
?
signature
:
buf
.
toString
();
}
static
final
class
Name
{
static
final
class
Name
{
final
char
type
;
final
BasicType
type
;
private
short
index
;
private
short
index
;
final
NamedFunction
function
;
final
NamedFunction
function
;
@Stable
final
Object
[]
arguments
;
@Stable
final
Object
[]
arguments
;
private
Name
(
int
index
,
char
type
,
NamedFunction
function
,
Object
[]
arguments
)
{
private
Name
(
int
index
,
BasicType
type
,
NamedFunction
function
,
Object
[]
arguments
)
{
this
.
index
=
(
short
)
index
;
this
.
index
=
(
short
)
index
;
this
.
type
=
type
;
this
.
type
=
type
;
this
.
function
=
function
;
this
.
function
=
function
;
...
@@ -1292,7 +1425,7 @@ class LambdaForm {
...
@@ -1292,7 +1425,7 @@ class LambdaForm {
}
}
Name
(
MethodType
functionType
,
Object
...
arguments
)
{
Name
(
MethodType
functionType
,
Object
...
arguments
)
{
this
(
new
NamedFunction
(
functionType
),
arguments
);
this
(
new
NamedFunction
(
functionType
),
arguments
);
assert
(
arguments
[
0
]
instanceof
Name
&&
((
Name
)
arguments
[
0
]).
type
==
'L'
);
assert
(
arguments
[
0
]
instanceof
Name
&&
((
Name
)
arguments
[
0
]).
type
==
L_TYPE
);
}
}
Name
(
MemberName
function
,
Object
...
arguments
)
{
Name
(
MemberName
function
,
Object
...
arguments
)
{
this
(
new
NamedFunction
(
function
),
arguments
);
this
(
new
NamedFunction
(
function
),
arguments
);
...
@@ -1303,14 +1436,14 @@ class LambdaForm {
...
@@ -1303,14 +1436,14 @@ class LambdaForm {
for
(
int
i
=
0
;
i
<
arguments
.
length
;
i
++)
for
(
int
i
=
0
;
i
<
arguments
.
length
;
i
++)
assert
(
typesMatch
(
function
.
parameterType
(
i
),
arguments
[
i
]))
:
"types don't match: function.parameterType("
+
i
+
")="
+
function
.
parameterType
(
i
)
+
", arguments["
+
i
+
"]="
+
arguments
[
i
]
+
" in "
+
debugString
();
assert
(
typesMatch
(
function
.
parameterType
(
i
),
arguments
[
i
]))
:
"types don't match: function.parameterType("
+
i
+
")="
+
function
.
parameterType
(
i
)
+
", arguments["
+
i
+
"]="
+
arguments
[
i
]
+
" in "
+
debugString
();
}
}
Name
(
int
index
,
char
type
)
{
/** Create a raw parameter of the given type, with an expected index. */
Name
(
int
index
,
BasicType
type
)
{
this
(
index
,
type
,
null
,
null
);
this
(
index
,
type
,
null
,
null
);
}
}
Name
(
char
type
)
{
/** Create a raw parameter of the given type. */
this
(-
1
,
type
);
Name
(
BasicType
type
)
{
this
(-
1
,
type
);
}
}
char
type
()
{
return
type
;
}
BasicType
type
()
{
return
type
;
}
int
index
()
{
return
index
;
}
int
index
()
{
return
index
;
}
boolean
initIndex
(
int
i
)
{
boolean
initIndex
(
int
i
)
{
if
(
index
!=
i
)
{
if
(
index
!=
i
)
{
...
@@ -1319,7 +1452,9 @@ class LambdaForm {
...
@@ -1319,7 +1452,9 @@ class LambdaForm {
}
}
return
true
;
return
true
;
}
}
char
typeChar
()
{
return
type
.
btChar
;
}
void
resolve
()
{
void
resolve
()
{
if
(
function
!=
null
)
if
(
function
!=
null
)
...
@@ -1397,18 +1532,18 @@ class LambdaForm {
...
@@ -1397,18 +1532,18 @@ class LambdaForm {
return
function
==
null
;
return
function
==
null
;
}
}
boolean
isConstantZero
()
{
boolean
isConstantZero
()
{
return
!
isParam
()
&&
arguments
.
length
==
0
&&
function
.
equals
(
constantZero
(
0
,
type
).
function
);
return
!
isParam
()
&&
arguments
.
length
==
0
&&
function
.
isConstantZero
(
);
}
}
public
String
toString
()
{
public
String
toString
()
{
return
(
isParam
()?
"a"
:
"t"
)+(
index
>=
0
?
index
:
System
.
identityHashCode
(
this
))+
":"
+
type
;
return
(
isParam
()?
"a"
:
"t"
)+(
index
>=
0
?
index
:
System
.
identityHashCode
(
this
))+
":"
+
type
Char
()
;
}
}
public
String
debugString
()
{
public
String
debugString
()
{
String
s
=
toString
();
String
s
=
toString
();
return
(
function
==
null
)
?
s
:
s
+
"="
+
exprString
();
return
(
function
==
null
)
?
s
:
s
+
"="
+
exprString
();
}
}
public
String
exprString
()
{
public
String
exprString
()
{
if
(
function
==
null
)
return
"null"
;
if
(
function
==
null
)
return
toString
()
;
StringBuilder
buf
=
new
StringBuilder
(
function
.
toString
());
StringBuilder
buf
=
new
StringBuilder
(
function
.
toString
());
buf
.
append
(
"("
);
buf
.
append
(
"("
);
String
cma
=
""
;
String
cma
=
""
;
...
@@ -1423,17 +1558,17 @@ class LambdaForm {
...
@@ -1423,17 +1558,17 @@ class LambdaForm {
return
buf
.
toString
();
return
buf
.
toString
();
}
}
private
static
boolean
typesMatch
(
char
parameterType
,
Object
object
)
{
static
boolean
typesMatch
(
BasicType
parameterType
,
Object
object
)
{
if
(
object
instanceof
Name
)
{
if
(
object
instanceof
Name
)
{
return
((
Name
)
object
).
type
==
parameterType
;
return
((
Name
)
object
).
type
==
parameterType
;
}
}
switch
(
parameterType
)
{
switch
(
parameterType
)
{
case
'I'
:
return
object
instanceof
Integer
;
case
I_TYPE
:
return
object
instanceof
Integer
;
case
'J'
:
return
object
instanceof
Long
;
case
J_TYPE
:
return
object
instanceof
Long
;
case
'F'
:
return
object
instanceof
Float
;
case
F_TYPE
:
return
object
instanceof
Float
;
case
'D'
:
return
object
instanceof
Double
;
case
D_TYPE
:
return
object
instanceof
Double
;
}
}
assert
(
parameterType
==
'L'
);
assert
(
parameterType
==
L_TYPE
);
return
true
;
return
true
;
}
}
...
@@ -1510,7 +1645,7 @@ class LambdaForm {
...
@@ -1510,7 +1645,7 @@ class LambdaForm {
@Override
@Override
public
int
hashCode
()
{
public
int
hashCode
()
{
if
(
isParam
())
if
(
isParam
())
return
index
|
(
type
<<
8
);
return
index
|
(
type
.
ordinal
()
<<
8
);
return
function
.
hashCode
()
^
Arrays
.
hashCode
(
arguments
);
return
function
.
hashCode
()
^
Arrays
.
hashCode
(
arguments
);
}
}
}
}
...
@@ -1545,10 +1680,12 @@ class LambdaForm {
...
@@ -1545,10 +1680,12 @@ class LambdaForm {
}
}
static
Name
argument
(
int
which
,
char
type
)
{
static
Name
argument
(
int
which
,
char
type
)
{
int
tn
=
ALL_TYPES
.
indexOf
(
type
);
return
argument
(
which
,
basicType
(
type
));
if
(
tn
<
0
||
which
>=
INTERNED_ARGUMENT_LIMIT
)
}
static
Name
argument
(
int
which
,
BasicType
type
)
{
if
(
which
>=
INTERNED_ARGUMENT_LIMIT
)
return
new
Name
(
which
,
type
);
return
new
Name
(
which
,
type
);
return
INTERNED_ARGUMENTS
[
t
n
][
which
];
return
INTERNED_ARGUMENTS
[
t
ype
.
ordinal
()
][
which
];
}
}
static
Name
internArgument
(
Name
n
)
{
static
Name
internArgument
(
Name
n
)
{
assert
(
n
.
isParam
())
:
"not param: "
+
n
;
assert
(
n
.
isParam
())
:
"not param: "
+
n
;
...
@@ -1590,57 +1727,119 @@ class LambdaForm {
...
@@ -1590,57 +1727,119 @@ class LambdaForm {
names
[
i
]
=
argument
(
i
,
basicType
(
types
.
parameterType
(
i
)));
names
[
i
]
=
argument
(
i
,
basicType
(
types
.
parameterType
(
i
)));
return
names
;
return
names
;
}
}
static
final
String
ALL_TYPES
=
"LIJFD"
;
// omit V, not an argument type
static
final
int
INTERNED_ARGUMENT_LIMIT
=
10
;
static
final
int
INTERNED_ARGUMENT_LIMIT
=
10
;
private
static
final
Name
[][]
INTERNED_ARGUMENTS
private
static
final
Name
[][]
INTERNED_ARGUMENTS
=
new
Name
[
A
LL_TYPES
.
length
()
][
INTERNED_ARGUMENT_LIMIT
];
=
new
Name
[
A
RG_TYPE_LIMIT
][
INTERNED_ARGUMENT_LIMIT
];
static
{
static
{
for
(
int
tn
=
0
;
tn
<
ALL_TYPES
.
length
();
tn
++
)
{
for
(
BasicType
type
:
BasicType
.
ARG_TYPES
)
{
for
(
int
i
=
0
;
i
<
INTERNED_ARGUMENTS
[
tn
].
length
;
i
++)
{
int
ord
=
type
.
ordinal
();
char
type
=
ALL_TYPES
.
charAt
(
tn
);
for
(
int
i
=
0
;
i
<
INTERNED_ARGUMENTS
[
ord
].
length
;
i
++)
{
INTERNED_ARGUMENTS
[
tn
][
i
]
=
new
Name
(
i
,
type
);
INTERNED_ARGUMENTS
[
ord
][
i
]
=
new
Name
(
i
,
type
);
}
}
}
}
}
}
private
static
final
MemberName
.
Factory
IMPL_NAMES
=
MemberName
.
getFactory
();
private
static
final
MemberName
.
Factory
IMPL_NAMES
=
MemberName
.
getFactory
();
static
Name
constantZero
(
int
which
,
char
type
)
{
static
LambdaForm
identityForm
(
BasicType
type
)
{
return
CONSTANT_ZERO
[
ALL_TYPES
.
indexOf
(
type
)].
newIndex
(
which
);
return
LF_identityForm
[
type
.
ordinal
()];
}
}
private
static
final
Name
[]
CONSTANT_ZERO
static
LambdaForm
zeroForm
(
BasicType
type
)
{
=
new
Name
[
ALL_TYPES
.
length
()];
return
LF_zeroForm
[
type
.
ordinal
()];
static
{
}
for
(
int
tn
=
0
;
tn
<
ALL_TYPES
.
length
();
tn
++)
{
static
NamedFunction
identity
(
BasicType
type
)
{
char
bt
=
ALL_TYPES
.
charAt
(
tn
);
return
NF_identity
[
type
.
ordinal
()];
Wrapper
wrap
=
Wrapper
.
forBasicType
(
bt
);
}
MemberName
zmem
=
new
MemberName
(
LambdaForm
.
class
,
"zero"
+
bt
,
MethodType
.
methodType
(
wrap
.
primitiveType
()),
REF_invokeStatic
);
static
NamedFunction
constantZero
(
BasicType
type
)
{
return
NF_zero
[
type
.
ordinal
()];
}
private
static
final
LambdaForm
[]
LF_identityForm
=
new
LambdaForm
[
TYPE_LIMIT
];
private
static
final
LambdaForm
[]
LF_zeroForm
=
new
LambdaForm
[
TYPE_LIMIT
];
private
static
final
NamedFunction
[]
NF_identity
=
new
NamedFunction
[
TYPE_LIMIT
];
private
static
final
NamedFunction
[]
NF_zero
=
new
NamedFunction
[
TYPE_LIMIT
];
private
static
void
createIdentityForms
()
{
for
(
BasicType
type
:
BasicType
.
ALL_TYPES
)
{
int
ord
=
type
.
ordinal
();
char
btChar
=
type
.
basicTypeChar
();
boolean
isVoid
=
(
type
==
V_TYPE
);
Class
<?>
btClass
=
type
.
btClass
;
MethodType
zeType
=
MethodType
.
methodType
(
btClass
);
MethodType
idType
=
isVoid
?
zeType
:
zeType
.
appendParameterTypes
(
btClass
);
// Look up some symbolic names. It might not be necessary to have these,
// but if we need to emit direct references to bytecodes, it helps.
// Zero is built from a call to an identity function with a constant zero input.
MemberName
idMem
=
new
MemberName
(
LambdaForm
.
class
,
"identity_"
+
btChar
,
idType
,
REF_invokeStatic
);
MemberName
zeMem
=
new
MemberName
(
LambdaForm
.
class
,
"zero_"
+
btChar
,
zeType
,
REF_invokeStatic
);
try
{
try
{
zmem
=
IMPL_NAMES
.
resolveOrFail
(
REF_invokeStatic
,
zmem
,
null
,
NoSuchMethodException
.
class
);
zeMem
=
IMPL_NAMES
.
resolveOrFail
(
REF_invokeStatic
,
zeMem
,
null
,
NoSuchMethodException
.
class
);
idMem
=
IMPL_NAMES
.
resolveOrFail
(
REF_invokeStatic
,
idMem
,
null
,
NoSuchMethodException
.
class
);
}
catch
(
IllegalAccessException
|
NoSuchMethodException
ex
)
{
}
catch
(
IllegalAccessException
|
NoSuchMethodException
ex
)
{
throw
newInternalError
(
ex
);
throw
newInternalError
(
ex
);
}
}
NamedFunction
zcon
=
new
NamedFunction
(
zmem
);
Name
n
=
new
Name
(
zcon
).
newIndex
(
0
);
NamedFunction
idFun
=
new
NamedFunction
(
idMem
);
assert
(
n
.
type
==
ALL_TYPES
.
charAt
(
tn
));
LambdaForm
idForm
;
CONSTANT_ZERO
[
tn
]
=
n
;
if
(
isVoid
)
{
assert
(
n
.
isConstantZero
());
Name
[]
idNames
=
new
Name
[]
{
argument
(
0
,
L_TYPE
)
};
idForm
=
new
LambdaForm
(
idMem
.
getName
(),
1
,
idNames
,
VOID_RESULT
);
}
else
{
Name
[]
idNames
=
new
Name
[]
{
argument
(
0
,
L_TYPE
),
argument
(
1
,
type
)
};
idForm
=
new
LambdaForm
(
idMem
.
getName
(),
2
,
idNames
,
1
);
}
LF_identityForm
[
ord
]
=
idForm
;
NF_identity
[
ord
]
=
idFun
;
NamedFunction
zeFun
=
new
NamedFunction
(
zeMem
);
LambdaForm
zeForm
;
if
(
isVoid
)
{
zeForm
=
idForm
;
}
else
{
Object
zeValue
=
Wrapper
.
forBasicType
(
btChar
).
zero
();
Name
[]
zeNames
=
new
Name
[]
{
argument
(
0
,
L_TYPE
),
new
Name
(
idFun
,
zeValue
)
};
zeForm
=
new
LambdaForm
(
zeMem
.
getName
(),
1
,
zeNames
,
1
);
}
LF_zeroForm
[
ord
]
=
zeForm
;
NF_zero
[
ord
]
=
zeFun
;
assert
(
idFun
.
isIdentity
());
assert
(
zeFun
.
isConstantZero
());
assert
(
new
Name
(
zeFun
).
isConstantZero
());
}
}
}
// Avoid appealing to ValueConversions at bootstrap time:
// Do this in a separate pass, so that SimpleMethodHandle.make can see the tables.
private
static
int
zeroI
()
{
return
0
;
}
for
(
BasicType
type
:
BasicType
.
ALL_TYPES
)
{
private
static
long
zeroJ
()
{
return
0
;
}
int
ord
=
type
.
ordinal
();
private
static
float
zeroF
()
{
return
0
;
}
NamedFunction
idFun
=
NF_identity
[
ord
];
private
static
double
zeroD
()
{
return
0
;
}
LambdaForm
idForm
=
LF_identityForm
[
ord
];
private
static
Object
zeroL
()
{
return
null
;
}
MemberName
idMem
=
idFun
.
member
;
idFun
.
resolvedHandle
=
SimpleMethodHandle
.
make
(
idMem
.
getInvocationType
(),
idForm
);
// Put this last, so that previous static inits can run before.
NamedFunction
zeFun
=
NF_zero
[
ord
];
static
{
LambdaForm
zeForm
=
LF_zeroForm
[
ord
];
if
(
USE_PREDEFINED_INTERPRET_METHODS
)
MemberName
zeMem
=
zeFun
.
member
;
PREPARED_FORMS
.
putAll
(
computeInitialPreparedForms
());
zeFun
.
resolvedHandle
=
SimpleMethodHandle
.
make
(
zeMem
.
getInvocationType
(),
zeForm
);
assert
(
idFun
.
isIdentity
());
assert
(
zeFun
.
isConstantZero
());
assert
(
new
Name
(
zeFun
).
isConstantZero
());
}
}
}
// Avoid appealing to ValueConversions at bootstrap time:
private
static
int
identity_I
(
int
x
)
{
return
x
;
}
private
static
long
identity_J
(
long
x
)
{
return
x
;
}
private
static
float
identity_F
(
float
x
)
{
return
x
;
}
private
static
double
identity_D
(
double
x
)
{
return
x
;
}
private
static
Object
identity_L
(
Object
x
)
{
return
x
;
}
private
static
void
identity_V
()
{
return
;
}
// same as zeroV, but that's OK
private
static
int
zero_I
()
{
return
0
;
}
private
static
long
zero_J
()
{
return
0
;
}
private
static
float
zero_F
()
{
return
0
;
}
private
static
double
zero_D
()
{
return
0
;
}
private
static
Object
zero_L
()
{
return
null
;
}
private
static
void
zero_V
()
{
return
;
}
/**
/**
* Internal marker for byte-compiled LambdaForms.
* Internal marker for byte-compiled LambdaForms.
*/
*/
...
@@ -1690,7 +1889,21 @@ class LambdaForm {
...
@@ -1690,7 +1889,21 @@ class LambdaForm {
static final native Object linkToInterface(Object x1, MemberName mn) throws Throwable;
static final native Object linkToInterface(Object x1, MemberName mn) throws Throwable;
*/
*/
static
{
NamedFunction
.
initializeInvokers
();
}
private
static
final
HashMap
<
String
,
Integer
>
DEBUG_NAME_COUNTERS
;
static
{
if
(
debugEnabled
())
DEBUG_NAME_COUNTERS
=
new
HashMap
<>();
else
DEBUG_NAME_COUNTERS
=
null
;
}
// Put this last, so that previous static inits can run before.
static
{
createIdentityForms
();
if
(
USE_PREDEFINED_INTERPRET_METHODS
)
PREPARED_FORMS
.
putAll
(
computeInitialPreparedForms
());
NamedFunction
.
initializeInvokers
();
}
// The following hack is necessary in order to suppress TRACE_INTERPRETER
// The following hack is necessary in order to suppress TRACE_INTERPRETER
// during execution of the static initializes of this class.
// during execution of the static initializes of this class.
...
...
src/share/classes/java/lang/invoke/MethodHandle.java
浏览文件 @
237bbe7d
...
@@ -27,12 +27,12 @@ package java.lang.invoke;
...
@@ -27,12 +27,12 @@ package java.lang.invoke;
import
java.util.*
;
import
java.util.*
;
import
java.lang.invoke.LambdaForm.BasicType
;
import
sun.invoke.util.*
;
import
sun.invoke.util.*
;
import
sun.misc.Unsafe
;
import
sun.misc.Unsafe
;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
import
java.util.logging.Level
;
import
static
java
.
lang
.
invoke
.
LambdaForm
.
BasicType
.*;
import
java.util.logging.Logger
;
/**
/**
* A method handle is a typed, directly executable reference to an underlying method,
* A method handle is a typed, directly executable reference to an underlying method,
...
@@ -731,7 +731,7 @@ public abstract class MethodHandle {
...
@@ -731,7 +731,7 @@ public abstract class MethodHandle {
* <li>If the return type <em>T0</em> is void and <em>T1</em> a primitive,
* <li>If the return type <em>T0</em> is void and <em>T1</em> a primitive,
* a zero value is introduced.
* a zero value is introduced.
* </ul>
* </ul>
* (<em>Note:</em> Both <em>T0</em> and <em>T1</em> may be regarded as static types,
* (<em>Note:</em> Both <em>T0</em> and <em>T1</em> may be regarded as static types,
* because neither corresponds specifically to the <em>dynamic type</em> of any
* because neither corresponds specifically to the <em>dynamic type</em> of any
* actual argument or return value.)
* actual argument or return value.)
* <p>
* <p>
...
@@ -1376,7 +1376,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
...
@@ -1376,7 +1376,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
}
}
/*non-public*/
/*non-public*/
MethodHandle
bindArgument
(
int
pos
,
char
basicType
,
Object
value
)
{
MethodHandle
bindArgument
(
int
pos
,
BasicType
basicType
,
Object
value
)
{
// Override this if it can be improved.
// Override this if it can be improved.
return
rebind
().
bindArgument
(
pos
,
basicType
,
value
);
return
rebind
().
bindArgument
(
pos
,
basicType
,
value
);
}
}
...
@@ -1384,26 +1384,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
...
@@ -1384,26 +1384,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
/*non-public*/
/*non-public*/
MethodHandle
bindReceiver
(
Object
receiver
)
{
MethodHandle
bindReceiver
(
Object
receiver
)
{
// Override this if it can be improved.
// Override this if it can be improved.
return
bindArgument
(
0
,
'L'
,
receiver
);
return
bindArgument
(
0
,
L_TYPE
,
receiver
);
}
/*non-public*/
MethodHandle
bindImmediate
(
int
pos
,
char
basicType
,
Object
value
)
{
// Bind an immediate value to a position in the arguments.
// This means, elide the respective argument,
// and replace all references to it in NamedFunction args with the specified value.
// CURRENT RESTRICTIONS
// * only for pos 0 and UNSAFE (position is adjusted in MHImpl to make API usable for others)
assert
pos
==
0
&&
basicType
==
'L'
&&
value
instanceof
Unsafe
;
MethodType
type2
=
type
.
dropParameterTypes
(
pos
,
pos
+
1
);
// adjustment: ignore receiver!
LambdaForm
form2
=
form
.
bindImmediate
(
pos
+
1
,
basicType
,
value
);
// adjust pos to form-relative pos
return
copyWith
(
type2
,
form2
);
}
/*non-public*/
MethodHandle
copyWith
(
MethodType
mt
,
LambdaForm
lf
)
{
throw
new
InternalError
(
"copyWith: "
+
this
.
getClass
());
}
}
/*non-public*/
/*non-public*/
...
...
src/share/classes/java/lang/invoke/MethodHandleImpl.java
浏览文件 @
237bbe7d
...
@@ -412,7 +412,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
...
@@ -412,7 +412,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
@Override
@Override
MethodHandle
bindArgument
(
int
pos
,
char
basicType
,
Object
value
)
{
MethodHandle
bindArgument
(
int
pos
,
BasicType
basicType
,
Object
value
)
{
return
asFixedArity
().
bindArgument
(
pos
,
basicType
,
value
);
return
asFixedArity
().
bindArgument
(
pos
,
basicType
,
value
);
}
}
...
...
src/share/classes/java/lang/invoke/MethodHandleNatives.java
浏览文件 @
237bbe7d
...
@@ -78,7 +78,7 @@ class MethodHandleNatives {
...
@@ -78,7 +78,7 @@ class MethodHandleNatives {
// The JVM calls MethodHandleNatives.<clinit>. Cascade the <clinit> calls as needed:
// The JVM calls MethodHandleNatives.<clinit>. Cascade the <clinit> calls as needed:
MethodHandleImpl
.
initStatics
();
MethodHandleImpl
.
initStatics
();
}
}
// All compile-time constants go here.
// All compile-time constants go here.
// There is an opportunity to check them against the JVM's idea of them.
// There is an opportunity to check them against the JVM's idea of them.
...
@@ -293,6 +293,17 @@ class MethodHandleNatives {
...
@@ -293,6 +293,17 @@ class MethodHandleNatives {
Class
<?>
caller
=
(
Class
<?>)
callerObj
;
Class
<?>
caller
=
(
Class
<?>)
callerObj
;
String
name
=
nameObj
.
toString
().
intern
();
String
name
=
nameObj
.
toString
().
intern
();
MethodType
type
=
(
MethodType
)
typeObj
;
MethodType
type
=
(
MethodType
)
typeObj
;
if
(!
TRACE_METHOD_LINKAGE
)
return
linkCallSiteImpl
(
caller
,
bootstrapMethod
,
name
,
type
,
staticArguments
,
appendixResult
);
return
linkCallSiteTracing
(
caller
,
bootstrapMethod
,
name
,
type
,
staticArguments
,
appendixResult
);
}
static
MemberName
linkCallSiteImpl
(
Class
<?>
caller
,
MethodHandle
bootstrapMethod
,
String
name
,
MethodType
type
,
Object
staticArguments
,
Object
[]
appendixResult
)
{
CallSite
callSite
=
CallSite
.
makeSite
(
bootstrapMethod
,
CallSite
callSite
=
CallSite
.
makeSite
(
bootstrapMethod
,
name
,
name
,
type
,
type
,
...
@@ -306,6 +317,30 @@ class MethodHandleNatives {
...
@@ -306,6 +317,30 @@ class MethodHandleNatives {
return
Invokers
.
linkToCallSiteMethod
(
type
);
return
Invokers
.
linkToCallSiteMethod
(
type
);
}
}
}
}
// Tracing logic:
static
MemberName
linkCallSiteTracing
(
Class
<?>
caller
,
MethodHandle
bootstrapMethod
,
String
name
,
MethodType
type
,
Object
staticArguments
,
Object
[]
appendixResult
)
{
Object
bsmReference
=
bootstrapMethod
.
internalMemberName
();
if
(
bsmReference
==
null
)
bsmReference
=
bootstrapMethod
;
Object
staticArglist
=
(
staticArguments
instanceof
Object
[]
?
java
.
util
.
Arrays
.
asList
((
Object
[])
staticArguments
)
:
staticArguments
);
System
.
out
.
println
(
"linkCallSite "
+
caller
.
getName
()+
" "
+
bsmReference
+
" "
+
name
+
type
+
"/"
+
staticArglist
);
try
{
MemberName
res
=
linkCallSiteImpl
(
caller
,
bootstrapMethod
,
name
,
type
,
staticArguments
,
appendixResult
);
System
.
out
.
println
(
"linkCallSite => "
+
res
+
" + "
+
appendixResult
[
0
]);
return
res
;
}
catch
(
Throwable
ex
)
{
System
.
out
.
println
(
"linkCallSite => throw "
+
ex
);
throw
ex
;
}
}
/**
/**
* The JVM wants a pointer to a MethodType. Oblige it by finding or creating one.
* The JVM wants a pointer to a MethodType. Oblige it by finding or creating one.
...
...
src/share/classes/java/lang/invoke/MethodHandleStatics.java
浏览文件 @
237bbe7d
...
@@ -65,6 +65,16 @@ import sun.misc.Unsafe;
...
@@ -65,6 +65,16 @@ import sun.misc.Unsafe;
COMPILE_THRESHOLD
=
(
Integer
)
values
[
4
];
COMPILE_THRESHOLD
=
(
Integer
)
values
[
4
];
}
}
/** Tell if any of the debugging switches are turned on.
* If this is the case, it is reasonable to perform extra checks or save extra information.
*/
/*non-public*/
static
boolean
debugEnabled
()
{
return
(
DEBUG_METHOD_HANDLE_NAMES
|
DUMP_CLASS_FILES
|
TRACE_INTERPRETER
|
TRACE_METHOD_LINKAGE
);
}
/*non-public*/
static
String
getNameString
(
MethodHandle
target
,
MethodType
type
)
{
/*non-public*/
static
String
getNameString
(
MethodHandle
target
,
MethodType
type
)
{
if
(
type
==
null
)
if
(
type
==
null
)
type
=
target
.
type
();
type
=
target
.
type
();
...
@@ -93,6 +103,9 @@ import sun.misc.Unsafe;
...
@@ -93,6 +103,9 @@ import sun.misc.Unsafe;
}
}
// handy shared exception makers (they simplify the common case code)
// handy shared exception makers (they simplify the common case code)
/*non-public*/
static
InternalError
newInternalError
(
String
message
)
{
return
new
InternalError
(
message
);
}
/*non-public*/
static
InternalError
newInternalError
(
String
message
,
Throwable
cause
)
{
/*non-public*/
static
InternalError
newInternalError
(
String
message
,
Throwable
cause
)
{
return
new
InternalError
(
message
,
cause
);
return
new
InternalError
(
message
,
cause
);
}
}
...
...
src/share/classes/java/lang/invoke/MethodHandles.java
浏览文件 @
237bbe7d
...
@@ -37,13 +37,13 @@ import sun.reflect.CallerSensitive;
...
@@ -37,13 +37,13 @@ import sun.reflect.CallerSensitive;
import
sun.reflect.Reflection
;
import
sun.reflect.Reflection
;
import
sun.reflect.misc.ReflectUtil
;
import
sun.reflect.misc.ReflectUtil
;
import
sun.security.util.SecurityConstants
;
import
sun.security.util.SecurityConstants
;
import
java.lang.invoke.LambdaForm.BasicType
;
import
static
java
.
lang
.
invoke
.
LambdaForm
.
BasicType
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleNatives
.
Constants
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleNatives
.
Constants
.*;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.ConcurrentHashMap
;
import
sun.security.util.SecurityConstants
;
/**
/**
* This class consists exclusively of static methods that operate on or return
* This class consists exclusively of static methods that operate on or return
* method handles. They fall into several categories:
* method handles. They fall into several categories:
...
@@ -2202,12 +2202,12 @@ assert((int)twice.invokeExact(21) == 42);
...
@@ -2202,12 +2202,12 @@ assert((int)twice.invokeExact(21) == 42);
Object
value
=
values
[
i
];
Object
value
=
values
[
i
];
Class
<?>
ptype
=
oldType
.
parameterType
(
pos
+
i
);
Class
<?>
ptype
=
oldType
.
parameterType
(
pos
+
i
);
if
(
ptype
.
isPrimitive
())
{
if
(
ptype
.
isPrimitive
())
{
char
btype
=
'I'
;
BasicType
btype
=
I_TYPE
;
Wrapper
w
=
Wrapper
.
forPrimitiveType
(
ptype
);
Wrapper
w
=
Wrapper
.
forPrimitiveType
(
ptype
);
switch
(
w
)
{
switch
(
w
)
{
case
LONG:
btype
=
'J'
;
break
;
case
LONG:
btype
=
J_TYPE
;
break
;
case
FLOAT:
btype
=
'F'
;
break
;
case
FLOAT:
btype
=
F_TYPE
;
break
;
case
DOUBLE:
btype
=
'D'
;
break
;
case
DOUBLE:
btype
=
D_TYPE
;
break
;
}
}
// perform unboxing and/or primitive conversion
// perform unboxing and/or primitive conversion
value
=
w
.
convert
(
value
,
ptype
);
value
=
w
.
convert
(
value
,
ptype
);
...
@@ -2218,7 +2218,7 @@ assert((int)twice.invokeExact(21) == 42);
...
@@ -2218,7 +2218,7 @@ assert((int)twice.invokeExact(21) == 42);
if
(
pos
==
0
)
{
if
(
pos
==
0
)
{
result
=
result
.
bindReceiver
(
value
);
result
=
result
.
bindReceiver
(
value
);
}
else
{
}
else
{
result
=
result
.
bindArgument
(
pos
,
'L'
,
value
);
result
=
result
.
bindArgument
(
pos
,
L_TYPE
,
value
);
}
}
}
}
return
result
;
return
result
;
...
...
src/share/classes/java/lang/invoke/SimpleMethodHandle.java
浏览文件 @
237bbe7d
...
@@ -26,9 +26,7 @@
...
@@ -26,9 +26,7 @@
package
java.lang.invoke
;
package
java.lang.invoke
;
import
static
java
.
lang
.
invoke
.
LambdaForm
.*;
import
static
java
.
lang
.
invoke
.
LambdaForm
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleNatives
.
Constants
.*;
import
static
java
.
lang
.
invoke
.
LambdaForm
.
BasicType
.*;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
/**
/**
* A method handle whose behavior is determined only by its LambdaForm.
* A method handle whose behavior is determined only by its LambdaForm.
...
@@ -44,7 +42,7 @@ final class SimpleMethodHandle extends MethodHandle {
...
@@ -44,7 +42,7 @@ final class SimpleMethodHandle extends MethodHandle {
}
}
@Override
@Override
MethodHandle
bindArgument
(
int
pos
,
char
basicType
,
Object
value
)
{
MethodHandle
bindArgument
(
int
pos
,
BasicType
basicType
,
Object
value
)
{
MethodType
type2
=
type
().
dropParameterTypes
(
pos
,
pos
+
1
);
MethodType
type2
=
type
().
dropParameterTypes
(
pos
,
pos
+
1
);
LambdaForm
form2
=
internalForm
().
bind
(
1
+
pos
,
BoundMethodHandle
.
SpeciesData
.
EMPTY
);
LambdaForm
form2
=
internalForm
().
bind
(
1
+
pos
,
BoundMethodHandle
.
SpeciesData
.
EMPTY
);
return
BoundMethodHandle
.
bindSingle
(
type2
,
form2
,
basicType
,
value
);
return
BoundMethodHandle
.
bindSingle
(
type2
,
form2
,
basicType
,
value
);
...
@@ -61,10 +59,4 @@ final class SimpleMethodHandle extends MethodHandle {
...
@@ -61,10 +59,4 @@ final class SimpleMethodHandle extends MethodHandle {
LambdaForm
form2
=
internalForm
().
permuteArguments
(
1
,
reorder
,
basicTypes
(
newType
.
parameterList
()));
LambdaForm
form2
=
internalForm
().
permuteArguments
(
1
,
reorder
,
basicTypes
(
newType
.
parameterList
()));
return
new
SimpleMethodHandle
(
newType
,
form2
);
return
new
SimpleMethodHandle
(
newType
,
form2
);
}
}
@Override
MethodHandle
copyWith
(
MethodType
mt
,
LambdaForm
lf
)
{
return
new
SimpleMethodHandle
(
mt
,
lf
);
}
}
}
test/java/lang/invoke/LambdaFormTest.java
0 → 100644
浏览文件 @
237bbe7d
/*
* Copyright (c) 2014, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @summary unit tests for java.lang.invoke.LambdaForm
* @run junit/othervm test.java.lang.invoke.LambdaFormTest
*/
package
test.java.lang.invoke
;
import
org.junit.Test
;
import
java.lang.reflect.Method
;
import
static
org
.
junit
.
Assert
.*;
public
class
LambdaFormTest
{
static
final
Method
M_shortenSignature
;
static
{
try
{
Class
<?>
impl
=
Class
.
forName
(
"java.lang.invoke.LambdaForm"
,
false
,
null
);
Method
m
=
impl
.
getDeclaredMethod
(
"shortenSignature"
,
String
.
class
);
m
.
setAccessible
(
true
);
M_shortenSignature
=
m
;
}
catch
(
Exception
e
)
{
throw
new
AssertionError
(
e
);
}
}
public
static
String
shortenSignature
(
String
signature
)
throws
ReflectiveOperationException
{
return
(
String
)
M_shortenSignature
.
invoke
(
null
,
signature
);
}
@Test
public
void
testShortenSignature
()
throws
ReflectiveOperationException
{
for
(
String
s
:
new
String
[]
{
// invariant strings:
"L"
,
"LL"
,
"ILL"
,
"LIL"
,
"LLI"
,
"IILL"
,
"ILIL"
,
"ILLI"
,
// a few mappings:
"LLL=L3"
,
"LLLL=L4"
,
"LLLLLLLLLL=L10"
,
"IIIDDD=I3D3"
,
"IDDD=ID3"
,
"IIDDD=IID3"
,
"IIID=I3D"
,
"IIIDD=I3DD"
})
{
String
s2
=
s
.
substring
(
s
.
indexOf
(
'='
)+
1
);
String
s1
=
s
.
equals
(
s2
)
?
s
:
s
.
substring
(
0
,
s
.
length
()
-
s2
.
length
()
-
1
);
// mix the above cases with before and after reps of Z*
for
(
int
k
=
-
3
;
k
<=
3
;
k
++)
{
String
beg
=
(
k
<
0
?
"ZZZZ"
.
substring
(-
k
)
:
""
);
String
end
=
(
k
>
0
?
"ZZZZ"
.
substring
(+
k
)
:
""
);
String
ks1
=
beg
+
s1
+
end
;
String
ks2
=
shortenSignature
(
beg
)+
s2
+
shortenSignature
(
end
);
String
ks3
=
shortenSignature
(
ks1
);
assertEquals
(
ks2
,
ks3
);
}
}
}
public
static
void
main
(
String
[]
args
)
throws
ReflectiveOperationException
{
LambdaFormTest
test
=
new
LambdaFormTest
();
test
.
testShortenSignature
();
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录