|
19 | 19 | import com.intellij.openapi.vfs.VirtualFile;
|
20 | 20 | import com.intellij.psi.PsiElement;
|
21 | 21 | import com.intellij.psi.PsiFile;
|
| 22 | +import com.intellij.util.ArrayUtil; |
| 23 | +import kotlin.jvm.functions.Function0; |
22 | 24 | import org.jetbrains.annotations.NotNull;
|
23 | 25 | import org.jetbrains.annotations.Nullable;
|
24 | 26 | import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
|
64 | 66 |
|
65 | 67 | import static org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags;
|
66 | 68 | import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive;
|
| 69 | +import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.API; |
67 | 70 | import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.addInlineMarker;
|
68 | 71 | import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.getConstant;
|
69 | 72 | import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral;
|
@@ -184,90 +187,163 @@ private SMAPAndMethodNode createMethodNode(boolean callDefault) throws IOExcepti
|
184 | 187 |
|
185 | 188 | @NotNull
|
186 | 189 | static SMAPAndMethodNode createMethodNode(
|
187 |
| - @NotNull FunctionDescriptor functionDescriptor, |
| 190 | + @NotNull final FunctionDescriptor functionDescriptor, |
188 | 191 | @NotNull JvmMethodSignature jvmSignature,
|
189 | 192 | @NotNull ExpressionCodegen codegen,
|
190 | 193 | @NotNull CodegenContext context,
|
191 | 194 | boolean callDefault,
|
192 |
| - @NotNull GenerationState state) throws IOException { |
| 195 | + @NotNull final GenerationState state |
| 196 | + ) { |
| 197 | + |
193 | 198 | KotlinTypeMapper typeMapper = state.getTypeMapper();
|
194 |
| - Method asmMethod = callDefault |
| 199 | + final Method asmMethod = callDefault |
195 | 200 | ? typeMapper.mapDefaultMethod(functionDescriptor, context.getContextKind())
|
196 | 201 | : jvmSignature.getAsmMethod();
|
197 | 202 |
|
| 203 | + MethodId methodId = new MethodId(DescriptorUtils.getFqNameSafe(functionDescriptor.getContainingDeclaration()), asmMethod); |
| 204 | + |
| 205 | + if (!isBuiltInArrayIntrinsic(functionDescriptor) && !(functionDescriptor instanceof DeserializedSimpleFunctionDescriptor)) { |
| 206 | + return doCreateMethodNodeFromSource(functionDescriptor, jvmSignature, codegen, context, callDefault, state, asmMethod); |
| 207 | + } |
| 208 | + |
| 209 | + SMAPAndMethodNode resultInCache = |
| 210 | + InlineCacheKt |
| 211 | + .getOrPut(state.getInlineCache().getMethodNodeById(), methodId, new Function0<SMAPAndMethodNode>() { |
| 212 | + @Override |
| 213 | + public SMAPAndMethodNode invoke() { |
| 214 | + return doCreateMethodNodeFromCompiled(functionDescriptor, |
| 215 | + state, asmMethod); |
| 216 | + } |
| 217 | + }); |
| 218 | + |
| 219 | + return resultInCache.copyWithNewNode(cloneMethodNode(resultInCache.getNode())); |
| 220 | + } |
| 221 | + |
| 222 | + @NotNull |
| 223 | + private static MethodNode cloneMethodNode(@NotNull MethodNode methodNode) { |
| 224 | + methodNode.instructions.resetLabels(); |
| 225 | + MethodNode result = new MethodNode( |
| 226 | + API, methodNode.access, methodNode.name, methodNode.desc, methodNode.signature, |
| 227 | + methodNode.exceptions.toArray(ArrayUtil.EMPTY_STRING_ARRAY)); |
| 228 | + methodNode.accept(result); |
| 229 | + return result; |
| 230 | + } |
| 231 | + |
| 232 | + @NotNull |
| 233 | + private static SMAPAndMethodNode doCreateMethodNodeFromCompiled( |
| 234 | + @NotNull FunctionDescriptor functionDescriptor, |
| 235 | + @NotNull final GenerationState state, |
| 236 | + @NotNull Method asmMethod |
| 237 | + ) { |
| 238 | + KotlinTypeMapper typeMapper = state.getTypeMapper(); |
| 239 | + |
198 | 240 | SMAPAndMethodNode nodeAndSMAP;
|
199 | 241 | if (isBuiltInArrayIntrinsic(functionDescriptor)) {
|
| 242 | + ClassId classId = IntrinsicArrayConstructorsKt.getClassId(); |
| 243 | + byte[] bytes = InlineCacheKt.getOrPut(state.getInlineCache().getClassBytes(), classId, new Function0<byte[]>() { |
| 244 | + @Override |
| 245 | + public byte[] invoke() { |
| 246 | + return IntrinsicArrayConstructorsKt.getBytecode(); |
| 247 | + } |
| 248 | + }); |
| 249 | + |
200 | 250 | nodeAndSMAP = InlineCodegenUtil.getMethodNode(
|
201 |
| - IntrinsicArrayConstructorsKt.getBytecode(), |
| 251 | + bytes, |
202 | 252 | asmMethod.getName(),
|
203 | 253 | asmMethod.getDescriptor(),
|
204 |
| - IntrinsicArrayConstructorsKt.getClassId() |
| 254 | + classId |
205 | 255 | );
|
206 | 256 |
|
207 | 257 | if (nodeAndSMAP == null) {
|
208 | 258 | throw new IllegalStateException("Couldn't obtain array constructor body for " + descriptorName(functionDescriptor));
|
209 | 259 | }
|
| 260 | + |
| 261 | + return nodeAndSMAP; |
210 | 262 | }
|
211 |
| - else if (functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) { |
212 |
| - KotlinTypeMapper.ContainingClassesInfo containingClasses = typeMapper.getContainingClassesForDeserializedCallable( |
213 |
| - (DeserializedSimpleFunctionDescriptor) functionDescriptor); |
214 | 263 |
|
215 |
| - ClassId containerId = containingClasses.getImplClassId(); |
216 |
| - VirtualFile file = InlineCodegenUtil.findVirtualFile(state, containerId); |
217 |
| - if (file == null) { |
218 |
| - throw new IllegalStateException("Couldn't find declaration file for " + containerId); |
219 |
| - } |
| 264 | + assert functionDescriptor instanceof DeserializedSimpleFunctionDescriptor; |
220 | 265 |
|
221 |
| - nodeAndSMAP = InlineCodegenUtil.getMethodNode( |
222 |
| - file.contentsToByteArray(), asmMethod.getName(), asmMethod.getDescriptor(), containerId |
223 |
| - ); |
| 266 | + KotlinTypeMapper.ContainingClassesInfo containingClasses = typeMapper.getContainingClassesForDeserializedCallable( |
| 267 | + (DeserializedSimpleFunctionDescriptor) functionDescriptor); |
224 | 268 |
|
225 |
| - if (nodeAndSMAP == null) { |
226 |
| - throw new IllegalStateException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor)); |
227 |
| - } |
228 |
| - } |
229 |
| - else { |
230 |
| - PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor); |
| 269 | + final ClassId containerId = containingClasses.getImplClassId(); |
231 | 270 |
|
232 |
| - if (!(element instanceof KtNamedFunction)) { |
233 |
| - throw new IllegalStateException("Couldn't find declaration for function " + descriptorName(functionDescriptor)); |
234 |
| - } |
235 |
| - KtNamedFunction inliningFunction = (KtNamedFunction) element; |
236 |
| - |
237 |
| - MethodNode node = new MethodNode(InlineCodegenUtil.API, |
238 |
| - getMethodAsmFlags(functionDescriptor, context.getContextKind()) | (callDefault ? Opcodes.ACC_STATIC : 0), |
239 |
| - asmMethod.getName(), |
240 |
| - asmMethod.getDescriptor(), |
241 |
| - null, |
242 |
| - null); |
243 |
| - |
244 |
| - //for maxLocals calculation |
245 |
| - MethodVisitor maxCalcAdapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node); |
246 |
| - MethodContext methodContext = context.getParentContext().intoFunction(functionDescriptor); |
247 |
| - |
248 |
| - SMAP smap; |
249 |
| - if (callDefault) { |
250 |
| - Type implementationOwner = typeMapper.mapImplementationOwner(functionDescriptor); |
251 |
| - FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen(), inliningFunction, |
252 |
| - (FieldOwnerContext) methodContext.getParentContext(), |
253 |
| - implementationOwner.getInternalName()); |
254 |
| - FunctionCodegen.generateDefaultImplBody( |
255 |
| - methodContext, functionDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT, |
256 |
| - inliningFunction, parentCodegen, asmMethod |
257 |
| - ); |
258 |
| - smap = createSMAPWithDefaultMapping(inliningFunction, parentCodegen.getOrCreateSourceMapper().getResultMappings()); |
259 |
| - } |
260 |
| - else { |
261 |
| - smap = generateMethodBody(maxCalcAdapter, functionDescriptor, methodContext, inliningFunction, jvmSignature, false, codegen, state); |
| 271 | + byte[] bytes = InlineCacheKt.getOrPut(state.getInlineCache().getClassBytes(), containerId, new Function0<byte[]>() { |
| 272 | + @Override |
| 273 | + public byte[] invoke() { |
| 274 | + VirtualFile file = InlineCodegenUtil.findVirtualFile(state, containerId); |
| 275 | + if (file == null) { |
| 276 | + throw new IllegalStateException("Couldn't find declaration file for " + containerId); |
| 277 | + } |
| 278 | + try { |
| 279 | + return file.contentsToByteArray(); |
| 280 | + } |
| 281 | + catch (IOException e) { |
| 282 | + throw new RuntimeException(e); |
| 283 | + } |
262 | 284 | }
|
| 285 | + }); |
263 | 286 |
|
264 |
| - nodeAndSMAP = new SMAPAndMethodNode(node, smap); |
265 |
| - maxCalcAdapter.visitMaxs(-1, -1); |
266 |
| - maxCalcAdapter.visitEnd(); |
| 287 | + nodeAndSMAP = InlineCodegenUtil.getMethodNode( |
| 288 | + bytes, asmMethod.getName(), asmMethod.getDescriptor(), containerId |
| 289 | + ); |
| 290 | + |
| 291 | + if (nodeAndSMAP == null) { |
| 292 | + throw new IllegalStateException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor)); |
267 | 293 | }
|
| 294 | + |
268 | 295 | return nodeAndSMAP;
|
269 | 296 | }
|
270 | 297 |
|
| 298 | + @NotNull |
| 299 | + private static SMAPAndMethodNode doCreateMethodNodeFromSource( |
| 300 | + @NotNull FunctionDescriptor functionDescriptor, |
| 301 | + @NotNull JvmMethodSignature jvmSignature, |
| 302 | + @NotNull ExpressionCodegen codegen, |
| 303 | + @NotNull CodegenContext context, |
| 304 | + boolean callDefault, |
| 305 | + @NotNull GenerationState state, |
| 306 | + @NotNull Method asmMethod |
| 307 | + ) { |
| 308 | + PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor); |
| 309 | + |
| 310 | + if (!(element instanceof KtNamedFunction)) { |
| 311 | + throw new IllegalStateException("Couldn't find declaration for function " + descriptorName(functionDescriptor)); |
| 312 | + } |
| 313 | + KtNamedFunction inliningFunction = (KtNamedFunction) element; |
| 314 | + |
| 315 | + MethodNode node = new MethodNode(InlineCodegenUtil.API, |
| 316 | + getMethodAsmFlags(functionDescriptor, context.getContextKind()) | (callDefault ? Opcodes.ACC_STATIC : 0), |
| 317 | + asmMethod.getName(), |
| 318 | + asmMethod.getDescriptor(), |
| 319 | + null, |
| 320 | + null); |
| 321 | + |
| 322 | + //for maxLocals calculation |
| 323 | + MethodVisitor maxCalcAdapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node); |
| 324 | + MethodContext methodContext = context.getParentContext().intoFunction(functionDescriptor); |
| 325 | + |
| 326 | + SMAP smap; |
| 327 | + if (callDefault) { |
| 328 | + Type implementationOwner = state.getTypeMapper().mapImplementationOwner(functionDescriptor); |
| 329 | + FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen(), inliningFunction, |
| 330 | + (FieldOwnerContext) methodContext.getParentContext(), |
| 331 | + implementationOwner.getInternalName()); |
| 332 | + FunctionCodegen.generateDefaultImplBody( |
| 333 | + methodContext, functionDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT, |
| 334 | + inliningFunction, parentCodegen, asmMethod |
| 335 | + ); |
| 336 | + smap = createSMAPWithDefaultMapping(inliningFunction, parentCodegen.getOrCreateSourceMapper().getResultMappings()); |
| 337 | + } |
| 338 | + else { |
| 339 | + smap = generateMethodBody(maxCalcAdapter, functionDescriptor, methodContext, inliningFunction, jvmSignature, false, codegen, state); |
| 340 | + } |
| 341 | + maxCalcAdapter.visitMaxs(-1, -1); |
| 342 | + maxCalcAdapter.visitEnd(); |
| 343 | + |
| 344 | + return new SMAPAndMethodNode(node, smap); |
| 345 | + } |
| 346 | + |
271 | 347 | private static boolean isBuiltInArrayIntrinsic(@NotNull FunctionDescriptor functionDescriptor) {
|
272 | 348 | if (functionDescriptor instanceof FictitiousArrayConstructor) return true;
|
273 | 349 | String name = functionDescriptor.getName().asString();
|
|
0 commit comments