Line 0
Link Here
|
|
|
1 |
package com.sun.tools.hc; |
2 |
|
3 |
import com.sun.tools.javac.util.Pair; |
4 |
import java.io.UnsupportedEncodingException; |
5 |
import java.lang.invoke.CallSite; |
6 |
import java.lang.invoke.LambdaConversionException; |
7 |
import java.lang.invoke.MethodHandle; |
8 |
import java.lang.invoke.MethodHandles; |
9 |
import java.lang.invoke.MethodType; |
10 |
import java.lang.reflect.Array; |
11 |
import java.lang.reflect.Field; |
12 |
import java.lang.reflect.Method; |
13 |
import java.util.logging.Level; |
14 |
import java.util.logging.Logger; |
15 |
|
16 |
|
17 |
|
18 |
/** |
19 |
* |
20 |
* @author Tomas Zezula |
21 |
*/ |
22 |
public class LambdaMetafactory { |
23 |
|
24 |
public static final int FLAG_SERIALIZABLE = 1 << 0; |
25 |
public static final int FLAG_MARKERS = 1 << 1; |
26 |
public static final int FLAG_BRIDGES = 1 << 2; |
27 |
|
28 |
private static final Logger LOG = Logger.getLogger(LambdaMetafactory.class.getName()); |
29 |
private static final byte[] PATTERN; |
30 |
private static final byte[] REPLACE; |
31 |
private static final boolean DO_TRANSLATE; |
32 |
static { |
33 |
try { |
34 |
PATTERN = "java/lang/invoke/LambdaMetafactory".getBytes("UTF-8"); //NOI18N |
35 |
REPLACE = "com/sun/tools/hc/LambdaMetafactory".getBytes("UTF-8"); //NOI18N |
36 |
} catch (UnsupportedEncodingException e) { |
37 |
throw new RuntimeException(e); |
38 |
} |
39 |
Pair<String,Integer> parsedJavaVersion = parseJavaVersion(System.getProperty("java.version")); //NOI18N |
40 |
DO_TRANSLATE = "1.8.0".equals(parsedJavaVersion.fst) && parsedJavaVersion.snd < 51; |
41 |
} |
42 |
private static final Method mm; |
43 |
private static final Method am; |
44 |
private static final ReflectiveOperationException refOpEx; |
45 |
static { |
46 |
Method mfm = null; |
47 |
Method amm = null; |
48 |
ReflectiveOperationException roe = null; |
49 |
try { |
50 |
final Class<?> clz = Class.forName("java.lang.invoke.LambdaMetafactory"); //NOI18N |
51 |
mfm = clz.getMethod( |
52 |
"metafactory", //NOI18N |
53 |
MethodHandles.Lookup.class, |
54 |
String.class, |
55 |
MethodType.class, |
56 |
MethodType.class, |
57 |
MethodHandle.class, |
58 |
MethodType.class); |
59 |
amm = clz.getMethod( |
60 |
"altMetafactory", //NOI18N |
61 |
MethodHandles.Lookup.class, |
62 |
String.class, |
63 |
MethodType.class, |
64 |
new Object[0].getClass()); |
65 |
} catch (ReflectiveOperationException e) { |
66 |
roe = e; |
67 |
} |
68 |
mm = mfm; |
69 |
am = amm; |
70 |
refOpEx = roe; |
71 |
} |
72 |
|
73 |
public static CallSite metafactory(MethodHandles.Lookup caller, |
74 |
String invokedName, |
75 |
MethodType invokedType, |
76 |
MethodType samMethodType, |
77 |
MethodHandle implMethod, |
78 |
MethodType instantiatedMethodType) throws LambdaConversionException { |
79 |
if (mm != null) { |
80 |
try { |
81 |
return (CallSite) mm.invoke( |
82 |
null, |
83 |
caller, |
84 |
invokedName, |
85 |
translate(invokedType), |
86 |
samMethodType, |
87 |
implMethod, |
88 |
instantiatedMethodType); |
89 |
} catch (ReflectiveOperationException e) { |
90 |
throw new RuntimeException(e); |
91 |
} |
92 |
} else { |
93 |
throw new RuntimeException(refOpEx); |
94 |
} |
95 |
} |
96 |
|
97 |
public static CallSite altMetafactory(MethodHandles.Lookup caller, |
98 |
String invokedName, |
99 |
MethodType invokedType, |
100 |
Object... args) throws LambdaConversionException { |
101 |
if (am != null) { |
102 |
try { |
103 |
return (CallSite) am.invoke( |
104 |
null, |
105 |
caller, |
106 |
invokedName, |
107 |
translate(invokedType), |
108 |
args); |
109 |
} catch (ReflectiveOperationException e) { |
110 |
throw new RuntimeException(e); |
111 |
} |
112 |
} else { |
113 |
throw new RuntimeException(refOpEx); |
114 |
} |
115 |
} |
116 |
|
117 |
public static byte[] translateClassFile( |
118 |
final byte[] data, |
119 |
final int start, |
120 |
final int end) { |
121 |
if (DO_TRANSLATE) { |
122 |
for (int index = find(data,start,end,PATTERN); |
123 |
index >= 0; |
124 |
index = find(data,index+PATTERN.length, end, PATTERN)) { |
125 |
System.arraycopy(REPLACE, 0, data, index, REPLACE.length); |
126 |
} |
127 |
} |
128 |
return data; |
129 |
} |
130 |
|
131 |
private static int find( |
132 |
final byte[] data, |
133 |
final int start, |
134 |
final int end, |
135 |
final byte[] pattern) { |
136 |
int i = start; |
137 |
int j = 0; |
138 |
for (; i < end && j < pattern.length; i++) { |
139 |
if (data[i] == pattern[j]) { |
140 |
j++; |
141 |
} else { |
142 |
j=0; |
143 |
} |
144 |
} |
145 |
return j == pattern.length ? |
146 |
i - j : |
147 |
-1; |
148 |
} |
149 |
|
150 |
private static MethodType translate(MethodType mt) { |
151 |
final Class<?> origRtype = mt.returnType(); |
152 |
final Class<?> rtype = translate(origRtype); |
153 |
final boolean changeRtype = origRtype != rtype; |
154 |
boolean changePtypes = false; |
155 |
final Class<?>[] ptypes = new Class<?>[mt.parameterCount()]; |
156 |
for (int i = 0; i < ptypes.length; i++) { |
157 |
final Class<?> origPtype = mt.parameterType(i); |
158 |
ptypes[i] = translate(origPtype); |
159 |
changePtypes |= origPtype != ptypes[i]; |
160 |
} |
161 |
try { |
162 |
if (changeRtype) { |
163 |
final Field rtypeFld = MethodType.class.getDeclaredField("rtype"); //NOI18N |
164 |
rtypeFld.setAccessible(true); |
165 |
rtypeFld.set(mt, rtype); |
166 |
} |
167 |
if (changePtypes) { |
168 |
final Field ptypesFld = MethodType.class.getDeclaredField("ptypes"); //NOI18N |
169 |
ptypesFld.setAccessible(true); |
170 |
ptypesFld.set(mt, ptypes); |
171 |
} |
172 |
} catch (ReflectiveOperationException e) { |
173 |
LOG.warning(e.getMessage()); |
174 |
} |
175 |
return mt; |
176 |
} |
177 |
|
178 |
private static Class<?> translate(Class<?> clz) { |
179 |
if (clz.isPrimitive()) { |
180 |
return clz; |
181 |
} else if (clz.isArray()) { |
182 |
final Class<?> oldCompType = clz.getComponentType(); |
183 |
final Class<?> newCompType = translate(oldCompType); |
184 |
if (oldCompType != newCompType) { |
185 |
clz = Array.newInstance(newCompType, 0).getClass(); |
186 |
} |
187 |
return clz; |
188 |
} else { |
189 |
try { |
190 |
final String fqn = clz.getName(); |
191 |
return LambdaMetafactory.class.getClassLoader().loadClass(fqn); |
192 |
} catch (ClassNotFoundException cnf) { |
193 |
return clz; |
194 |
} |
195 |
} |
196 |
} |
197 |
|
198 |
private static Pair<String,Integer> parseJavaVersion(final String version) { |
199 |
String ver = null; |
200 |
int update = 0; |
201 |
if (version != null) { |
202 |
final int index = version.lastIndexOf('_'); //NOI18N |
203 |
if (index > 0) { |
204 |
ver = version.substring(0, index); |
205 |
if (index+1 < version.length()) { |
206 |
try { |
207 |
update = Integer.parseInt(version.substring(index+1)); |
208 |
} catch (NumberFormatException e) { |
209 |
LOG.log(Level.FINE, "Invalid update version in: {0}", version); //NOI18N |
210 |
} |
211 |
} |
212 |
} |
213 |
} |
214 |
return Pair.of(ver, update); |
215 |
} |
216 |
} |