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.context; 018 019 import org.jetbrains.annotations.NotNull; 020 import org.jetbrains.kotlin.codegen.ExpressionCodegen; 021 import org.jetbrains.kotlin.codegen.JvmCodegenUtil; 022 import org.jetbrains.kotlin.codegen.StackValue; 023 import org.jetbrains.kotlin.codegen.binding.MutableClosure; 024 import org.jetbrains.kotlin.codegen.state.GenerationState; 025 import org.jetbrains.kotlin.descriptors.*; 026 import org.jetbrains.kotlin.load.java.JvmAbi; 027 import org.jetbrains.kotlin.resolve.BindingContext; 028 import org.jetbrains.kotlin.types.JetType; 029 import org.jetbrains.org.objectweb.asm.Type; 030 031 import static org.jetbrains.kotlin.codegen.AsmUtil.CAPTURED_RECEIVER_FIELD; 032 import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*; 033 034 public interface LocalLookup { 035 boolean lookupLocal(DeclarationDescriptor descriptor); 036 037 enum LocalLookupCase { 038 VAR { 039 @Override 040 public boolean isCase(DeclarationDescriptor d) { 041 return d instanceof VariableDescriptor && !(d instanceof PropertyDescriptor); 042 } 043 044 @Override 045 public StackValue.StackValueWithSimpleReceiver innerValue( 046 DeclarationDescriptor d, 047 LocalLookup localLookup, 048 GenerationState state, 049 MutableClosure closure, 050 Type classType 051 ) { 052 VariableDescriptor vd = (VariableDescriptor) d; 053 054 boolean idx = localLookup != null && localLookup.lookupLocal(vd); 055 if (!idx) return null; 056 057 Type sharedVarType = state.getTypeMapper().getSharedVarType(vd); 058 Type localType = state.getTypeMapper().mapType(vd); 059 Type type = sharedVarType != null ? sharedVarType : localType; 060 061 String fieldName = "$" + vd.getName(); 062 StackValue.Local thiz = StackValue.LOCAL_0; 063 StackValue.StackValueWithSimpleReceiver innerValue = sharedVarType != null 064 ? StackValue.fieldForSharedVar(localType, classType, fieldName, thiz) 065 : StackValue.field(type, classType, fieldName, false, thiz); 066 067 closure.recordField(fieldName, type); 068 closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, type)); 069 070 return innerValue; 071 } 072 }, 073 074 LOCAL_NAMED_FUNCTION { 075 @Override 076 public boolean isCase(DeclarationDescriptor d) { 077 return isLocalNamedFun(d); 078 } 079 080 @Override 081 public StackValue.StackValueWithSimpleReceiver innerValue( 082 DeclarationDescriptor d, 083 LocalLookup localLookup, 084 GenerationState state, 085 MutableClosure closure, 086 Type classType 087 ) { 088 FunctionDescriptor vd = (FunctionDescriptor) d; 089 090 boolean idx = localLookup != null && localLookup.lookupLocal(vd); 091 if (!idx) return null; 092 093 BindingContext bindingContext = state.getBindingContext(); 094 Type localType = asmTypeForAnonymousClass(bindingContext, vd); 095 096 MutableClosure localFunClosure = bindingContext.get(CLOSURE, bindingContext.get(CLASS_FOR_FUNCTION, vd)); 097 if (localFunClosure != null && JvmCodegenUtil.isConst(localFunClosure)) { 098 // This is an optimization: we can obtain an instance of a const closure simply by GETSTATIC ...$instance 099 // (instead of passing this instance to the constructor and storing as a field) 100 return StackValue.field(localType, localType, JvmAbi.INSTANCE_FIELD, true, StackValue.LOCAL_0); 101 } 102 103 String fieldName = "$" + vd.getName(); 104 StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(localType, classType, fieldName, false, 105 StackValue.LOCAL_0); 106 107 closure.recordField(fieldName, localType); 108 closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, localType)); 109 110 return innerValue; 111 } 112 }, 113 114 RECEIVER { 115 @Override 116 public boolean isCase(DeclarationDescriptor d) { 117 return d instanceof ReceiverParameterDescriptor; 118 } 119 120 @Override 121 public StackValue.StackValueWithSimpleReceiver innerValue( 122 DeclarationDescriptor d, 123 LocalLookup enclosingLocalLookup, 124 GenerationState state, 125 MutableClosure closure, 126 Type classType 127 ) { 128 if (closure.getEnclosingReceiverDescriptor() != d) { 129 return null; 130 } 131 132 JetType receiverType = closure.getEnclosingReceiverDescriptor().getType(); 133 Type type = state.getTypeMapper().mapType(receiverType); 134 StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(type, classType, CAPTURED_RECEIVER_FIELD, false, 135 StackValue.LOCAL_0); 136 closure.setCaptureReceiver(); 137 138 return innerValue; 139 } 140 141 @NotNull 142 @Override 143 public StackValue outerValue(@NotNull EnclosedValueDescriptor d, @NotNull ExpressionCodegen codegen) { 144 CallableDescriptor descriptor = (CallableDescriptor) d.getDescriptor(); 145 return StackValue.local(descriptor.getDispatchReceiverParameter() != null ? 1 : 0, d.getType()); 146 } 147 }; 148 149 public abstract boolean isCase(DeclarationDescriptor d); 150 151 public abstract StackValue.StackValueWithSimpleReceiver innerValue( 152 DeclarationDescriptor d, 153 LocalLookup localLookup, 154 GenerationState state, 155 MutableClosure closure, 156 Type classType 157 ); 158 159 @NotNull 160 public StackValue outerValue(@NotNull EnclosedValueDescriptor d, @NotNull ExpressionCodegen codegen) { 161 int idx = codegen.lookupLocalIndex(d.getDescriptor()); 162 assert idx != -1; 163 164 return StackValue.local(idx, d.getType()); 165 } 166 } 167 }