001 /*
002 * Copyright 2010-2015 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.kotlin.codegen.inline;
018
019 import com.intellij.openapi.vfs.VirtualFile;
020 import com.intellij.psi.PsiElement;
021 import com.intellij.psi.PsiFile;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.kotlin.backend.common.CodegenUtil;
025 import org.jetbrains.kotlin.codegen.*;
026 import org.jetbrains.kotlin.codegen.context.CodegenContext;
027 import org.jetbrains.kotlin.codegen.context.FieldOwnerContext;
028 import org.jetbrains.kotlin.codegen.context.MethodContext;
029 import org.jetbrains.kotlin.codegen.context.PackageContext;
030 import org.jetbrains.kotlin.codegen.state.GenerationState;
031 import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
032 import org.jetbrains.kotlin.descriptors.*;
033 import org.jetbrains.kotlin.load.kotlin.PackageClassUtils;
034 import org.jetbrains.kotlin.name.ClassId;
035 import org.jetbrains.kotlin.psi.*;
036 import org.jetbrains.kotlin.renderer.DescriptorRenderer;
037 import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
038 import org.jetbrains.kotlin.resolve.DescriptorUtils;
039 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
040 import org.jetbrains.kotlin.resolve.inline.InlineStrategy;
041 import org.jetbrains.kotlin.resolve.inline.InlineUtil;
042 import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
043 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
044 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
045 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
046 import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor;
047 import org.jetbrains.org.objectweb.asm.Label;
048 import org.jetbrains.org.objectweb.asm.MethodVisitor;
049 import org.jetbrains.org.objectweb.asm.Opcodes;
050 import org.jetbrains.org.objectweb.asm.Type;
051 import org.jetbrains.org.objectweb.asm.commons.Method;
052 import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode;
053 import org.jetbrains.org.objectweb.asm.tree.LabelNode;
054 import org.jetbrains.org.objectweb.asm.tree.MethodNode;
055
056 import java.io.IOException;
057 import java.util.*;
058
059 import static org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags;
060 import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive;
061 import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.CLASS_FOR_SCRIPT;
062 import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.addInlineMarker;
063 import static org.jetbrains.kotlin.resolve.DescriptorUtils.isFunctionLiteral;
064 import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getResolvedCallWithAssert;
065
066 public class InlineCodegen extends CallGenerator {
067 private final GenerationState state;
068 private final JetTypeMapper typeMapper;
069
070 private final SimpleFunctionDescriptor functionDescriptor;
071 private final JvmMethodSignature jvmSignature;
072 private final JetElement callElement;
073 private final MethodContext context;
074 private final ExpressionCodegen codegen;
075
076 private final boolean asFunctionInline;
077 private final int initialFrameSize;
078 private final boolean isSameModule;
079
080 protected final ParametersBuilder invocationParamBuilder = ParametersBuilder.newBuilder();
081 protected final Map<Integer, LambdaInfo> expressionMap = new HashMap<Integer, LambdaInfo>();
082
083 private final ReifiedTypeInliner reifiedTypeInliner;
084
085 private LambdaInfo activeLambda;
086
087 private final SourceMapper sourceMapper;
088
089 public InlineCodegen(
090 @NotNull ExpressionCodegen codegen,
091 @NotNull GenerationState state,
092 @NotNull SimpleFunctionDescriptor functionDescriptor,
093 @NotNull JetElement callElement,
094 @Nullable ReifiedTypeParameterMappings typeParameterMappings
095 ) {
096 assert InlineUtil.isInline(functionDescriptor) : "InlineCodegen could inline only inline function: " + functionDescriptor;
097
098 this.state = state;
099 this.typeMapper = state.getTypeMapper();
100 this.codegen = codegen;
101 this.callElement = callElement;
102 this.functionDescriptor = functionDescriptor.getOriginal();
103
104 reifiedTypeInliner = new ReifiedTypeInliner(typeParameterMappings);
105
106 initialFrameSize = codegen.getFrameMap().getCurrentSize();
107
108 context = (MethodContext) getContext(functionDescriptor, state);
109 jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind());
110
111 // TODO: implement AS_FUNCTION inline strategy
112 InlineStrategy inlineStrategy = InlineUtil.getInlineStrategy(functionDescriptor);
113 this.asFunctionInline = false;
114
115 isSameModule = JvmCodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext(), state.getOutDirectory());
116
117 sourceMapper = codegen.getParentCodegen().getOrCreateSourceMapper();
118 }
119
120 @Override
121 public void genCallWithoutAssertions(
122 @NotNull CallableMethod callableMethod, @NotNull ExpressionCodegen codegen
123 ) {
124 genCall(callableMethod, null, false, codegen);
125 }
126
127 @Override
128 public void genCallInner(@NotNull Callable callableMethod, @Nullable ResolvedCall<?> resolvedCall, boolean callDefault, @NotNull ExpressionCodegen codegen) {
129 SMAPAndMethodNode nodeAndSmap = null;
130 if (!state.getInlineCycleReporter().enterIntoInlining(resolvedCall)) {
131 generateStub(resolvedCall, codegen);
132 return;
133 }
134
135 try {
136 nodeAndSmap = createMethodNode(callDefault);
137 endCall(inlineCall(nodeAndSmap));
138 }
139 catch (CompilationException e) {
140 throw e;
141 }
142 catch (Exception e) {
143 boolean generateNodeText = !(e instanceof InlineException);
144 PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(this.codegen.getContext().getContextDescriptor());
145 throw new CompilationException("Couldn't inline method call '" +
146 functionDescriptor.getName() +
147 "' into \n" + (element != null ? element.getText() : "null psi element " + this.codegen.getContext().getContextDescriptor()) +
148 (generateNodeText ? ("\ncause: " + InlineCodegenUtil.getNodeText(nodeAndSmap != null ? nodeAndSmap.getNode(): null)) : ""),
149 e, callElement);
150 }
151 finally {
152 state.getInlineCycleReporter().exitFromInliningOf(resolvedCall);
153 }
154 }
155
156 protected void generateStub(@Nullable ResolvedCall<?> resolvedCall, @NotNull ExpressionCodegen codegen) {
157 leaveTemps();
158 assert resolvedCall != null;
159 String message = "Call is part of inline cycle: " + resolvedCall.getCall().getCallElement().getText();
160 AsmUtil.genThrow(codegen.v, "java/lang/UnsupportedOperationException", message);
161 }
162
163 private void endCall(@NotNull InlineResult result) {
164 leaveTemps();
165
166 codegen.propagateChildReifiedTypeParametersUsages(result.getReifiedTypeParametersUsages());
167
168 state.getFactory().removeInlinedClasses(result.getClassesToRemove());
169
170 codegen.markLineNumberAfterInlineIfNeeded();
171 }
172
173 @NotNull
174 private SMAPAndMethodNode createMethodNode(boolean callDefault) throws ClassNotFoundException, IOException {
175 JvmMethodSignature jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind());
176
177 Method asmMethod;
178 if (callDefault) {
179 asmMethod = typeMapper.mapDefaultMethod(functionDescriptor, context.getContextKind(), context);
180 }
181 else {
182 asmMethod = jvmSignature.getAsmMethod();
183 }
184
185 SMAPAndMethodNode nodeAndSMAP;
186 if (functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) {
187 ClassId containerClassId = InlineCodegenUtil.getContainerClassIdForInlineCallable(
188 (DeserializedSimpleFunctionDescriptor) functionDescriptor);
189
190 VirtualFile file = InlineCodegenUtil.getVirtualFileForCallable(containerClassId, state);
191 if (functionDescriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor) {
192 /*use facade class*/
193 containerClassId = PackageClassUtils.getPackageClassId(containerClassId.getPackageFqName());
194 }
195 nodeAndSMAP = InlineCodegenUtil.getMethodNode(file.contentsToByteArray(),
196 asmMethod.getName(),
197 asmMethod.getDescriptor(),
198 containerClassId);
199
200 if (nodeAndSMAP == null) {
201 throw new RuntimeException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor));
202 }
203 }
204 else {
205 PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor);
206
207 if (element == null || !(element instanceof JetNamedFunction)) {
208 throw new RuntimeException("Couldn't find declaration for function " + descriptorName(functionDescriptor));
209 }
210 JetNamedFunction inliningFunction = (JetNamedFunction) element;
211
212 MethodNode node = new MethodNode(InlineCodegenUtil.API,
213 getMethodAsmFlags(functionDescriptor, context.getContextKind()) | (callDefault ? Opcodes.ACC_STATIC : 0),
214 asmMethod.getName(),
215 asmMethod.getDescriptor(),
216 jvmSignature.getGenericsSignature(),
217 null);
218
219 //for maxLocals calculation
220 MethodVisitor maxCalcAdapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node);
221 MethodContext methodContext = context.getParentContext().intoFunction(functionDescriptor);
222
223 SMAP smap;
224 if (callDefault) {
225 Type ownerType = typeMapper.mapOwner(functionDescriptor, false/*use facade class*/);
226 FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen(), inliningFunction,
227 (FieldOwnerContext) methodContext.getParentContext(),
228 ownerType.getInternalName());
229 FunctionCodegen.generateDefaultImplBody(
230 methodContext, functionDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT,
231 inliningFunction, parentCodegen
232 );
233 smap = createSMAPWithDefaultMapping(inliningFunction, parentCodegen.getOrCreateSourceMapper().getResultMappings());
234 }
235 else {
236 smap = generateMethodBody(maxCalcAdapter, functionDescriptor, methodContext, inliningFunction, jvmSignature, false);
237 }
238
239 nodeAndSMAP = new SMAPAndMethodNode(node, smap);
240 maxCalcAdapter.visitMaxs(-1, -1);
241 maxCalcAdapter.visitEnd();
242 }
243 return nodeAndSMAP;
244 }
245
246 private InlineResult inlineCall(SMAPAndMethodNode nodeAndSmap) {
247 MethodNode node = nodeAndSmap.getNode();
248 ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node.instructions);
249 generateClosuresBodies();
250
251 //through generation captured parameters will be added to invocationParamBuilder
252 putClosureParametersOnStack();
253
254 addInlineMarker(codegen.v, true);
255
256 Parameters parameters = invocationParamBuilder.buildParameters();
257
258 InliningContext info = new RootInliningContext(expressionMap,
259 state,
260 codegen.getInlineNameGenerator()
261 .subGenerator(functionDescriptor.getName().asString()),
262 codegen.getContext(),
263 callElement,
264 codegen.getParentCodegen().getClassName(), reifiedTypeInliner);
265
266 MethodInliner inliner = new MethodInliner(node, parameters, info, new FieldRemapper(null, null, parameters), isSameModule,
267 "Method inlining " + callElement.getText(),
268 createNestedSourceMapper(nodeAndSmap)); //with captured
269
270 LocalVarRemapper remapper = new LocalVarRemapper(parameters, initialFrameSize);
271
272
273 MethodNode adapter = InlineCodegenUtil.createEmptyMethodNode();
274 //hack to keep linenumber info, otherwise jdi will skip begin of linenumber chain
275 adapter.visitInsn(Opcodes.NOP);
276
277 InlineResult result = inliner.doInline(adapter, remapper, true, LabelOwner.SKIP_ALL);
278 result.getReifiedTypeParametersUsages().mergeAll(reificationResult);
279
280 CallableMemberDescriptor descriptor = codegen.getContext().getContextDescriptor();
281 final Set<String> labels = getDeclarationLabels(DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor);
282 LabelOwner labelOwner = new LabelOwner() {
283 @Override
284 public boolean isMyLabel(@NotNull String name) {
285 return labels.contains(name);
286 }
287 };
288
289 List<MethodInliner.PointForExternalFinallyBlocks> infos = MethodInliner.processReturns(adapter, labelOwner, true, null);
290 generateAndInsertFinallyBlocks(adapter, infos, ((StackValue.Local)remapper.remap(parameters.totalSize() + 1).value).index);
291
292 adapter.accept(new InliningInstructionAdapter(codegen.v));
293
294 addInlineMarker(codegen.v, false);
295
296 return result;
297 }
298
299 private void generateClosuresBodies() {
300 for (LambdaInfo info : expressionMap.values()) {
301 info.setNode(generateLambdaBody(info));
302 }
303 }
304
305 private SMAPAndMethodNode generateLambdaBody(LambdaInfo info) {
306 JetExpression declaration = info.getFunctionWithBodyOrCallableReference();
307 FunctionDescriptor descriptor = info.getFunctionDescriptor();
308
309 MethodContext parentContext = codegen.getContext();
310
311 MethodContext context = parentContext.intoClosure(descriptor, codegen, typeMapper).intoInlinedLambda(descriptor);
312
313 JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature(descriptor);
314 Method asmMethod = jvmMethodSignature.getAsmMethod();
315 MethodNode methodNode = new MethodNode(InlineCodegenUtil.API, getMethodAsmFlags(descriptor, context.getContextKind()), asmMethod.getName(), asmMethod.getDescriptor(), jvmMethodSignature.getGenericsSignature(), null);
316
317 MethodVisitor adapter = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode);
318
319 SMAP smap = generateMethodBody(adapter, descriptor, context, declaration, jvmMethodSignature, true);
320 adapter.visitMaxs(-1, -1);
321 return new SMAPAndMethodNode(methodNode, smap);
322 }
323
324 private SMAP generateMethodBody(
325 @NotNull MethodVisitor adapter,
326 @NotNull FunctionDescriptor descriptor,
327 @NotNull MethodContext context,
328 @NotNull JetExpression expression,
329 @NotNull JvmMethodSignature jvmMethodSignature,
330 boolean isLambda
331 ) {
332 FakeMemberCodegen parentCodegen =
333 new FakeMemberCodegen(codegen.getParentCodegen(), expression,
334 (FieldOwnerContext) context.getParentContext(),
335 isLambda ? codegen.getParentCodegen().getClassName() : typeMapper.mapOwner(descriptor, false).getInternalName());
336
337 FunctionGenerationStrategy strategy =
338 expression instanceof JetCallableReferenceExpression ?
339 new FunctionReferenceGenerationStrategy(
340 state,
341 descriptor,
342 getResolvedCallWithAssert(((JetCallableReferenceExpression) expression).getCallableReference(),
343 codegen.getBindingContext()
344 )) :
345 new FunctionGenerationStrategy.FunctionDefault(state, descriptor, (JetDeclarationWithBody) expression);
346
347 FunctionCodegen.generateMethodBody(
348 adapter, descriptor, context, jvmMethodSignature,
349 strategy,
350 // Wrapping for preventing marking actual parent codegen as containing reifier markers
351 parentCodegen
352 );
353
354 return createSMAPWithDefaultMapping(expression, parentCodegen.getOrCreateSourceMapper().getResultMappings());
355 }
356
357 private static SMAP createSMAPWithDefaultMapping(
358 @NotNull JetExpression declaration,
359 @NotNull List<FileMapping> mappings
360 ) {
361 PsiFile containingFile = declaration.getContainingFile();
362 Integer lineNumbers = CodegenUtil.getLineNumberForElement(containingFile, true);
363 assert lineNumbers != null : "Couldn't extract line count in " + containingFile;
364
365 return new SMAP(mappings);
366 }
367
368 private static class FakeMemberCodegen extends MemberCodegen {
369
370 private final MemberCodegen delegate;
371 @NotNull private final String className;
372
373 public FakeMemberCodegen(@NotNull MemberCodegen wrapped, @NotNull JetElement declaration, @NotNull FieldOwnerContext codegenContext, @NotNull String className) {
374 super(wrapped, declaration, codegenContext);
375 delegate = wrapped;
376 this.className = className;
377 }
378
379 @Override
380 protected void generateDeclaration() {
381 throw new IllegalStateException();
382 }
383
384 @Override
385 protected void generateBody() {
386 throw new IllegalStateException();
387 }
388
389 @Override
390 protected void generateKotlinAnnotation() {
391 throw new IllegalStateException();
392 }
393
394 @NotNull
395 @Override
396 public NameGenerator getInlineNameGenerator() {
397 return delegate.getInlineNameGenerator();
398 }
399
400 @NotNull
401 @Override
402 //TODO: obtain name from context
403 public String getClassName() {
404 return className;
405 }
406 }
407
408 @Override
409 public void afterParameterPut(@NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor valueParameterDescriptor) {
410 putCapturedInLocal(type, stackValue, valueParameterDescriptor, -1);
411 }
412
413 private void putCapturedInLocal(
414 @NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor valueParameterDescriptor, int capturedParamIndex
415 ) {
416 if (!asFunctionInline && Type.VOID_TYPE != type) {
417 //TODO remap only inlinable closure => otherwise we could get a lot of problem
418 boolean couldBeRemapped = !shouldPutValue(type, stackValue, valueParameterDescriptor);
419 StackValue remappedIndex = couldBeRemapped ? stackValue : null;
420
421 ParameterInfo info;
422 if (capturedParamIndex >= 0) {
423 CapturedParamDesc capturedParamInfoInLambda = activeLambda.getCapturedVars().get(capturedParamIndex);
424 info = invocationParamBuilder.addCapturedParam(capturedParamInfoInLambda, capturedParamInfoInLambda.getFieldName());
425 info.setRemapValue(remappedIndex);
426 }
427 else {
428 info = invocationParamBuilder.addNextParameter(type, false, remappedIndex);
429 }
430
431 putParameterOnStack(info);
432 }
433 }
434
435 /*descriptor is null for captured vars*/
436 public boolean shouldPutValue(
437 @NotNull Type type,
438 @Nullable StackValue stackValue,
439 @Nullable ValueParameterDescriptor descriptor
440 ) {
441
442 if (stackValue == null) {
443 //default or vararg
444 return true;
445 }
446
447 //remap only inline functions (and maybe non primitives)
448 //TODO - clean asserion and remapping logic
449 if (isPrimitive(type) != isPrimitive(stackValue.type)) {
450 //don't remap boxing/unboxing primitives - lost identity and perfomance
451 return true;
452 }
453
454 if (stackValue instanceof StackValue.Local) {
455 return false;
456 }
457
458 StackValue field = stackValue;
459 if (stackValue instanceof StackValue.FieldForSharedVar) {
460 field = ((StackValue.FieldForSharedVar) stackValue).receiver;
461 }
462
463 //check that value corresponds to captured inlining parameter
464 if (field instanceof StackValue.Field) {
465 DeclarationDescriptor varDescriptor = ((StackValue.Field) field).descriptor;
466 //check that variable is inline function parameter
467 return !(varDescriptor instanceof ParameterDescriptor &&
468 InlineUtil.isInlineLambdaParameter((ParameterDescriptor) varDescriptor) &&
469 InlineUtil.isInline(varDescriptor.getContainingDeclaration()));
470 }
471
472 return true;
473 }
474
475 private void putParameterOnStack(ParameterInfo... infos) {
476 int[] index = new int[infos.length];
477 for (int i = 0; i < infos.length; i++) {
478 ParameterInfo info = infos[i];
479 if (!info.isSkippedOrRemapped()) {
480 index[i] = codegen.getFrameMap().enterTemp(info.getType());
481 }
482 else {
483 index[i] = -1;
484 }
485 }
486
487 for (int i = infos.length - 1; i >= 0; i--) {
488 ParameterInfo info = infos[i];
489 if (!info.isSkippedOrRemapped()) {
490 Type type = info.type;
491 StackValue.local(index[i], type).store(StackValue.onStack(type), codegen.v);
492 }
493 }
494 }
495
496 @Override
497 public void putHiddenParams() {
498 List<JvmMethodParameterSignature> valueParameters = jvmSignature.getValueParameters();
499
500 if (!isStaticMethod(functionDescriptor, context)) {
501 invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false, null);
502 }
503
504 for (JvmMethodParameterSignature param : valueParameters) {
505 if (param.getKind() == JvmMethodParameterKind.VALUE) {
506 break;
507 }
508 invocationParamBuilder.addNextParameter(param.getAsmType(), false, null);
509 }
510
511 List<ParameterInfo> infos = invocationParamBuilder.listNotCaptured();
512 putParameterOnStack(infos.toArray(new ParameterInfo[infos.size()]));
513 }
514
515 public void leaveTemps() {
516 FrameMap frameMap = codegen.getFrameMap();
517 List<ParameterInfo> infos = invocationParamBuilder.listAllParams();
518 for (ListIterator<? extends ParameterInfo> iterator = infos.listIterator(infos.size()); iterator.hasPrevious(); ) {
519 ParameterInfo param = iterator.previous();
520 if (!param.isSkippedOrRemapped()) {
521 frameMap.leaveTemp(param.type);
522 }
523 }
524 }
525
526 /*lambda or callable reference*/
527 public static boolean isInliningParameter(JetExpression expression, ValueParameterDescriptor valueParameterDescriptor) {
528 //TODO deparenthisise typed
529 JetExpression deparenthesized = JetPsiUtil.deparenthesize(expression);
530 return InlineUtil.isInlineLambdaParameter(valueParameterDescriptor) &&
531 isInlinableParameterExpression(deparenthesized);
532 }
533
534 protected static boolean isInlinableParameterExpression(JetExpression deparenthesized) {
535 return deparenthesized instanceof JetFunctionLiteralExpression ||
536 deparenthesized instanceof JetNamedFunction ||
537 deparenthesized instanceof JetCallableReferenceExpression;
538 }
539
540 public void rememberClosure(JetExpression expression, Type type) {
541 JetExpression lambda = JetPsiUtil.deparenthesize(expression);
542 assert isInlinableParameterExpression(lambda) : "Couldn't find inline expression in " + expression.getText();
543
544 LambdaInfo info = new LambdaInfo(lambda, typeMapper);
545
546 ParameterInfo closureInfo = invocationParamBuilder.addNextParameter(type, true, null);
547 closureInfo.setLambda(info);
548 expressionMap.put(closureInfo.getIndex(), info);
549 }
550
551 @NotNull
552 protected static Set<String> getDeclarationLabels(@Nullable PsiElement lambdaOrFun, @NotNull DeclarationDescriptor descriptor) {
553 Set<String> result = new HashSet<String>();
554 if (lambdaOrFun != null) {
555 PsiElement parent = lambdaOrFun.getParent();
556 if (parent instanceof JetLabeledExpression) {
557 String labelName = ((JetLabeledExpression) parent).getLabelName();
558 assert labelName != null : "Labeled expression should have not nul label " + parent.getText();
559 result.add(labelName);
560 }
561 }
562 if (!isFunctionLiteral(descriptor)) {
563 if (!descriptor.getName().isSpecial()) {
564 result.add(descriptor.getName().asString());
565 }
566 result.add(InlineCodegenUtil.FIRST_FUN_LABEL);
567 }
568 return result;
569 }
570
571 private void putClosureParametersOnStack() {
572 for (LambdaInfo next : expressionMap.values()) {
573 activeLambda = next;
574 codegen.pushClosureOnStack(next.getClassDescriptor(), true, this);
575 }
576 activeLambda = null;
577 }
578
579 public static CodegenContext getContext(DeclarationDescriptor descriptor, GenerationState state) {
580 if (descriptor instanceof PackageFragmentDescriptor) {
581 return new PackageContext((PackageFragmentDescriptor) descriptor, null, null);
582 }
583
584 CodegenContext parent = getContext(descriptor.getContainingDeclaration(), state);
585
586 if (descriptor instanceof ClassDescriptor) {
587 OwnerKind kind = DescriptorUtils.isTrait(descriptor) ? OwnerKind.TRAIT_IMPL : OwnerKind.IMPLEMENTATION;
588 return parent.intoClass((ClassDescriptor) descriptor, kind, state);
589 }
590 else if (descriptor instanceof ScriptDescriptor) {
591 ClassDescriptor classDescriptorForScript = state.getBindingContext().get(CLASS_FOR_SCRIPT, (ScriptDescriptor) descriptor);
592 assert classDescriptorForScript != null : "Can't find class for script: " + descriptor;
593 List<ScriptDescriptor> earlierScripts = state.getEarlierScriptsForReplInterpreter();
594 return parent.intoScript((ScriptDescriptor) descriptor,
595 earlierScripts == null ? Collections.emptyList() : earlierScripts,
596 classDescriptorForScript);
597 }
598 else if (descriptor instanceof FunctionDescriptor) {
599 return parent.intoFunction((FunctionDescriptor) descriptor);
600 }
601
602 throw new IllegalStateException("Couldn't build context for " + descriptorName(descriptor));
603 }
604
605 private static boolean isStaticMethod(FunctionDescriptor functionDescriptor, MethodContext context) {
606 return (getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) != 0;
607 }
608
609 private static String descriptorName(DeclarationDescriptor descriptor) {
610 return DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor);
611 }
612
613 @Override
614 public void genValueAndPut(
615 @NotNull ValueParameterDescriptor valueParameterDescriptor,
616 @NotNull JetExpression argumentExpression,
617 @NotNull Type parameterType
618 ) {
619 if (isInliningParameter(argumentExpression, valueParameterDescriptor)) {
620 rememberClosure(argumentExpression, parameterType);
621 }
622 else {
623 StackValue value = codegen.gen(argumentExpression);
624 putValueIfNeeded(valueParameterDescriptor, parameterType, value);
625 }
626 }
627
628 @Override
629 public void putValueIfNeeded(@Nullable ValueParameterDescriptor valueParameterDescriptor, @NotNull Type parameterType, @NotNull StackValue value) {
630 if (shouldPutValue(parameterType, value, valueParameterDescriptor)) {
631 value.put(parameterType, codegen.v);
632 }
633 afterParameterPut(parameterType, value, valueParameterDescriptor);
634 }
635
636 @Override
637 public void putCapturedValueOnStack(
638 @NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex
639 ) {
640 if (shouldPutValue(stackValue.type, stackValue, null)) {
641 stackValue.put(stackValue.type, codegen.v);
642 }
643 putCapturedInLocal(stackValue.type, stackValue, null, paramIndex);
644 }
645
646
647 public void generateAndInsertFinallyBlocks(
648 MethodNode intoNode,
649 List<MethodInliner.PointForExternalFinallyBlocks> insertPoints,
650 int offsetForFinallyLocalVar
651 ) {
652 if (!codegen.hasFinallyBlocks()) return;
653
654 Map<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks> extensionPoints =
655 new HashMap<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks>();
656 for (MethodInliner.PointForExternalFinallyBlocks insertPoint : insertPoints) {
657 extensionPoints.put(insertPoint.beforeIns, insertPoint);
658 }
659
660 DefaultProcessor processor = new DefaultProcessor(intoNode, offsetForFinallyLocalVar);
661
662 AbstractInsnNode curInstr = intoNode.instructions.getFirst();
663 while (curInstr != null) {
664 processor.processInstruction(curInstr, true);
665
666 MethodInliner.PointForExternalFinallyBlocks extension = extensionPoints.get(curInstr);
667 if (extension != null) {
668 Label start = new Label();
669 Label end = new Label();
670
671 MethodNode finallyNode = InlineCodegenUtil.createEmptyMethodNode();
672 finallyNode.visitLabel(start);
673
674 ExpressionCodegen finallyCodegen =
675 new ExpressionCodegen(finallyNode, codegen.getFrameMap(), codegen.getReturnType(),
676 codegen.getContext(), codegen.getState(), codegen.getParentCodegen());
677 finallyCodegen.addBlockStackElementsForNonLocalReturns(codegen.getBlockStackElements());
678
679 FrameMap frameMap = finallyCodegen.getFrameMap();
680 FrameMap.Mark mark = frameMap.mark();
681 while (frameMap.getCurrentSize() < processor.getNextFreeLocalIndex()) {
682 frameMap.enterTemp(Type.INT_TYPE);
683 }
684
685 finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType);
686 finallyNode.visitLabel(end);
687 //Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method
688 InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr);
689
690 SimpleInterval splitBy = new SimpleInterval((LabelNode) start.info, (LabelNode) end.info);
691 processor.getTryBlocksMetaInfo().splitCurrentIntervals(splitBy, false);
692
693 processor.getLocalVarsMetaInfo().splitCurrentIntervals(splitBy, false);
694
695 mark.dropTo();
696 }
697
698 curInstr = curInstr.getNext();
699 }
700
701 processor.substituteTryBlockNodes(intoNode);
702
703 //processor.substituteLocalVarTable(intoNode);
704 }
705
706 private SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap) {
707 return new NestedSourceMapper(sourceMapper, nodeAndSmap.getRanges(), nodeAndSmap.getClassSMAP().getSourceInfo());
708 }
709
710 }