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