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