author | darcy |
Thu, 27 Jun 2013 19:02:02 -0700 | |
changeset 18569 | 0e46c17766b7 |
parent 18556 | 0fe397a41c18 |
child 18716 | 9723e722b955 |
permissions | -rw-r--r-- |
14323 | 1 |
/* |
2 |
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. |
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
7 |
* published by the Free Software Foundation. Oracle designates this |
|
8 |
* particular file as subject to the "Classpath" exception as provided |
|
9 |
* by Oracle in the LICENSE file that accompanied this code. |
|
10 |
* |
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
24 |
*/ |
|
25 |
||
26 |
package java.lang.invoke; |
|
27 |
||
18284 | 28 |
import java.lang.reflect.Constructor; |
29 |
import java.lang.reflect.Method; |
|
30 |
import java.security.ProtectionDomain; |
|
31 |
import java.util.concurrent.atomic.AtomicInteger; |
|
18182
a86f1b828425
8015402: Lambda metafactory should not attempt to determine bridge methods
rfield
parents:
16859
diff
changeset
|
32 |
import jdk.internal.org.objectweb.asm.*; |
18284 | 33 |
import static jdk.internal.org.objectweb.asm.Opcodes.*; |
18182
a86f1b828425
8015402: Lambda metafactory should not attempt to determine bridge methods
rfield
parents:
16859
diff
changeset
|
34 |
import sun.misc.Unsafe; |
a86f1b828425
8015402: Lambda metafactory should not attempt to determine bridge methods
rfield
parents:
16859
diff
changeset
|
35 |
import java.security.AccessController; |
a86f1b828425
8015402: Lambda metafactory should not attempt to determine bridge methods
rfield
parents:
16859
diff
changeset
|
36 |
import java.security.PrivilegedAction; |
14323 | 37 |
|
38 |
/** |
|
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
39 |
* Lambda metafactory implementation which dynamically creates an inner-class-like class per lambda callsite. |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
40 |
* |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
41 |
* @see LambdaMetafactory |
14323 | 42 |
*/ |
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
43 |
/* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory { |
14323 | 44 |
private static final int CLASSFILE_VERSION = 51; |
45 |
private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE); |
|
46 |
private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl"; |
|
47 |
private static final String NAME_CTOR = "<init>"; |
|
48 |
||
49 |
//Serialization support |
|
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
50 |
private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda"; |
14323 | 51 |
private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;"; |
52 |
private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace"; |
|
53 |
private static final String NAME_OBJECT = "java/lang/Object"; |
|
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
54 |
private static final String DESCR_CTOR_SERIALIZED_LAMBDA |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
55 |
= MethodType.methodType(void.class, |
16034
cb5fbea1ecec
8008770: SerializedLambda incorrect class loader for lambda deserializing class
rfield
parents:
16001
diff
changeset
|
56 |
Class.class, |
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
57 |
int.class, String.class, String.class, String.class, |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
58 |
int.class, String.class, String.class, String.class, |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
59 |
String.class, |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
60 |
Object[].class).toMethodDescriptorString(); |
14323 | 61 |
|
62 |
// Used to ensure that each spun class name is unique |
|
63 |
private static final AtomicInteger counter = new AtomicInteger(0); |
|
64 |
||
65 |
// See context values in AbstractValidatingLambdaMetafactory |
|
66 |
private final String implMethodClassName; // Name of type containing implementation "CC" |
|
67 |
private final String implMethodName; // Name of implementation method "impl" |
|
68 |
private final String implMethodDesc; // Type descriptor for implementation methods "(I)Ljava/lang/String;" |
|
69 |
private final Type[] implMethodArgumentTypes; // ASM types for implementaion method parameters |
|
70 |
private final Type implMethodReturnType; // ASM type for implementaion method return type "Ljava/lang/String;" |
|
71 |
private final MethodType constructorType; // Generated class constructor type "(CC)void" |
|
72 |
private final String constructorDesc; // Type descriptor for constructor "(LCC;)V" |
|
73 |
private final ClassWriter cw; // ASM class writer |
|
74 |
private final Type[] argTypes; // ASM types for the constructor arguments |
|
75 |
private final String[] argNames; // Generated names for the constructor arguments |
|
76 |
private final String lambdaClassName; // Generated name for the generated class "X$$Lambda$1" |
|
77 |
private final Type[] instantiatedArgumentTypes; // ASM types for the functional interface arguments |
|
78 |
||
79 |
/** |
|
18284 | 80 |
* General meta-factory constructor, standard cases and allowing for uncommon options such as serialization. |
14323 | 81 |
* |
18284 | 82 |
* @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges |
83 |
* of the caller. |
|
84 |
* @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the |
|
85 |
* expected static type of the returned lambda object, and the static types of the captured |
|
86 |
* arguments for the lambda. In the event that the implementation method is an instance method, |
|
87 |
* the first argument in the invocation signature will correspond to the receiver. |
|
88 |
* @param samMethod The primary method in the functional interface to which the lambda or method reference is |
|
89 |
* being converted, represented as a method handle. |
|
90 |
* @param implMethod The implementation method which should be called (with suitable adaptation of argument |
|
91 |
* types, return types, and adjustment for captured arguments) when methods of the resulting |
|
92 |
* functional interface instance are invoked. |
|
93 |
* @param instantiatedMethodType The signature of the primary functional interface method after type variables |
|
94 |
* are substituted with their instantiation from the capture site |
|
95 |
* @param flags A bitmask containing flags that may influence the translation of this lambda expression. Defined |
|
96 |
* fields include FLAG_SERIALIZABLE. |
|
97 |
* @param markerInterfaces Additional interfaces which the lambda object should implement. |
|
14323 | 98 |
* @throws ReflectiveOperationException |
18284 | 99 |
* @throws LambdaConversionException If any of the meta-factory protocol invariants are violated |
14323 | 100 |
*/ |
101 |
public InnerClassLambdaMetafactory(MethodHandles.Lookup caller, |
|
102 |
MethodType invokedType, |
|
103 |
MethodHandle samMethod, |
|
104 |
MethodHandle implMethod, |
|
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
105 |
MethodType instantiatedMethodType, |
18284 | 106 |
int flags, |
107 |
Class<?>[] markerInterfaces) |
|
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
108 |
throws ReflectiveOperationException, LambdaConversionException { |
18284 | 109 |
super(caller, invokedType, samMethod, implMethod, instantiatedMethodType, flags, markerInterfaces); |
14323 | 110 |
implMethodClassName = implDefiningClass.getName().replace('.', '/'); |
111 |
implMethodName = implInfo.getName(); |
|
112 |
implMethodDesc = implMethodType.toMethodDescriptorString(); |
|
113 |
Type implMethodAsmType = Type.getMethodType(implMethodDesc); |
|
114 |
implMethodArgumentTypes = implMethodAsmType.getArgumentTypes(); |
|
18556
0fe397a41c18
8016761: Lambda metafactory - incorrect type conversion of constructor method handle
rfield
parents:
18284
diff
changeset
|
115 |
implMethodReturnType = (implKind == MethodHandleInfo.REF_newInvokeSpecial) |
0fe397a41c18
8016761: Lambda metafactory - incorrect type conversion of constructor method handle
rfield
parents:
18284
diff
changeset
|
116 |
? Type.getObjectType(implMethodClassName) |
0fe397a41c18
8016761: Lambda metafactory - incorrect type conversion of constructor method handle
rfield
parents:
18284
diff
changeset
|
117 |
: implMethodAsmType.getReturnType(); |
14323 | 118 |
constructorType = invokedType.changeReturnType(Void.TYPE); |
119 |
constructorDesc = constructorType.toMethodDescriptorString(); |
|
120 |
lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet(); |
|
121 |
cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); |
|
122 |
argTypes = Type.getArgumentTypes(constructorDesc); |
|
123 |
argNames = new String[argTypes.length]; |
|
124 |
for (int i = 0; i < argTypes.length; i++) { |
|
125 |
argNames[i] = "arg$" + (i + 1); |
|
126 |
} |
|
127 |
instantiatedArgumentTypes = Type.getArgumentTypes(instantiatedMethodType.toMethodDescriptorString()); |
|
128 |
} |
|
129 |
||
130 |
/** |
|
131 |
* Build the CallSite. Generate a class file which implements the functional |
|
132 |
* interface, define the class, if there are no parameters create an instance |
|
133 |
* of the class which the CallSite will return, otherwise, generate handles |
|
134 |
* which will call the class' constructor. |
|
135 |
* |
|
136 |
* @return a CallSite, which, when invoked, will return an instance of the |
|
137 |
* functional interface |
|
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
138 |
* @throws ReflectiveOperationException |
18284 | 139 |
* @throws LambdaConversionException If properly formed functional interface is not found |
14323 | 140 |
*/ |
141 |
@Override |
|
142 |
CallSite buildCallSite() throws ReflectiveOperationException, LambdaConversionException { |
|
143 |
final Class<?> innerClass = spinInnerClass(); |
|
144 |
if (invokedType.parameterCount() == 0) { |
|
14762
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
145 |
final Constructor[] ctrs = AccessController.doPrivileged( |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
146 |
new PrivilegedAction<Constructor[]>() { |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
147 |
@Override |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
148 |
public Constructor[] run() { |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
149 |
return innerClass.getDeclaredConstructors(); |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
150 |
} |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
151 |
}); |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
152 |
if (ctrs.length != 1) { |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
153 |
throw new ReflectiveOperationException("Expected one lambda constructor for " |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
154 |
+ innerClass.getCanonicalName() + ", got " + ctrs.length); |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
155 |
} |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
156 |
// The lambda implementing inner class constructor is private, set |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
157 |
// it accessible (by us) before creating the constant sole instance |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
158 |
AccessController.doPrivileged(new PrivilegedAction<Void>() { |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
159 |
@Override |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
160 |
public Void run() { |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
161 |
ctrs[0].setAccessible(true); |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
162 |
return null; |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
163 |
} |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
164 |
}); |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
165 |
Object inst = ctrs[0].newInstance(); |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
166 |
return new ConstantCallSite(MethodHandles.constant(samBase, inst)); |
14323 | 167 |
} else { |
168 |
return new ConstantCallSite( |
|
169 |
MethodHandles.Lookup.IMPL_LOOKUP |
|
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
170 |
.findConstructor(innerClass, constructorType) |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
171 |
.asType(constructorType.changeReturnType(samBase))); |
14323 | 172 |
} |
173 |
} |
|
174 |
||
175 |
/** |
|
176 |
* Generate a class file which implements the functional |
|
177 |
* interface, define and return the class. |
|
178 |
* |
|
179 |
* @return a Class which implements the functional interface |
|
18284 | 180 |
* @throws LambdaConversionException If properly formed functional interface is not found |
14323 | 181 |
*/ |
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
182 |
private Class<?> spinInnerClass() throws LambdaConversionException { |
14323 | 183 |
String samName = samBase.getName().replace('.', '/'); |
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
184 |
String[] interfaces = new String[markerInterfaces.length + 1]; |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
185 |
interfaces[0] = samName; |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
186 |
for (int i=0; i<markerInterfaces.length; i++) { |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
187 |
interfaces[i+1] = markerInterfaces[i].getName().replace('.', '/'); |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
188 |
} |
16859
45fbee947921
8012028: Metafactory-generated lambda classes should be final
rfield
parents:
16854
diff
changeset
|
189 |
cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC, |
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
190 |
lambdaClassName, null, |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
191 |
NAME_MAGIC_ACCESSOR_IMPL, interfaces); |
14323 | 192 |
|
193 |
// Generate final fields to be filled in by constructor |
|
194 |
for (int i = 0; i < argTypes.length; i++) { |
|
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
195 |
FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL, argNames[i], argTypes[i].getDescriptor(), |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
196 |
null, null); |
14323 | 197 |
fv.visitEnd(); |
198 |
} |
|
199 |
||
200 |
generateConstructor(); |
|
201 |
||
18284 | 202 |
MethodAnalyzer ma = new MethodAnalyzer(); |
203 |
||
14323 | 204 |
// Forward the SAM method |
18284 | 205 |
if (ma.getSamMethod() == null) { |
206 |
throw new LambdaConversionException(String.format("Functional interface method not found: %s", samMethodType)); |
|
207 |
} else { |
|
208 |
generateForwardingMethod(ma.getSamMethod(), false); |
|
209 |
} |
|
14323 | 210 |
|
211 |
// Forward the bridges |
|
18284 | 212 |
// @@@ The commented-out code is temporary, pending the VM's ability to bridge all methods on request |
213 |
// @@@ Once the VM can do fail-over, uncomment the !ma.wasDefaultMethodFound() test, and emit the appropriate |
|
214 |
// @@@ classfile attribute to request custom bridging. See 8002092. |
|
215 |
if (!ma.getMethodsToBridge().isEmpty() /* && !ma.conflictFoundBetweenDefaultAndBridge() */ ) { |
|
216 |
for (Method m : ma.getMethodsToBridge()) { |
|
217 |
generateForwardingMethod(m, true); |
|
14323 | 218 |
} |
219 |
} |
|
220 |
||
18284 | 221 |
if (isSerializable) { |
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
222 |
generateWriteReplace(); |
18284 | 223 |
} |
14323 | 224 |
|
225 |
cw.visitEnd(); |
|
226 |
||
227 |
// Define the generated class in this VM. |
|
228 |
||
229 |
final byte[] classBytes = cw.toByteArray(); |
|
230 |
||
14762
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
231 |
/*** Uncomment to dump the generated file |
14323 | 232 |
System.out.printf("Loaded: %s (%d bytes) %n", lambdaClassName, classBytes.length); |
233 |
try (FileOutputStream fos = new FileOutputStream(lambdaClassName.replace('/', '.') + ".class")) { |
|
234 |
fos.write(classBytes); |
|
235 |
} catch (IOException ex) { |
|
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
236 |
PlatformLogger.getLogger(InnerClassLambdaMetafactory.class.getName()).severe(ex.getMessage(), ex); |
14323 | 237 |
} |
14762
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
238 |
***/ |
14323 | 239 |
|
240 |
ClassLoader loader = targetClass.getClassLoader(); |
|
14762
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
241 |
ProtectionDomain pd = (loader == null) |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
242 |
? null |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
243 |
: AccessController.doPrivileged( |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
244 |
new PrivilegedAction<ProtectionDomain>() { |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
245 |
@Override |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
246 |
public ProtectionDomain run() { |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
247 |
return targetClass.getProtectionDomain(); |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
248 |
} |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
249 |
} |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
250 |
); |
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
251 |
|
18284 | 252 |
return (Class<?>) Unsafe.getUnsafe().defineClass(lambdaClassName, classBytes, 0, classBytes.length, |
253 |
loader, pd); |
|
14323 | 254 |
} |
255 |
||
256 |
/** |
|
257 |
* Generate the constructor for the class |
|
258 |
*/ |
|
259 |
private void generateConstructor() { |
|
260 |
// Generate constructor |
|
14762
34956da26ceb
8003881: Prevent lambda implementing inner classes from allowing the creation of new instances
rfield
parents:
14680
diff
changeset
|
261 |
MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR, constructorDesc, null, null); |
14323 | 262 |
ctor.visitCode(); |
263 |
ctor.visitVarInsn(ALOAD, 0); |
|
264 |
ctor.visitMethodInsn(INVOKESPECIAL, NAME_MAGIC_ACCESSOR_IMPL, NAME_CTOR, METHOD_DESCRIPTOR_VOID); |
|
265 |
int lvIndex = 0; |
|
266 |
for (int i = 0; i < argTypes.length; i++) { |
|
267 |
ctor.visitVarInsn(ALOAD, 0); |
|
268 |
ctor.visitVarInsn(argTypes[i].getOpcode(ILOAD), lvIndex + 1); |
|
269 |
lvIndex += argTypes[i].getSize(); |
|
18284 | 270 |
ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor()); |
14323 | 271 |
} |
272 |
ctor.visitInsn(RETURN); |
|
273 |
ctor.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored |
|
274 |
ctor.visitEnd(); |
|
275 |
} |
|
276 |
||
277 |
/** |
|
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
278 |
* Generate the writeReplace method (if needed for serialization) |
14323 | 279 |
*/ |
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
280 |
private void generateWriteReplace() { |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
281 |
TypeConvertingMethodAdapter mv |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
282 |
= new TypeConvertingMethodAdapter(cw.visitMethod(ACC_PRIVATE + ACC_FINAL, |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
283 |
NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE, |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
284 |
null, null)); |
14323 | 285 |
|
286 |
mv.visitCode(); |
|
287 |
mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA); |
|
18284 | 288 |
mv.visitInsn(DUP);; |
16034
cb5fbea1ecec
8008770: SerializedLambda incorrect class loader for lambda deserializing class
rfield
parents:
16001
diff
changeset
|
289 |
mv.visitLdcInsn(Type.getType(targetClass)); |
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
290 |
mv.visitLdcInsn(samInfo.getReferenceKind()); |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
291 |
mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/')); |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
292 |
mv.visitLdcInsn(samInfo.getName()); |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
293 |
mv.visitLdcInsn(samInfo.getMethodType().toMethodDescriptorString()); |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
294 |
mv.visitLdcInsn(implInfo.getReferenceKind()); |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
295 |
mv.visitLdcInsn(implInfo.getDeclaringClass().getName().replace('.', '/')); |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
296 |
mv.visitLdcInsn(implInfo.getName()); |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
297 |
mv.visitLdcInsn(implInfo.getMethodType().toMethodDescriptorString()); |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
298 |
mv.visitLdcInsn(instantiatedMethodType.toMethodDescriptorString()); |
14323 | 299 |
|
300 |
mv.iconst(argTypes.length); |
|
301 |
mv.visitTypeInsn(ANEWARRAY, NAME_OBJECT); |
|
302 |
for (int i = 0; i < argTypes.length; i++) { |
|
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
303 |
mv.visitInsn(DUP); |
14323 | 304 |
mv.iconst(i); |
305 |
mv.visitVarInsn(ALOAD, 0); |
|
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
306 |
mv.visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor()); |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
307 |
mv.boxIfTypePrimitive(argTypes[i]); |
14323 | 308 |
mv.visitInsn(AASTORE); |
309 |
} |
|
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
310 |
mv.visitMethodInsn(INVOKESPECIAL, NAME_SERIALIZED_LAMBDA, NAME_CTOR, |
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
311 |
DESCR_CTOR_SERIALIZED_LAMBDA); |
14323 | 312 |
mv.visitInsn(ARETURN); |
313 |
mv.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored |
|
314 |
mv.visitEnd(); |
|
315 |
} |
|
316 |
||
317 |
/** |
|
18284 | 318 |
* Generate a method which calls the lambda implementation method, |
319 |
* converting arguments, as needed. |
|
320 |
* @param m The method whose signature should be generated |
|
321 |
* @param isBridge True if this methods should be flagged as a bridge |
|
322 |
*/ |
|
323 |
private void generateForwardingMethod(Method m, boolean isBridge) { |
|
324 |
Class<?>[] exceptionTypes = m.getExceptionTypes(); |
|
325 |
String[] exceptionNames = new String[exceptionTypes.length]; |
|
326 |
for (int i = 0; i < exceptionTypes.length; i++) { |
|
327 |
exceptionNames[i] = exceptionTypes[i].getName().replace('.', '/'); |
|
328 |
} |
|
329 |
String methodDescriptor = Type.getMethodDescriptor(m); |
|
330 |
int access = isBridge? ACC_PUBLIC | ACC_BRIDGE : ACC_PUBLIC; |
|
331 |
MethodVisitor mv = cw.visitMethod(access, m.getName(), methodDescriptor, null, exceptionNames); |
|
332 |
new ForwardingMethodGenerator(mv).generate(m); |
|
333 |
} |
|
334 |
||
335 |
/** |
|
14323 | 336 |
* This class generates a method body which calls the lambda implementation |
337 |
* method, converting arguments, as needed. |
|
338 |
*/ |
|
339 |
private class ForwardingMethodGenerator extends TypeConvertingMethodAdapter { |
|
340 |
||
341 |
ForwardingMethodGenerator(MethodVisitor mv) { |
|
342 |
super(mv); |
|
343 |
} |
|
344 |
||
18284 | 345 |
void generate(Method m) throws InternalError { |
14323 | 346 |
visitCode(); |
347 |
||
348 |
if (implKind == MethodHandleInfo.REF_newInvokeSpecial) { |
|
349 |
visitTypeInsn(NEW, implMethodClassName); |
|
18284 | 350 |
visitInsn(DUP);; |
14323 | 351 |
} |
352 |
for (int i = 0; i < argTypes.length; i++) { |
|
353 |
visitVarInsn(ALOAD, 0); |
|
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
354 |
visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor()); |
14323 | 355 |
} |
356 |
||
18284 | 357 |
convertArgumentTypes(Type.getArgumentTypes(m)); |
14323 | 358 |
|
359 |
// Invoke the method we want to forward to |
|
360 |
visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc); |
|
361 |
||
362 |
// Convert the return value (if any) and return it |
|
363 |
// Note: if adapting from non-void to void, the 'return' instruction will pop the unneeded result |
|
18284 | 364 |
Type samReturnType = Type.getReturnType(m); |
14323 | 365 |
convertType(implMethodReturnType, samReturnType, samReturnType); |
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
366 |
visitInsn(samReturnType.getOpcode(Opcodes.IRETURN)); |
14323 | 367 |
|
368 |
visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored |
|
369 |
visitEnd(); |
|
370 |
} |
|
371 |
||
372 |
private void convertArgumentTypes(Type[] samArgumentTypes) { |
|
373 |
int lvIndex = 0; |
|
374 |
boolean samIncludesReceiver = implIsInstanceMethod && argTypes.length == 0; |
|
375 |
int samReceiverLength = samIncludesReceiver ? 1 : 0; |
|
376 |
if (samIncludesReceiver) { |
|
377 |
// push receiver |
|
378 |
Type rcvrType = samArgumentTypes[0]; |
|
379 |
Type instantiatedRcvrType = instantiatedArgumentTypes[0]; |
|
380 |
||
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
381 |
visitVarInsn(rcvrType.getOpcode(ILOAD), lvIndex + 1); |
14323 | 382 |
lvIndex += rcvrType.getSize(); |
383 |
convertType(rcvrType, Type.getType(implDefiningClass), instantiatedRcvrType); |
|
384 |
} |
|
385 |
int argOffset = implMethodArgumentTypes.length - samArgumentTypes.length; |
|
386 |
for (int i = samReceiverLength; i < samArgumentTypes.length; i++) { |
|
387 |
Type argType = samArgumentTypes[i]; |
|
388 |
Type targetType = implMethodArgumentTypes[argOffset + i]; |
|
389 |
Type instantiatedArgType = instantiatedArgumentTypes[i]; |
|
390 |
||
16001
fd4c8d3becf8
8004970: Implement serialization in the lambda metafactory
rfield
parents:
14762
diff
changeset
|
391 |
visitVarInsn(argType.getOpcode(ILOAD), lvIndex + 1); |
14323 | 392 |
lvIndex += argType.getSize(); |
393 |
convertType(argType, targetType, instantiatedArgType); |
|
394 |
} |
|
395 |
} |
|
396 |
||
397 |
private void convertType(Type argType, Type targetType, Type functionalType) { |
|
398 |
convertType(argType.getDescriptor(), targetType.getDescriptor(), functionalType.getDescriptor()); |
|
399 |
} |
|
400 |
||
401 |
private int invocationOpcode() throws InternalError { |
|
402 |
switch (implKind) { |
|
403 |
case MethodHandleInfo.REF_invokeStatic: |
|
404 |
return INVOKESTATIC; |
|
405 |
case MethodHandleInfo.REF_newInvokeSpecial: |
|
406 |
return INVOKESPECIAL; |
|
407 |
case MethodHandleInfo.REF_invokeVirtual: |
|
408 |
return INVOKEVIRTUAL; |
|
409 |
case MethodHandleInfo.REF_invokeInterface: |
|
410 |
return INVOKEINTERFACE; |
|
411 |
case MethodHandleInfo.REF_invokeSpecial: |
|
412 |
return INVOKESPECIAL; |
|
413 |
default: |
|
414 |
throw new InternalError("Unexpected invocation kind: " + implKind); |
|
415 |
} |
|
416 |
} |
|
417 |
} |
|
418 |
} |