001 /* 002 * Copyright 2010-2014 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.binding; 018 019 import com.intellij.openapi.vfs.VirtualFile; 020 import org.jetbrains.annotations.NotNull; 021 import org.jetbrains.annotations.Nullable; 022 import org.jetbrains.asm4.Type; 023 import org.jetbrains.jet.codegen.state.GenerationState; 024 import org.jetbrains.jet.lang.descriptors.*; 025 import org.jetbrains.jet.lang.descriptors.impl.ClassDescriptorImpl; 026 import org.jetbrains.jet.lang.psi.*; 027 import org.jetbrains.jet.lang.resolve.BindingContext; 028 import org.jetbrains.jet.lang.resolve.BindingTrace; 029 import org.jetbrains.jet.lang.resolve.java.JvmAbi; 030 import org.jetbrains.jet.lang.resolve.java.descriptor.JavaClassDescriptor; 031 import org.jetbrains.jet.lang.resolve.name.FqName; 032 import org.jetbrains.jet.lang.resolve.name.Name; 033 import org.jetbrains.jet.lang.resolve.scopes.JetScope; 034 import org.jetbrains.jet.lang.types.JetType; 035 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 036 import org.jetbrains.jet.util.slicedmap.Slices; 037 import org.jetbrains.jet.util.slicedmap.WritableSlice; 038 039 import java.util.*; 040 041 import static org.jetbrains.jet.codegen.CodegenUtil.isInterface; 042 import static org.jetbrains.jet.lang.resolve.BindingContext.*; 043 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumClass; 044 045 public class CodegenBinding { 046 public static final WritableSlice<ClassDescriptor, MutableClosure> CLOSURE = Slices.createSimpleSlice(); 047 048 public static final WritableSlice<FunctionDescriptor, ClassDescriptor> CLASS_FOR_FUNCTION = Slices.createSimpleSlice(); 049 050 public static final WritableSlice<ScriptDescriptor, ClassDescriptor> CLASS_FOR_SCRIPT = Slices.createSimpleSlice(); 051 052 public static final WritableSlice<ClassDescriptor, Type> ASM_TYPE = Slices.createSimpleSlice(); 053 054 public static final WritableSlice<ClassDescriptor, Boolean> ENUM_ENTRY_CLASS_NEED_SUBCLASS = Slices.createSimpleSetSlice(); 055 056 public static final WritableSlice<ClassDescriptor, Collection<ClassDescriptor>> INNER_CLASSES = Slices.createSimpleSlice(); 057 058 public static final WritableSlice<JetExpression, JavaClassDescriptor> SAM_VALUE = Slices.createSimpleSlice(); 059 060 private CodegenBinding() { 061 } 062 063 public static void initTrace(BindingTrace bindingTrace, Collection<JetFile> files) { 064 initTrace(bindingTrace, files, GenerationState.GenerateClassFilter.GENERATE_ALL); 065 } 066 067 public static void initTrace(BindingTrace bindingTrace, Collection<JetFile> files, GenerationState.GenerateClassFilter filter) { 068 CodegenAnnotatingVisitor visitor = new CodegenAnnotatingVisitor(bindingTrace, filter); 069 for (JetFile file : allFilesInPackages(bindingTrace.getBindingContext(), files)) { 070 file.accept(visitor); 071 } 072 } 073 074 public static boolean enumEntryNeedSubclass(BindingContext bindingContext, JetEnumEntry enumEntry) { 075 return enumEntryNeedSubclass(bindingContext, bindingContext.get(CLASS, enumEntry)); 076 } 077 078 public static boolean enumEntryNeedSubclass(BindingContext bindingContext, ClassDescriptor classDescriptor) { 079 return Boolean.TRUE.equals(bindingContext.get(ENUM_ENTRY_CLASS_NEED_SUBCLASS, classDescriptor)); 080 } 081 082 @NotNull 083 public static Type asmTypeForScriptDescriptor(BindingContext bindingContext, @NotNull ScriptDescriptor scriptDescriptor) { 084 ClassDescriptor classDescriptor = bindingContext.get(CLASS_FOR_SCRIPT, scriptDescriptor); 085 //noinspection ConstantConditions 086 return asmType(bindingContext, classDescriptor); 087 } 088 089 @NotNull 090 public static Type asmTypeForScriptPsi(BindingContext bindingContext, @NotNull JetScript script) { 091 ScriptDescriptor scriptDescriptor = bindingContext.get(SCRIPT, script); 092 if (scriptDescriptor == null) { 093 throw new IllegalStateException("Script descriptor not found by PSI " + script); 094 } 095 return asmTypeForScriptDescriptor(bindingContext, scriptDescriptor); 096 } 097 098 public static ClassDescriptor enclosingClassDescriptor(BindingContext bindingContext, ClassDescriptor descriptor) { 099 CalculatedClosure closure = bindingContext.get(CLOSURE, descriptor); 100 return closure == null ? null : closure.getEnclosingClass(); 101 } 102 103 @NotNull 104 public static ClassDescriptor anonymousClassForFunction( 105 @NotNull BindingContext bindingContext, 106 @NotNull FunctionDescriptor descriptor 107 ) { 108 //noinspection ConstantConditions 109 return bindingContext.get(CLASS_FOR_FUNCTION, descriptor); 110 } 111 112 @NotNull 113 private static Type asmType(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor descriptor) { 114 //noinspection ConstantConditions 115 return bindingContext.get(ASM_TYPE, descriptor); 116 } 117 118 @NotNull 119 public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull JetElement expression) { 120 if (expression instanceof JetObjectLiteralExpression) { 121 JetObjectLiteralExpression jetObjectLiteralExpression = (JetObjectLiteralExpression) expression; 122 expression = jetObjectLiteralExpression.getObjectDeclaration(); 123 } 124 125 ClassDescriptor descriptor = bindingContext.get(CLASS, expression); 126 if (descriptor == null) { 127 SimpleFunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression); 128 assert functionDescriptor != null; 129 return asmTypeForAnonymousClass(bindingContext, functionDescriptor); 130 } 131 132 return asmType(bindingContext, descriptor); 133 } 134 135 @NotNull 136 public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull FunctionDescriptor descriptor) { 137 ClassDescriptor classDescriptor = anonymousClassForFunction(bindingContext, descriptor); 138 return asmType(bindingContext, classDescriptor); 139 } 140 141 public static void registerClassNameForScript( 142 BindingTrace bindingTrace, 143 @NotNull ScriptDescriptor scriptDescriptor, 144 @NotNull Type asmType 145 ) { 146 ClassDescriptorImpl classDescriptor = 147 new ClassDescriptorImpl(scriptDescriptor, Name.special("<script-" + asmType.getInternalName() + ">"), Modality.FINAL, 148 Collections.singleton(KotlinBuiltIns.getInstance().getAnyType())); 149 classDescriptor.initialize(JetScope.EMPTY, Collections.<ConstructorDescriptor>emptySet(), null); 150 151 recordClosure(bindingTrace, null, classDescriptor, null, asmType); 152 153 bindingTrace.record(CLASS_FOR_SCRIPT, scriptDescriptor, classDescriptor); 154 } 155 156 public static boolean canHaveOuter(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor classDescriptor) { 157 if (classDescriptor.getKind() != ClassKind.CLASS) { 158 return false; 159 } 160 161 ClassDescriptor enclosing = enclosingClassDescriptor(bindingContext, classDescriptor); 162 if (enclosing == null) { 163 return false; 164 } 165 166 return classDescriptor.isInner() || !(classDescriptor.getContainingDeclaration() instanceof ClassDescriptor); 167 } 168 169 static void recordClosure( 170 BindingTrace bindingTrace, 171 @Nullable JetElement element, 172 ClassDescriptor classDescriptor, 173 @Nullable ClassDescriptor enclosing, 174 Type asmType 175 ) { 176 JetDelegatorToSuperCall superCall = findSuperCall(bindingTrace.getBindingContext(), element); 177 178 CallableDescriptor enclosingReceiver = null; 179 if (classDescriptor.getContainingDeclaration() instanceof CallableDescriptor) { 180 enclosingReceiver = (CallableDescriptor) classDescriptor.getContainingDeclaration(); 181 enclosingReceiver = enclosingReceiver instanceof PropertyAccessorDescriptor 182 ? ((PropertyAccessorDescriptor) enclosingReceiver).getCorrespondingProperty() 183 : enclosingReceiver; 184 185 if (enclosingReceiver.getReceiverParameter() == null) { 186 enclosingReceiver = null; 187 } 188 } 189 190 MutableClosure closure = new MutableClosure(superCall, enclosing, enclosingReceiver); 191 192 assert PsiCodegenPredictor.checkPredictedNameFromPsi(bindingTrace, classDescriptor, asmType); 193 bindingTrace.record(ASM_TYPE, classDescriptor, asmType); 194 bindingTrace.record(CLOSURE, classDescriptor, closure); 195 196 if (classDescriptor.isInner()) { 197 closure.setCaptureThis(); 198 } 199 200 //TEMPORARY EAT INNER CLASS INFO FOR FUNCTION LITERALS 201 //TODO: we should understand that lambda/closure would be inlined and don't generate inner class record 202 if (enclosing != null && !(element instanceof JetFunctionLiteral)) { 203 recordInnerClass(bindingTrace, enclosing, classDescriptor); 204 } 205 } 206 207 private static void recordInnerClass( 208 @NotNull BindingTrace bindingTrace, 209 @NotNull ClassDescriptor outer, 210 @NotNull ClassDescriptor inner 211 ) { 212 Collection<ClassDescriptor> innerClasses = bindingTrace.get(INNER_CLASSES, outer); 213 if (innerClasses == null) { 214 innerClasses = new ArrayList<ClassDescriptor>(); 215 bindingTrace.record(INNER_CLASSES, outer, innerClasses); 216 } 217 innerClasses.add(inner); 218 } 219 220 public static void registerClassNameForScript( 221 BindingTrace bindingTrace, 222 @NotNull JetScript jetScript, 223 @NotNull Type asmType 224 ) { 225 ScriptDescriptor descriptor = bindingTrace.getBindingContext().get(SCRIPT, jetScript); 226 if (descriptor == null) { 227 throw new IllegalStateException("Descriptor is not found for PSI " + jetScript); 228 } 229 registerClassNameForScript(bindingTrace, descriptor, asmType); 230 } 231 232 @NotNull 233 public static Collection<JetFile> allFilesInPackages(BindingContext bindingContext, Collection<JetFile> files) { 234 // todo: we use Set and add given files but ignoring other scripts because something non-clear kept in binding 235 // for scripts especially in case of REPL 236 237 HashSet<FqName> names = new HashSet<FqName>(); 238 for (JetFile file : files) { 239 if (!file.isScript()) { 240 names.add(JetPsiUtil.getFQName(file)); 241 } 242 } 243 244 HashSet<JetFile> answer = new HashSet<JetFile>(); 245 answer.addAll(files); 246 247 for (FqName name : names) { 248 Collection<JetFile> jetFiles = bindingContext.get(PACKAGE_TO_FILES, name); 249 if (jetFiles != null) { 250 answer.addAll(jetFiles); 251 } 252 } 253 254 List<JetFile> sortedAnswer = new ArrayList<JetFile>(answer); 255 Collections.sort(sortedAnswer, new Comparator<JetFile>() { 256 @NotNull 257 private String path(JetFile file) { 258 VirtualFile virtualFile = file.getVirtualFile(); 259 assert virtualFile != null : "VirtualFile is null for JetFile: " + file.getName(); 260 return virtualFile.getPath(); 261 } 262 263 @Override 264 public int compare(@NotNull JetFile first, @NotNull JetFile second) { 265 return path(first).compareTo(path(second)); 266 } 267 }); 268 269 return sortedAnswer; 270 } 271 272 public static boolean isLocalNamedFun(DeclarationDescriptor fd) { 273 if (fd instanceof FunctionDescriptor) { 274 FunctionDescriptor descriptor = (FunctionDescriptor) fd; 275 return descriptor.getVisibility() == Visibilities.LOCAL && !descriptor.getName().isSpecial(); 276 } 277 return false; 278 } 279 280 @NotNull 281 public static Type getAsmType(@NotNull BindingTrace bindingTrace, @NotNull ClassDescriptor klass) { 282 klass = (ClassDescriptor) klass.getOriginal(); 283 Type alreadyComputedType = bindingTrace.getBindingContext().get(ASM_TYPE, klass); 284 if (alreadyComputedType != null) { 285 return alreadyComputedType; 286 } 287 288 Type asmType = Type.getObjectType(getAsmTypeImpl(bindingTrace, klass)); 289 290 assert PsiCodegenPredictor.checkPredictedNameFromPsi(bindingTrace, klass, asmType); 291 bindingTrace.record(ASM_TYPE, klass, asmType); 292 return asmType; 293 } 294 295 @NotNull 296 private static String getAsmTypeImpl(@NotNull BindingTrace bindingTrace, @NotNull ClassDescriptor klass) { 297 DeclarationDescriptor container = klass.getContainingDeclaration(); 298 299 if (container instanceof PackageFragmentDescriptor) { 300 String shortName = klass.getName().getIdentifier(); 301 FqName fqName = ((PackageFragmentDescriptor) container).getFqName(); 302 return fqName.isRoot() ? shortName : fqName.asString().replace('.', '/') + '/' + shortName; 303 } 304 305 assert container instanceof ClassDescriptor : "Unexpected container: " + container + " for " + klass; 306 307 String containerInternalName = getAsmType(bindingTrace, (ClassDescriptor) container).getInternalName(); 308 if (klass.getKind() == ClassKind.OBJECT || klass.getKind() == ClassKind.CLASS_OBJECT) { 309 if (isEnumClass(container)) { 310 return containerInternalName; 311 } 312 else if (klass.getKind() == ClassKind.OBJECT) { 313 return containerInternalName + "$" + klass.getName(); 314 } 315 else { 316 return containerInternalName + JvmAbi.CLASS_OBJECT_SUFFIX; 317 } 318 } 319 return containerInternalName + "$" + klass.getName().getIdentifier(); 320 } 321 322 public static boolean hasThis0(BindingContext bindingContext, ClassDescriptor classDescriptor) { 323 //noinspection SuspiciousMethodCalls 324 CalculatedClosure closure = bindingContext.get(CLOSURE, classDescriptor); 325 return closure != null && closure.getCaptureThis() != null; 326 } 327 328 private static JetDelegatorToSuperCall findSuperCall(BindingContext bindingContext, JetElement classOrObject) { 329 if (!(classOrObject instanceof JetClassOrObject)) { 330 return null; 331 } 332 333 if (classOrObject instanceof JetClass && ((JetClass) classOrObject).isTrait()) { 334 return null; 335 } 336 337 for (JetDelegationSpecifier specifier : ((JetClassOrObject) classOrObject).getDelegationSpecifiers()) { 338 if (specifier instanceof JetDelegatorToSuperCall) { 339 JetTypeReference typeReference = specifier.getTypeReference(); 340 341 JetType superType = bindingContext.get(TYPE, typeReference); 342 assert superType != null: String.format( 343 "No type in binding context for \n---\n%s\n---\n", JetPsiUtil.getElementTextWithContext(specifier)); 344 345 ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); 346 assert superClassDescriptor != null; 347 if (!isInterface(superClassDescriptor)) { 348 return (JetDelegatorToSuperCall) specifier; 349 } 350 } 351 } 352 353 return null; 354 } 355 356 @NotNull 357 public static Collection<ClassDescriptor> getAllInnerClasses( 358 @NotNull BindingContext bindingContext, @NotNull ClassDescriptor outermostClass 359 ) { 360 Collection<ClassDescriptor> innerClasses = bindingContext.get(INNER_CLASSES, outermostClass); 361 if (innerClasses == null || innerClasses.isEmpty()) return Collections.emptySet(); 362 363 Set<ClassDescriptor> allInnerClasses = new HashSet<ClassDescriptor>(); 364 365 Deque<ClassDescriptor> stack = new ArrayDeque<ClassDescriptor>(innerClasses); 366 do { 367 ClassDescriptor currentClass = stack.pop(); 368 if (allInnerClasses.add(currentClass)) { 369 Collection<ClassDescriptor> nextClasses = bindingContext.get(INNER_CLASSES, currentClass); 370 if (nextClasses != null) { 371 for (ClassDescriptor nextClass : nextClasses) { 372 stack.push(nextClass); 373 } 374 } 375 } 376 } while (!stack.isEmpty()); 377 378 return allInnerClasses; 379 } 380 381 @NotNull 382 public static String getJvmInternalName(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor classDescriptor) { 383 Type asmType = bindingContext.get(ASM_TYPE, classDescriptor); 384 assert asmType != null : "ASM_TYPE not present for " + classDescriptor; 385 386 String jvmInternalName = asmType.getClassName(); 387 assert jvmInternalName != null : "No internal name for " + asmType + " for class " + classDescriptor; 388 389 return jvmInternalName; 390 } 391 }