Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
aad77330
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看板
提交
aad77330
编写于
9月 10, 2014
作者:
V
vlivanov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
8057042: LambdaFormEditor: derive new LFs from a base LF
Reviewed-by: vlivanov, psandoz Contributed-by: john.r.rose@oracle.com
上级
a859b764
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
881 addition
and
100 deletion
+881
-100
src/share/classes/java/lang/invoke/BoundMethodHandle.java
src/share/classes/java/lang/invoke/BoundMethodHandle.java
+19
-15
src/share/classes/java/lang/invoke/LambdaForm.java
src/share/classes/java/lang/invoke/LambdaForm.java
+11
-84
src/share/classes/java/lang/invoke/LambdaFormBuffer.java
src/share/classes/java/lang/invoke/LambdaFormBuffer.java
+400
-0
src/share/classes/java/lang/invoke/LambdaFormEditor.java
src/share/classes/java/lang/invoke/LambdaFormEditor.java
+450
-0
src/share/classes/java/lang/invoke/MethodHandleImpl.java
src/share/classes/java/lang/invoke/MethodHandleImpl.java
+1
-1
未找到文件。
src/share/classes/java/lang/invoke/BoundMethodHandle.java
浏览文件 @
aad77330
...
@@ -54,6 +54,7 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -54,6 +54,7 @@ import jdk.internal.org.objectweb.asm.Type;
/*non-public*/
BoundMethodHandle
(
MethodType
type
,
LambdaForm
form
)
{
/*non-public*/
BoundMethodHandle
(
MethodType
type
,
LambdaForm
form
)
{
super
(
type
,
form
);
super
(
type
,
form
);
assert
(
speciesData
()
==
speciesData
(
form
));
}
}
//
//
...
@@ -81,6 +82,11 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -81,6 +82,11 @@ import jdk.internal.org.objectweb.asm.Type;
}
}
}
}
/*non-public*/
LambdaFormEditor
editor
()
{
return
form
.
editor
();
}
static
BoundMethodHandle
bindSingle
(
MethodType
type
,
LambdaForm
form
,
Object
x
)
{
static
BoundMethodHandle
bindSingle
(
MethodType
type
,
LambdaForm
form
,
Object
x
)
{
return
Species_L
.
make
(
type
,
form
,
x
);
return
Species_L
.
make
(
type
,
form
,
x
);
}
}
...
@@ -88,33 +94,23 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -88,33 +94,23 @@ import jdk.internal.org.objectweb.asm.Type;
@Override
// there is a default binder in the super class, for 'L' types only
@Override
// there is a default binder in the super class, for 'L' types only
/*non-public*/
/*non-public*/
BoundMethodHandle
bindArgumentL
(
int
pos
,
Object
value
)
{
BoundMethodHandle
bindArgumentL
(
int
pos
,
Object
value
)
{
MethodType
type
=
type
().
dropParameterTypes
(
pos
,
pos
+
1
);
return
editor
().
bindArgumentL
(
this
,
pos
,
value
);
LambdaForm
form
=
internalForm
().
bind
(
1
+
pos
,
speciesData
());
return
copyWithExtendL
(
type
,
form
,
value
);
}
}
/*non-public*/
/*non-public*/
BoundMethodHandle
bindArgumentI
(
int
pos
,
int
value
)
{
BoundMethodHandle
bindArgumentI
(
int
pos
,
int
value
)
{
MethodType
type
=
type
().
dropParameterTypes
(
pos
,
pos
+
1
);
return
editor
().
bindArgumentI
(
this
,
pos
,
value
);
LambdaForm
form
=
internalForm
().
bind
(
1
+
pos
,
speciesData
());
return
copyWithExtendI
(
type
,
form
,
value
);
}
}
/*non-public*/
/*non-public*/
BoundMethodHandle
bindArgumentJ
(
int
pos
,
long
value
)
{
BoundMethodHandle
bindArgumentJ
(
int
pos
,
long
value
)
{
MethodType
type
=
type
().
dropParameterTypes
(
pos
,
pos
+
1
);
return
editor
().
bindArgumentJ
(
this
,
pos
,
value
);
LambdaForm
form
=
internalForm
().
bind
(
1
+
pos
,
speciesData
());
return
copyWithExtendJ
(
type
,
form
,
value
);
}
}
/*non-public*/
/*non-public*/
BoundMethodHandle
bindArgumentF
(
int
pos
,
float
value
)
{
BoundMethodHandle
bindArgumentF
(
int
pos
,
float
value
)
{
MethodType
type
=
type
().
dropParameterTypes
(
pos
,
pos
+
1
);
return
editor
().
bindArgumentF
(
this
,
pos
,
value
);
LambdaForm
form
=
internalForm
().
bind
(
1
+
pos
,
speciesData
());
return
copyWithExtendF
(
type
,
form
,
value
);
}
}
/*non-public*/
/*non-public*/
BoundMethodHandle
bindArgumentD
(
int
pos
,
double
value
)
{
BoundMethodHandle
bindArgumentD
(
int
pos
,
double
value
)
{
MethodType
type
=
type
().
dropParameterTypes
(
pos
,
pos
+
1
);
return
editor
().
bindArgumentD
(
this
,
pos
,
value
);
LambdaForm
form
=
internalForm
().
bind
(
1
+
pos
,
speciesData
());
return
copyWithExtendD
(
type
,
form
,
value
);
}
}
@Override
@Override
...
@@ -149,6 +145,14 @@ import jdk.internal.org.objectweb.asm.Type;
...
@@ -149,6 +145,14 @@ import jdk.internal.org.objectweb.asm.Type;
*/
*/
/*non-public*/
abstract
SpeciesData
speciesData
();
/*non-public*/
abstract
SpeciesData
speciesData
();
/*non-public*/
static
SpeciesData
speciesData
(
LambdaForm
form
)
{
Object
c
=
form
.
names
[
0
].
constraint
;
if
(
c
instanceof
SpeciesData
)
return
(
SpeciesData
)
c
;
// if there is no BMH constraint, then use the null constraint
return
SpeciesData
.
EMPTY
;
}
/**
/**
* Return the number of fields in this BMH. Equivalent to speciesData().fieldCount().
* Return the number of fields in this BMH. Equivalent to speciesData().fieldCount().
*/
*/
...
...
src/share/classes/java/lang/invoke/LambdaForm.java
浏览文件 @
aad77330
...
@@ -124,8 +124,7 @@ class LambdaForm {
...
@@ -124,8 +124,7 @@ class LambdaForm {
MemberName
vmentry
;
// low-level behavior, or null if not yet prepared
MemberName
vmentry
;
// low-level behavior, or null if not yet prepared
private
boolean
isCompiled
;
private
boolean
isCompiled
;
// Caches for common structural transforms:
Object
transformCache
;
// managed by LambdaFormEditor
LambdaForm
[]
bindCache
;
public
static
final
int
VOID_RESULT
=
-
1
,
LAST_RESULT
=
-
2
;
public
static
final
int
VOID_RESULT
=
-
1
,
LAST_RESULT
=
-
2
;
...
@@ -213,6 +212,13 @@ class LambdaForm {
...
@@ -213,6 +212,13 @@ class LambdaForm {
}
}
return
btypes
;
return
btypes
;
}
}
static
byte
[]
basicTypesOrd
(
BasicType
[]
btypes
)
{
byte
[]
ords
=
new
byte
[
btypes
.
length
];
for
(
int
i
=
0
;
i
<
btypes
.
length
;
i
++)
{
ords
[
i
]
=
(
byte
)
btypes
[
i
].
ordinal
();
}
return
ords
;
}
static
boolean
isBasicTypeChar
(
char
c
)
{
static
boolean
isBasicTypeChar
(
char
c
)
{
return
"LIJFDV"
.
indexOf
(
c
)
>=
0
;
return
"LIJFDV"
.
indexOf
(
c
)
>=
0
;
}
}
...
@@ -408,7 +414,7 @@ class LambdaForm {
...
@@ -408,7 +414,7 @@ class LambdaForm {
* This allows Name references to be freely reused to construct
* This allows Name references to be freely reused to construct
* fresh lambdas, without confusion.
* fresh lambdas, without confusion.
*/
*/
private
boolean
nameRefsAreLegal
()
{
boolean
nameRefsAreLegal
()
{
assert
(
arity
>=
0
&&
arity
<=
names
.
length
);
assert
(
arity
>=
0
&&
arity
<=
names
.
length
);
assert
(
result
>=
-
1
&&
result
<
names
.
length
);
assert
(
result
>=
-
1
&&
result
<
names
.
length
);
// Do all names possess an index consistent with their local definition order?
// Do all names possess an index consistent with their local definition order?
...
@@ -887,87 +893,8 @@ class LambdaForm {
...
@@ -887,87 +893,8 @@ class LambdaForm {
public
int
hashCode
()
{
public
int
hashCode
()
{
return
result
+
31
*
Arrays
.
hashCode
(
names
);
return
result
+
31
*
Arrays
.
hashCode
(
names
);
}
}
LambdaFormEditor
editor
()
{
LambdaForm
bind
(
int
namePos
,
BoundMethodHandle
.
SpeciesData
oldData
)
{
return
LambdaFormEditor
.
lambdaFormEditor
(
this
);
Name
name
=
names
[
namePos
];
BoundMethodHandle
.
SpeciesData
newData
=
oldData
.
extendWith
(
name
.
type
);
return
bind
(
name
,
new
Name
(
newData
.
getterFunction
(
oldData
.
fieldCount
()),
names
[
0
]),
oldData
,
newData
);
}
LambdaForm
bind
(
Name
name
,
Name
binding
,
BoundMethodHandle
.
SpeciesData
oldData
,
BoundMethodHandle
.
SpeciesData
newData
)
{
int
pos
=
name
.
index
;
assert
(
name
.
isParam
());
assert
(!
binding
.
isParam
());
assert
(
name
.
type
==
binding
.
type
);
assert
(
0
<=
pos
&&
pos
<
arity
&&
names
[
pos
]
==
name
);
assert
(
binding
.
function
.
memberDeclaringClassOrNull
()
==
newData
.
fieldHolder
());
assert
(
oldData
.
getterFunctions
().
length
==
newData
.
getterFunctions
().
length
-
1
);
if
(
bindCache
!=
null
)
{
LambdaForm
form
=
bindCache
[
pos
];
if
(
form
!=
null
)
{
assert
(
form
.
contains
(
binding
))
:
"form << "
+
form
+
" >> does not contain binding << "
+
binding
+
" >>"
;
return
form
;
}
}
else
{
bindCache
=
new
LambdaForm
[
arity
];
}
assert
(
nameRefsAreLegal
());
int
arity2
=
arity
-
1
;
Name
[]
names2
=
names
.
clone
();
names2
[
pos
]
=
binding
;
// we might move this in a moment
// The newly created LF will run with a different BMH.
// Switch over any pre-existing BMH field references to the new BMH class.
int
firstOldRef
=
-
1
;
for
(
int
i
=
0
;
i
<
names2
.
length
;
i
++)
{
Name
n
=
names
[
i
];
if
(
n
.
function
!=
null
&&
n
.
function
.
memberDeclaringClassOrNull
()
==
oldData
.
fieldHolder
())
{
MethodHandle
oldGetter
=
n
.
function
.
resolvedHandle
;
MethodHandle
newGetter
=
null
;
for
(
int
j
=
0
;
j
<
oldData
.
getterHandles
().
length
;
j
++)
{
if
(
oldGetter
==
oldData
.
getterHandles
()[
j
])
newGetter
=
newData
.
getterHandles
()[
j
];
}
if
(
newGetter
!=
null
)
{
if
(
firstOldRef
<
0
)
firstOldRef
=
i
;
Name
n2
=
new
Name
(
newGetter
,
n
.
arguments
);
names2
[
i
]
=
n2
;
}
}
}
// Walk over the new list of names once, in forward order.
// Replace references to 'name' with 'binding'.
// Replace data structure references to the old BMH species with the new.
// This might cause a ripple effect, but it will settle in one pass.
assert
(
firstOldRef
<
0
||
firstOldRef
>
pos
);
for
(
int
i
=
pos
+
1
;
i
<
names2
.
length
;
i
++)
{
if
(
i
<=
arity2
)
continue
;
names2
[
i
]
=
names2
[
i
].
replaceNames
(
names
,
names2
,
pos
,
i
);
}
// (a0, a1, name=a2, a3, a4) => (a0, a1, a3, a4, binding)
int
insPos
=
pos
;
for
(;
insPos
+
1
<
names2
.
length
;
insPos
++)
{
Name
n
=
names2
[
insPos
+
1
];
if
(
n
.
isParam
())
{
names2
[
insPos
]
=
n
;
}
else
{
break
;
}
}
names2
[
insPos
]
=
binding
;
// Since we moved some stuff, maybe update the result reference:
int
result2
=
result
;
if
(
result2
==
pos
)
result2
=
insPos
;
else
if
(
result2
>
pos
&&
result2
<=
insPos
)
result2
-=
1
;
return
bindCache
[
pos
]
=
new
LambdaForm
(
debugName
,
arity2
,
names2
,
result2
);
}
}
boolean
contains
(
Name
name
)
{
boolean
contains
(
Name
name
)
{
...
...
src/share/classes/java/lang/invoke/LambdaFormBuffer.java
0 → 100644
浏览文件 @
aad77330
/*
* Copyright (c) 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package
java.lang.invoke
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
static
java
.
lang
.
invoke
.
LambdaForm
.*;
import
static
java
.
lang
.
invoke
.
LambdaForm
.
BasicType
.*;
/** Working storage for an LF that is being transformed.
* Similarly to a StringBuffer, the editing can take place in multiple steps.
*/
final
class
LambdaFormBuffer
{
private
int
arity
,
length
;
private
Name
[]
names
;
private
Name
[]
originalNames
;
// snapshot of pre-transaction names
private
byte
flags
;
private
int
firstChange
;
private
Name
resultName
;
private
String
debugName
;
private
ArrayList
<
Name
>
dups
;
private
static
final
int
F_TRANS
=
0x10
,
F_OWNED
=
0x03
;
LambdaFormBuffer
(
LambdaForm
lf
)
{
this
(
lf
.
arity
,
lf
.
names
,
lf
.
result
);
debugName
=
lf
.
debugName
;
assert
(
lf
.
nameRefsAreLegal
());
}
private
LambdaFormBuffer
(
int
arity
,
Name
[]
names
,
int
result
)
{
this
.
arity
=
arity
;
setNames
(
names
);
if
(
result
==
LAST_RESULT
)
result
=
length
-
1
;
if
(
result
>=
0
&&
names
[
result
].
type
!=
V_TYPE
)
resultName
=
names
[
result
];
}
LambdaForm
lambdaForm
()
{
assert
(!
inTrans
());
// need endEdit call to tidy things up
return
new
LambdaForm
(
debugName
,
arity
,
nameArray
(),
resultIndex
());
}
Name
name
(
int
i
)
{
assert
(
i
<
length
);
return
names
[
i
];
}
Name
[]
nameArray
()
{
return
Arrays
.
copyOf
(
names
,
length
);
}
int
resultIndex
()
{
if
(
resultName
==
null
)
return
VOID_RESULT
;
int
index
=
indexOf
(
resultName
,
names
);
assert
(
index
>=
0
);
return
index
;
}
void
setNames
(
Name
[]
names2
)
{
names
=
originalNames
=
names2
;
// keep a record of where everything was to start with
length
=
names2
.
length
;
flags
=
0
;
}
private
boolean
verifyArity
()
{
for
(
int
i
=
0
;
i
<
arity
&&
i
<
firstChange
;
i
++)
{
assert
(
names
[
i
].
isParam
())
:
"#"
+
i
+
"="
+
names
[
i
];
}
for
(
int
i
=
arity
;
i
<
length
;
i
++)
{
assert
(!
names
[
i
].
isParam
())
:
"#"
+
i
+
"="
+
names
[
i
];
}
for
(
int
i
=
length
;
i
<
names
.
length
;
i
++)
{
assert
(
names
[
i
]
==
null
)
:
"#"
+
i
+
"="
+
names
[
i
];
}
// check resultName also
if
(
resultName
!=
null
)
{
int
resultIndex
=
indexOf
(
resultName
,
names
);
assert
(
resultIndex
>=
0
)
:
"not found: "
+
resultName
.
exprString
()
+
Arrays
.
asList
(
names
);
assert
(
names
[
resultIndex
]
==
resultName
);
}
return
true
;
}
private
boolean
verifyFirstChange
()
{
assert
(
inTrans
());
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
if
(
names
[
i
]
!=
originalNames
[
i
])
{
assert
(
firstChange
==
i
)
:
Arrays
.
asList
(
firstChange
,
i
,
originalNames
[
i
].
exprString
(),
Arrays
.
asList
(
names
));
return
true
;
}
}
assert
(
firstChange
==
length
)
:
Arrays
.
asList
(
firstChange
,
Arrays
.
asList
(
names
));
return
true
;
}
private
static
int
indexOf
(
NamedFunction
fn
,
NamedFunction
[]
fns
)
{
for
(
int
i
=
0
;
i
<
fns
.
length
;
i
++)
{
if
(
fns
[
i
]
==
fn
)
return
i
;
}
return
-
1
;
}
private
static
int
indexOf
(
Name
n
,
Name
[]
ns
)
{
for
(
int
i
=
0
;
i
<
ns
.
length
;
i
++)
{
if
(
ns
[
i
]
==
n
)
return
i
;
}
return
-
1
;
}
boolean
inTrans
()
{
return
(
flags
&
F_TRANS
)
!=
0
;
}
int
ownedCount
()
{
return
flags
&
F_OWNED
;
}
void
growNames
(
int
insertPos
,
int
growLength
)
{
int
oldLength
=
length
;
int
newLength
=
oldLength
+
growLength
;
int
oc
=
ownedCount
();
if
(
oc
==
0
||
newLength
>
names
.
length
)
{
names
=
Arrays
.
copyOf
(
names
,
(
names
.
length
+
growLength
)
*
5
/
4
);
if
(
oc
==
0
)
{
flags
++;
oc
++;
assert
(
ownedCount
()
==
oc
);
}
}
if
(
originalNames
!=
null
&&
originalNames
.
length
<
names
.
length
)
{
originalNames
=
Arrays
.
copyOf
(
originalNames
,
names
.
length
);
if
(
oc
==
1
)
{
flags
++;
oc
++;
assert
(
ownedCount
()
==
oc
);
}
}
if
(
growLength
==
0
)
return
;
int
insertEnd
=
insertPos
+
growLength
;
int
tailLength
=
oldLength
-
insertPos
;
System
.
arraycopy
(
names
,
insertPos
,
names
,
insertEnd
,
tailLength
);
Arrays
.
fill
(
names
,
insertPos
,
insertEnd
,
null
);
if
(
originalNames
!=
null
)
{
System
.
arraycopy
(
originalNames
,
insertPos
,
originalNames
,
insertEnd
,
tailLength
);
Arrays
.
fill
(
originalNames
,
insertPos
,
insertEnd
,
null
);
}
length
=
newLength
;
if
(
firstChange
>=
insertPos
)
{
firstChange
+=
growLength
;
}
}
int
lastIndexOf
(
Name
n
)
{
int
result
=
-
1
;
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
if
(
names
[
i
]
==
n
)
result
=
i
;
}
return
result
;
}
/** We have just overwritten the name at pos1 with the name at pos2.
* This means that there are two copies of the name, which we will have to fix later.
*/
private
void
noteDuplicate
(
int
pos1
,
int
pos2
)
{
Name
n
=
names
[
pos1
];
assert
(
n
==
names
[
pos2
]);
assert
(
originalNames
[
pos1
]
!=
null
);
// something was replaced at pos1
assert
(
originalNames
[
pos2
]
==
null
||
originalNames
[
pos2
]
==
n
);
if
(
dups
==
null
)
{
dups
=
new
ArrayList
<>();
}
dups
.
add
(
n
);
}
/** Replace duplicate names by nulls, and remove all nulls. */
private
void
clearDuplicatesAndNulls
()
{
if
(
dups
!=
null
)
{
// Remove duplicates.
assert
(
ownedCount
()
>=
1
);
for
(
Name
dup
:
dups
)
{
for
(
int
i
=
firstChange
;
i
<
length
;
i
++)
{
if
(
names
[
i
]
==
dup
&&
originalNames
[
i
]
!=
dup
)
{
names
[
i
]
=
null
;
assert
(
Arrays
.
asList
(
names
).
contains
(
dup
));
break
;
// kill only one dup
}
}
}
dups
.
clear
();
}
// Now that we are done with originalNames, remove "killed" names.
int
oldLength
=
length
;
for
(
int
i
=
firstChange
;
i
<
length
;
i
++)
{
if
(
names
[
i
]
==
null
)
{
System
.
arraycopy
(
names
,
i
+
1
,
names
,
i
,
(--
length
-
i
));
--
i
;
// restart loop at this position
}
}
if
(
length
<
oldLength
)
{
Arrays
.
fill
(
names
,
length
,
oldLength
,
null
);
}
assert
(!
Arrays
.
asList
(
names
).
subList
(
0
,
length
).
contains
(
null
));
}
/** Create a private, writable copy of names.
* Preserve the original copy, for reference.
*/
void
startEdit
()
{
assert
(
verifyArity
());
int
oc
=
ownedCount
();
assert
(!
inTrans
());
// no nested transactions
flags
|=
F_TRANS
;
Name
[]
oldNames
=
names
;
Name
[]
ownBuffer
=
(
oc
==
2
?
originalNames
:
null
);
assert
(
ownBuffer
!=
oldNames
);
if
(
ownBuffer
!=
null
&&
ownBuffer
.
length
>=
length
)
{
names
=
copyNamesInto
(
ownBuffer
);
}
else
{
// make a new buffer to hold the names
final
int
SLOP
=
2
;
names
=
Arrays
.
copyOf
(
oldNames
,
Math
.
max
(
length
+
SLOP
,
oldNames
.
length
));
if
(
oc
<
2
)
++
flags
;
assert
(
ownedCount
()
==
oc
+
1
);
}
originalNames
=
oldNames
;
assert
(
originalNames
!=
names
);
firstChange
=
length
;
assert
(
inTrans
());
}
private
void
changeName
(
int
i
,
Name
name
)
{
assert
(
inTrans
());
assert
(
i
<
length
);
Name
oldName
=
names
[
i
];
assert
(
oldName
==
originalNames
[
i
]);
// no multiple changes
assert
(
verifyFirstChange
());
if
(
ownedCount
()
==
0
)
growNames
(
0
,
0
);
names
[
i
]
=
name
;
if
(
firstChange
>
i
)
{
firstChange
=
i
;
}
if
(
resultName
!=
null
&&
resultName
==
oldName
)
{
resultName
=
name
;
}
}
/** Change the result name. Null means a void result. */
void
setResult
(
Name
name
)
{
assert
(
name
==
null
||
lastIndexOf
(
name
)
>=
0
);
resultName
=
name
;
}
/** Finish a transaction. */
void
endEdit
()
{
assert
(
verifyFirstChange
());
// Assuming names have been changed pairwise from originalNames[i] to names[i],
// update arguments to ensure referential integrity.
for
(
int
i
=
Math
.
max
(
firstChange
,
arity
);
i
<
length
;
i
++)
{
Name
name
=
names
[
i
];
if
(
name
==
null
)
continue
;
// space for removed duplicate
Name
newName
=
name
.
replaceNames
(
originalNames
,
names
,
firstChange
,
i
);
if
(
newName
!=
name
)
{
names
[
i
]
=
newName
;
if
(
resultName
==
name
)
{
resultName
=
newName
;
}
}
}
assert
(
inTrans
());
flags
&=
~
F_TRANS
;
clearDuplicatesAndNulls
();
originalNames
=
null
;
// If any parameters have been changed, then reorder them as needed.
// This is a "sheep-and-goats" stable sort, pushing all non-parameters
// to the right of all parameters.
if
(
firstChange
<
arity
)
{
Name
[]
exprs
=
new
Name
[
arity
-
firstChange
];
int
argp
=
firstChange
,
exprp
=
0
;
for
(
int
i
=
firstChange
;
i
<
arity
;
i
++)
{
Name
name
=
names
[
i
];
if
(
name
.
isParam
())
{
names
[
argp
++]
=
name
;
}
else
{
exprs
[
exprp
++]
=
name
;
}
}
assert
(
exprp
==
(
arity
-
argp
));
// copy the exprs just after the last remaining param
System
.
arraycopy
(
exprs
,
0
,
names
,
argp
,
exprp
);
// adjust arity
arity
-=
exprp
;
}
assert
(
verifyArity
());
}
private
Name
[]
copyNamesInto
(
Name
[]
buffer
)
{
System
.
arraycopy
(
names
,
0
,
buffer
,
0
,
length
);
Arrays
.
fill
(
buffer
,
length
,
buffer
.
length
,
null
);
return
buffer
;
}
/** Replace any Name whose function is in oldFns with a copy
* whose function is in the corresponding position in newFns.
* Only do this if the arguments are exactly equal to the given.
*/
LambdaFormBuffer
replaceFunctions
(
NamedFunction
[]
oldFns
,
NamedFunction
[]
newFns
,
Object
...
forArguments
)
{
assert
(
inTrans
());
if
(
oldFns
.
length
==
0
)
return
this
;
for
(
int
i
=
arity
;
i
<
length
;
i
++)
{
Name
n
=
names
[
i
];
int
nfi
=
indexOf
(
n
.
function
,
oldFns
);
if
(
nfi
>=
0
&&
Arrays
.
equals
(
n
.
arguments
,
forArguments
))
{
changeName
(
i
,
new
Name
(
newFns
[
nfi
],
n
.
arguments
));
}
}
return
this
;
}
private
void
replaceName
(
int
pos
,
Name
binding
)
{
assert
(
inTrans
());
assert
(
verifyArity
());
assert
(
pos
<
arity
);
Name
param
=
names
[
pos
];
assert
(
param
.
isParam
());
assert
(
param
.
type
==
binding
.
type
);
changeName
(
pos
,
binding
);
}
/** Replace a parameter by a fresh parameter. */
LambdaFormBuffer
renameParameter
(
int
pos
,
Name
newParam
)
{
assert
(
newParam
.
isParam
());
replaceName
(
pos
,
newParam
);
return
this
;
}
/** Replace a parameter by a fresh expression. */
LambdaFormBuffer
replaceParameterByNewExpression
(
int
pos
,
Name
binding
)
{
assert
(!
binding
.
isParam
());
assert
(
lastIndexOf
(
binding
)
<
0
);
// else use replaceParameterByCopy
replaceName
(
pos
,
binding
);
return
this
;
}
/** Replace a parameter by another parameter or expression already in the form. */
LambdaFormBuffer
replaceParameterByCopy
(
int
pos
,
int
valuePos
)
{
assert
(
pos
!=
valuePos
);
replaceName
(
pos
,
names
[
valuePos
]);
noteDuplicate
(
pos
,
valuePos
);
// temporarily, will occur twice in the names array
return
this
;
}
private
void
insertName
(
int
pos
,
Name
expr
,
boolean
isParameter
)
{
assert
(
inTrans
());
assert
(
verifyArity
());
assert
(
isParameter
?
pos
<=
arity
:
pos
>=
arity
);
growNames
(
pos
,
1
);
if
(
isParameter
)
arity
+=
1
;
changeName
(
pos
,
expr
);
}
/** Insert a fresh expression. */
LambdaFormBuffer
insertExpression
(
int
pos
,
Name
expr
)
{
assert
(!
expr
.
isParam
());
insertName
(
pos
,
expr
,
false
);
return
this
;
}
/** Insert a fresh parameter. */
LambdaFormBuffer
insertParameter
(
int
pos
,
Name
param
)
{
assert
(
param
.
isParam
());
insertName
(
pos
,
param
,
true
);
return
this
;
}
}
src/share/classes/java/lang/invoke/LambdaFormEditor.java
0 → 100644
浏览文件 @
aad77330
/*
* 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package
java.lang.invoke
;
import
java.util.Arrays
;
import
static
java
.
lang
.
invoke
.
LambdaForm
.*;
import
static
java
.
lang
.
invoke
.
LambdaForm
.
BasicType
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleImpl
.
Intrinsic
;
import
java.util.Collections
;
import
java.util.concurrent.ConcurrentHashMap
;
import
sun.invoke.util.Wrapper
;
/** Transforms on LFs.
* A lambda-form editor can derive new LFs from its base LF.
* The editor can cache derived LFs, which simplifies the reuse of their underlying bytecodes.
* To support this caching, a LF has an optional pointer to its editor.
*/
class
LambdaFormEditor
{
final
LambdaForm
lambdaForm
;
private
LambdaFormEditor
(
LambdaForm
lambdaForm
)
{
this
.
lambdaForm
=
lambdaForm
;
}
// Factory method.
static
LambdaFormEditor
lambdaFormEditor
(
LambdaForm
lambdaForm
)
{
// TO DO: Consider placing intern logic here, to cut down on duplication.
// lambdaForm = findPreexistingEquivalent(lambdaForm)
return
new
LambdaFormEditor
(
lambdaForm
);
}
/** A description of a cached transform, possibly associated with the result of the transform.
* The logical content is a sequence of byte values, starting with a Kind.ordinal value.
* The sequence is unterminated, ending with an indefinite number of zero bytes.
* Sequences that are simple (short enough and with small enough values) pack into a 64-bit long.
*/
private
static
final
class
Transform
{
final
long
packedBytes
;
final
byte
[]
fullBytes
;
final
LambdaForm
result
;
// result of transform, or null, if there is none available
private
enum
Kind
{
NO_KIND
,
// necessary because ordinal must be greater than zero
BIND_ARG
,
ADD_ARG
,
DUP_ARG
,
SPREAD_ARGS
,
FILTER_ARG
,
FILTER_RETURN
,
FILTER_RETURN_TO_ZERO
,
COLLECT_ARGS
,
COLLECT_ARGS_TO_VOID
,
COLLECT_ARGS_TO_ARRAY
,
FOLD_ARGS
,
FOLD_ARGS_TO_VOID
,
PERMUTE_ARGS
//maybe add more for guard with test, catch exception, pointwise type conversions
}
private
static
final
boolean
STRESS_TEST
=
false
;
// turn on to disable most packing
private
static
final
int
PACKED_BYTE_SIZE
=
(
STRESS_TEST
?
2
:
4
),
PACKED_BYTE_MASK
=
(
1
<<
PACKED_BYTE_SIZE
)
-
1
,
PACKED_BYTE_MAX_LENGTH
=
(
STRESS_TEST
?
3
:
64
/
PACKED_BYTE_SIZE
);
private
static
long
packedBytes
(
byte
[]
bytes
)
{
if
(
bytes
.
length
>
PACKED_BYTE_MAX_LENGTH
)
return
0
;
long
pb
=
0
;
int
bitset
=
0
;
for
(
int
i
=
0
;
i
<
bytes
.
length
;
i
++)
{
int
b
=
bytes
[
i
]
&
0xFF
;
bitset
|=
b
;
pb
|=
(
long
)
b
<<
(
i
*
PACKED_BYTE_SIZE
);
}
if
(!
inRange
(
bitset
))
return
0
;
return
pb
;
}
private
static
long
packedBytes
(
int
b0
,
int
b1
)
{
assert
(
inRange
(
b0
|
b1
));
return
(
(
b0
<<
0
*
PACKED_BYTE_SIZE
)
|
(
b1
<<
1
*
PACKED_BYTE_SIZE
));
}
private
static
long
packedBytes
(
int
b0
,
int
b1
,
int
b2
)
{
assert
(
inRange
(
b0
|
b1
|
b2
));
return
(
(
b0
<<
0
*
PACKED_BYTE_SIZE
)
|
(
b1
<<
1
*
PACKED_BYTE_SIZE
)
|
(
b2
<<
2
*
PACKED_BYTE_SIZE
));
}
private
static
long
packedBytes
(
int
b0
,
int
b1
,
int
b2
,
int
b3
)
{
assert
(
inRange
(
b0
|
b1
|
b2
|
b3
));
return
(
(
b0
<<
0
*
PACKED_BYTE_SIZE
)
|
(
b1
<<
1
*
PACKED_BYTE_SIZE
)
|
(
b2
<<
2
*
PACKED_BYTE_SIZE
)
|
(
b3
<<
3
*
PACKED_BYTE_SIZE
));
}
private
static
boolean
inRange
(
int
bitset
)
{
assert
((
bitset
&
0xFF
)
==
bitset
);
// incoming values must fit in *unsigned* byte
return
((
bitset
&
~
PACKED_BYTE_MASK
)
==
0
);
}
private
static
byte
[]
fullBytes
(
int
...
byteValues
)
{
byte
[]
bytes
=
new
byte
[
byteValues
.
length
];
int
i
=
0
;
for
(
int
bv
:
byteValues
)
{
bytes
[
i
++]
=
bval
(
bv
);
}
assert
(
packedBytes
(
bytes
)
==
0
);
return
bytes
;
}
private
byte
byteAt
(
int
i
)
{
long
pb
=
packedBytes
;
if
(
pb
==
0
)
{
if
(
i
>=
fullBytes
.
length
)
return
0
;
return
fullBytes
[
i
];
}
assert
(
fullBytes
==
null
);
if
(
i
>
PACKED_BYTE_MAX_LENGTH
)
return
0
;
int
pos
=
(
i
*
PACKED_BYTE_SIZE
);
return
(
byte
)((
pb
>>>
pos
)
&
PACKED_BYTE_MASK
);
}
Kind
kind
()
{
return
Kind
.
values
()[
byteAt
(
0
)];
}
private
Transform
(
long
packedBytes
,
byte
[]
fullBytes
,
LambdaForm
result
)
{
this
.
packedBytes
=
packedBytes
;
this
.
fullBytes
=
fullBytes
;
this
.
result
=
result
;
}
private
Transform
(
long
packedBytes
)
{
this
(
packedBytes
,
null
,
null
);
assert
(
packedBytes
!=
0
);
}
private
Transform
(
byte
[]
fullBytes
)
{
this
(
0
,
fullBytes
,
null
);
}
private
static
byte
bval
(
int
b
)
{
assert
((
b
&
0xFF
)
==
b
);
// incoming value must fit in *unsigned* byte
return
(
byte
)
b
;
}
private
static
byte
bval
(
Kind
k
)
{
return
bval
(
k
.
ordinal
());
}
static
Transform
of
(
Kind
k
,
int
b1
)
{
byte
b0
=
bval
(
k
);
if
(
inRange
(
b0
|
b1
))
return
new
Transform
(
packedBytes
(
b0
,
b1
));
else
return
new
Transform
(
fullBytes
(
b0
,
b1
));
}
static
Transform
of
(
Kind
k
,
int
b1
,
int
b2
)
{
byte
b0
=
(
byte
)
k
.
ordinal
();
if
(
inRange
(
b0
|
b1
|
b2
))
return
new
Transform
(
packedBytes
(
b0
,
b1
,
b2
));
else
return
new
Transform
(
fullBytes
(
b0
,
b1
,
b2
));
}
static
Transform
of
(
Kind
k
,
int
b1
,
int
b2
,
int
b3
)
{
byte
b0
=
(
byte
)
k
.
ordinal
();
if
(
inRange
(
b0
|
b1
|
b2
|
b3
))
return
new
Transform
(
packedBytes
(
b0
,
b1
,
b2
,
b3
));
else
return
new
Transform
(
fullBytes
(
b0
,
b1
,
b2
,
b3
));
}
private
static
final
byte
[]
NO_BYTES
=
{};
static
Transform
of
(
Kind
k
,
int
...
b123
)
{
return
ofBothArrays
(
k
,
b123
,
NO_BYTES
);
}
static
Transform
of
(
Kind
k
,
int
b1
,
byte
[]
b234
)
{
return
ofBothArrays
(
k
,
new
int
[]{
b1
},
b234
);
}
static
Transform
of
(
Kind
k
,
int
b1
,
int
b2
,
byte
[]
b345
)
{
return
ofBothArrays
(
k
,
new
int
[]{
b1
,
b2
},
b345
);
}
private
static
Transform
ofBothArrays
(
Kind
k
,
int
[]
b123
,
byte
[]
b456
)
{
byte
[]
fullBytes
=
new
byte
[
1
+
b123
.
length
+
b456
.
length
];
int
i
=
0
;
fullBytes
[
i
++]
=
bval
(
k
);
for
(
int
bv
:
b123
)
{
fullBytes
[
i
++]
=
bval
(
bv
);
}
for
(
byte
bv
:
b456
)
{
fullBytes
[
i
++]
=
bv
;
}
long
packedBytes
=
packedBytes
(
fullBytes
);
if
(
packedBytes
!=
0
)
return
new
Transform
(
packedBytes
);
else
return
new
Transform
(
fullBytes
);
}
Transform
withResult
(
LambdaForm
result
)
{
return
new
Transform
(
this
.
packedBytes
,
this
.
fullBytes
,
result
);
}
@Override
public
boolean
equals
(
Object
obj
)
{
return
obj
instanceof
Transform
&&
equals
((
Transform
)
obj
);
}
public
boolean
equals
(
Transform
that
)
{
return
this
.
packedBytes
==
that
.
packedBytes
&&
Arrays
.
equals
(
this
.
fullBytes
,
that
.
fullBytes
);
}
@Override
public
int
hashCode
()
{
if
(
packedBytes
!=
0
)
{
assert
(
fullBytes
==
null
);
return
Long
.
hashCode
(
packedBytes
);
}
return
Arrays
.
hashCode
(
fullBytes
);
}
@Override
public
String
toString
()
{
StringBuilder
buf
=
new
StringBuilder
();
long
bits
=
packedBytes
;
if
(
bits
!=
0
)
{
buf
.
append
(
"("
);
while
(
bits
!=
0
)
{
buf
.
append
(
bits
&
PACKED_BYTE_MASK
);
bits
>>>=
PACKED_BYTE_SIZE
;
if
(
bits
!=
0
)
buf
.
append
(
","
);
}
buf
.
append
(
")"
);
}
if
(
fullBytes
!=
null
)
{
buf
.
append
(
"unpacked"
);
buf
.
append
(
Arrays
.
toString
(
fullBytes
));
}
if
(
result
!=
null
)
{
buf
.
append
(
" result="
);
buf
.
append
(
result
);
}
return
buf
.
toString
();
}
}
/** Find a previously cached transform equivalent to the given one, and return its result. */
private
LambdaForm
getInCache
(
Transform
key
)
{
assert
(
key
.
result
==
null
);
// The transformCache is one of null, Transform, Transform[], or ConcurrentHashMap.
Object
c
=
lambdaForm
.
transformCache
;
Transform
k
=
null
;
if
(
c
instanceof
ConcurrentHashMap
)
{
@SuppressWarnings
(
"unchecked"
)
ConcurrentHashMap
<
Transform
,
Transform
>
m
=
(
ConcurrentHashMap
<
Transform
,
Transform
>)
c
;
k
=
m
.
get
(
key
);
}
else
if
(
c
==
null
)
{
return
null
;
}
else
if
(
c
instanceof
Transform
)
{
// one-element cache avoids overhead of an array
Transform
t
=
(
Transform
)
c
;
if
(
t
.
equals
(
key
))
k
=
t
;
}
else
{
Transform
[]
ta
=
(
Transform
[])
c
;
for
(
int
i
=
0
;
i
<
ta
.
length
;
i
++)
{
Transform
t
=
ta
[
i
];
if
(
t
==
null
)
break
;
if
(
t
.
equals
(
key
))
{
k
=
t
;
break
;
}
}
}
assert
(
k
==
null
||
key
.
equals
(
k
));
return
k
==
null
?
null
:
k
.
result
;
}
/** Arbitrary but reasonable limits on Transform[] size for cache. */
private
static
final
int
MIN_CACHE_ARRAY_SIZE
=
4
,
MAX_CACHE_ARRAY_SIZE
=
16
;
/** Cache a transform with its result, and return that result.
* But if an equivalent transform has already been cached, return its result instead.
*/
private
LambdaForm
putInCache
(
Transform
key
,
LambdaForm
form
)
{
key
=
key
.
withResult
(
form
);
for
(
int
pass
=
0
;
;
pass
++)
{
Object
c
=
lambdaForm
.
transformCache
;
if
(
c
instanceof
ConcurrentHashMap
)
{
@SuppressWarnings
(
"unchecked"
)
ConcurrentHashMap
<
Transform
,
Transform
>
m
=
(
ConcurrentHashMap
<
Transform
,
Transform
>)
c
;
Transform
k
=
m
.
putIfAbsent
(
key
,
key
);
return
k
!=
null
?
k
.
result
:
form
;
}
assert
(
pass
==
0
);
synchronized
(
lambdaForm
)
{
c
=
lambdaForm
.
transformCache
;
if
(
c
instanceof
ConcurrentHashMap
)
continue
;
if
(
c
==
null
)
{
lambdaForm
.
transformCache
=
key
;
return
form
;
}
Transform
[]
ta
;
if
(
c
instanceof
Transform
)
{
Transform
k
=
(
Transform
)
c
;
if
(
k
.
equals
(
key
))
{
return
k
.
result
;
}
// expand one-element cache to small array
ta
=
new
Transform
[
MIN_CACHE_ARRAY_SIZE
];
ta
[
0
]
=
k
;
lambdaForm
.
transformCache
=
c
=
ta
;
}
else
{
// it is already expanded
ta
=
(
Transform
[])
c
;
}
int
len
=
ta
.
length
;
int
i
;
for
(
i
=
0
;
i
<
len
;
i
++)
{
Transform
k
=
ta
[
i
];
if
(
k
==
null
)
{
break
;
}
if
(
k
.
equals
(
key
))
{
return
k
.
result
;
}
}
if
(
i
<
len
)
{
// just fall through to cache update
}
else
if
(
len
<
MAX_CACHE_ARRAY_SIZE
)
{
len
=
Math
.
min
(
len
*
2
,
MAX_CACHE_ARRAY_SIZE
);
ta
=
Arrays
.
copyOf
(
ta
,
len
);
lambdaForm
.
transformCache
=
ta
;
}
else
{
ConcurrentHashMap
<
Transform
,
Transform
>
m
=
new
ConcurrentHashMap
<>(
MAX_CACHE_ARRAY_SIZE
*
2
);
for
(
Transform
k
:
ta
)
{
m
.
put
(
k
,
k
);
}
lambdaForm
.
transformCache
=
m
;
// The second iteration will update for this query, concurrently.
continue
;
}
ta
[
i
]
=
key
;
return
form
;
}
}
}
private
LambdaFormBuffer
buffer
()
{
return
new
LambdaFormBuffer
(
lambdaForm
);
}
/// Editing methods for method handles. These need to have fast paths.
private
BoundMethodHandle
.
SpeciesData
oldSpeciesData
()
{
return
BoundMethodHandle
.
speciesData
(
lambdaForm
);
}
private
BoundMethodHandle
.
SpeciesData
newSpeciesData
(
BasicType
type
)
{
return
oldSpeciesData
().
extendWith
(
type
);
}
BoundMethodHandle
bindArgumentL
(
BoundMethodHandle
mh
,
int
pos
,
Object
value
)
{
assert
(
mh
.
speciesData
()
==
oldSpeciesData
());
BasicType
bt
=
L_TYPE
;
MethodType
type2
=
bindArgumentType
(
mh
,
pos
,
bt
);
LambdaForm
form2
=
bindArgumentForm
(
1
+
pos
);
return
mh
.
copyWithExtendL
(
type2
,
form2
,
value
);
}
BoundMethodHandle
bindArgumentI
(
BoundMethodHandle
mh
,
int
pos
,
int
value
)
{
assert
(
mh
.
speciesData
()
==
oldSpeciesData
());
BasicType
bt
=
I_TYPE
;
MethodType
type2
=
bindArgumentType
(
mh
,
pos
,
bt
);
LambdaForm
form2
=
bindArgumentForm
(
1
+
pos
);
return
mh
.
copyWithExtendI
(
type2
,
form2
,
value
);
}
BoundMethodHandle
bindArgumentJ
(
BoundMethodHandle
mh
,
int
pos
,
long
value
)
{
assert
(
mh
.
speciesData
()
==
oldSpeciesData
());
BasicType
bt
=
J_TYPE
;
MethodType
type2
=
bindArgumentType
(
mh
,
pos
,
bt
);
LambdaForm
form2
=
bindArgumentForm
(
1
+
pos
);
return
mh
.
copyWithExtendJ
(
type2
,
form2
,
value
);
}
BoundMethodHandle
bindArgumentF
(
BoundMethodHandle
mh
,
int
pos
,
float
value
)
{
assert
(
mh
.
speciesData
()
==
oldSpeciesData
());
BasicType
bt
=
F_TYPE
;
MethodType
type2
=
bindArgumentType
(
mh
,
pos
,
bt
);
LambdaForm
form2
=
bindArgumentForm
(
1
+
pos
);
return
mh
.
copyWithExtendF
(
type2
,
form2
,
value
);
}
BoundMethodHandle
bindArgumentD
(
BoundMethodHandle
mh
,
int
pos
,
double
value
)
{
assert
(
mh
.
speciesData
()
==
oldSpeciesData
());
BasicType
bt
=
D_TYPE
;
MethodType
type2
=
bindArgumentType
(
mh
,
pos
,
bt
);
LambdaForm
form2
=
bindArgumentForm
(
1
+
pos
);
return
mh
.
copyWithExtendD
(
type2
,
form2
,
value
);
}
private
MethodType
bindArgumentType
(
BoundMethodHandle
mh
,
int
pos
,
BasicType
bt
)
{
assert
(
mh
.
form
==
lambdaForm
);
assert
(
mh
.
form
.
names
[
1
+
pos
].
type
==
bt
);
assert
(
BasicType
.
basicType
(
mh
.
type
().
parameterType
(
pos
))
==
bt
);
return
mh
.
type
().
dropParameterTypes
(
pos
,
pos
+
1
);
}
/// Editing methods for lambda forms.
// Each editing method can (potentially) cache the edited LF so that it can be reused later.
LambdaForm
bindArgumentForm
(
int
pos
)
{
Transform
key
=
Transform
.
of
(
Transform
.
Kind
.
BIND_ARG
,
pos
);
LambdaForm
form
=
getInCache
(
key
);
if
(
form
!=
null
)
{
assert
(
form
.
parameterConstraint
(
0
)
==
newSpeciesData
(
lambdaForm
.
parameterType
(
pos
)));
return
form
;
}
LambdaFormBuffer
buf
=
buffer
();
buf
.
startEdit
();
BoundMethodHandle
.
SpeciesData
oldData
=
oldSpeciesData
();
BoundMethodHandle
.
SpeciesData
newData
=
newSpeciesData
(
lambdaForm
.
parameterType
(
pos
));
Name
oldBaseAddress
=
lambdaForm
.
parameter
(
0
);
// BMH holding the values
Name
newBaseAddress
;
NamedFunction
getter
=
newData
.
getterFunction
(
oldData
.
fieldCount
());
if
(
pos
!=
0
)
{
// The newly created LF will run with a different BMH.
// Switch over any pre-existing BMH field references to the new BMH class.
buf
.
replaceFunctions
(
oldData
.
getterFunctions
(),
newData
.
getterFunctions
(),
oldBaseAddress
);
newBaseAddress
=
oldBaseAddress
.
withConstraint
(
newData
);
buf
.
renameParameter
(
0
,
newBaseAddress
);
buf
.
replaceParameterByNewExpression
(
pos
,
new
Name
(
getter
,
newBaseAddress
));
}
else
{
// cannot bind the MH arg itself, unless oldData is empty
assert
(
oldData
==
BoundMethodHandle
.
SpeciesData
.
EMPTY
);
newBaseAddress
=
new
Name
(
L_TYPE
).
withConstraint
(
newData
);
buf
.
replaceParameterByNewExpression
(
0
,
new
Name
(
getter
,
newBaseAddress
));
buf
.
insertParameter
(
0
,
newBaseAddress
);
}
buf
.
endEdit
();
form
=
buf
.
lambdaForm
();
return
putInCache
(
key
,
form
);
}
}
src/share/classes/java/lang/invoke/MethodHandleImpl.java
浏览文件 @
aad77330
...
@@ -530,7 +530,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
...
@@ -530,7 +530,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
* Pre-initialized NamedFunctions for bootstrapping purposes.
* Pre-initialized NamedFunctions for bootstrapping purposes.
* Factored in an inner class to delay initialization until first usage.
* Factored in an inner class to delay initialization until first usage.
*/
*/
private
static
class
Lazy
{
static
class
Lazy
{
private
static
final
Class
<?>
MHI
=
MethodHandleImpl
.
class
;
private
static
final
Class
<?>
MHI
=
MethodHandleImpl
.
class
;
static
final
NamedFunction
NF_checkSpreadArgument
;
static
final
NamedFunction
NF_checkSpreadArgument
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录