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