private static String getJvmInternalFQNameImpl( BindingTrace bindingTrace, DeclarationDescriptor descriptor) { if (descriptor instanceof FunctionDescriptor) { throw new IllegalStateException("requested fq name for function: " + descriptor); } if (descriptor.getContainingDeclaration() instanceof ModuleDescriptor || descriptor instanceof ScriptDescriptor) { return ""; } if (descriptor instanceof ModuleDescriptor) { throw new IllegalStateException("missed something"); } if (descriptor instanceof ClassDescriptor) { ClassDescriptor klass = (ClassDescriptor) descriptor; if (klass.getKind() == ClassKind.OBJECT || klass.getKind() == ClassKind.CLASS_OBJECT) { if (klass.getContainingDeclaration() instanceof ClassDescriptor) { ClassDescriptor containingKlass = (ClassDescriptor) klass.getContainingDeclaration(); if (containingKlass.getKind() == ClassKind.ENUM_CLASS) { return getJvmInternalName(bindingTrace, containingKlass).getInternalName(); } else { return getJvmInternalName(bindingTrace, containingKlass).getInternalName() + JvmAbi.CLASS_OBJECT_SUFFIX; } } } JvmClassName name = bindingTrace.getBindingContext().get(FQN, descriptor); if (name != null) { return name.getInternalName(); } } DeclarationDescriptor container = descriptor.getContainingDeclaration(); if (container == null) { throw new IllegalStateException("descriptor has no container: " + descriptor); } Name name = descriptor.getName(); String baseName = getJvmInternalName(bindingTrace, container).getInternalName(); if (!baseName.isEmpty()) { return baseName + (container instanceof NamespaceDescriptor ? "/" : "$") + name.getIdentifier(); } return name.getIdentifier(); }
@Override public void visitClassObject(JetClassObject classObject) { ClassDescriptor classDescriptor = bindingContext.get(CLASS, classObject.getObjectDeclaration()); assert classDescriptor != null; JvmClassName name = JvmClassName.byInternalName(peekFromStack(nameStack) + JvmAbi.CLASS_OBJECT_SUFFIX); recordClosure( bindingTrace, classObject, classDescriptor, peekFromStack(classStack), name, false); classStack.push(classDescriptor); nameStack.push(name.getInternalName()); super.visitClassObject(classObject); nameStack.pop(); classStack.pop(); }
@Override public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) { ClassDescriptor classDescriptor = bindingContext.get(CLASS, expression.getObjectDeclaration()); if (classDescriptor == null) { // working around a problem with shallow analysis super.visitObjectLiteralExpression(expression); return; } final String name = inventAnonymousClassName(expression.getObjectDeclaration()); recordClosure( bindingTrace, expression.getObjectDeclaration(), classDescriptor, peekFromStack(classStack), JvmClassName.byInternalName(name), false); classStack.push(classDescriptor); //noinspection ConstantConditions nameStack.push(bindingContext.get(FQN, classDescriptor).getInternalName()); super.visitObjectLiteralExpression(expression); nameStack.pop(); classStack.pop(); }
@Override public void visitObjectDeclaration(JetObjectDeclaration declaration) { if (declaration.getParent() instanceof JetObjectLiteralExpression || declaration.getParent() instanceof JetClassObject) { super.visitObjectDeclaration(declaration); } else { ClassDescriptor classDescriptor = bindingContext.get(CLASS, declaration); // working around a problem with shallow analysis if (classDescriptor == null) return; String name = getName(classDescriptor); recordClosure( bindingTrace, declaration, classDescriptor, peekFromStack(classStack), JvmClassName.byInternalName(name), false); classStack.push(classDescriptor); nameStack.push(name); super.visitObjectDeclaration(declaration); nameStack.pop(); classStack.pop(); } }
private void invoke(InstructionAdapter v) { v.visitMethodInsn( getInvokeOpcode(), owner.getInternalName(), getSignature().getAsmMethod().getName(), getSignature().getAsmMethod().getDescriptor()); }
private void invokeDefault(InstructionAdapter v, int mask) { if (defaultImplOwner == null || defaultImplParam == null) { throw new IllegalStateException(); } v.iconst(mask); String desc = getSignature().getAsmMethod().getDescriptor().replace(")", "I)"); if ("<init>".equals(getSignature().getAsmMethod().getName())) { v.visitMethodInsn(INVOKESPECIAL, defaultImplOwner.getInternalName(), "<init>", desc); } else { if (getInvokeOpcode() != INVOKESTATIC) { desc = desc.replace("(", "(" + defaultImplParam.getDescriptor()); } v.visitMethodInsn( INVOKESTATIC, defaultImplOwner.getInternalName(), getSignature().getAsmMethod().getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, desc); } }
@NotNull public static JvmClassName getJvmInternalName( BindingTrace bindingTrace, @NotNull DeclarationDescriptor descriptor) { descriptor = descriptor.getOriginal(); JvmClassName name = bindingTrace.getBindingContext().get(FQN, descriptor); if (name != null) { return name; } name = JvmClassName.byInternalName(getJvmInternalFQNameImpl(bindingTrace, descriptor)); assert PsiCodegenPredictor.checkPredictedNameFromPsi(bindingTrace, descriptor, name); bindingTrace.record(FQN, descriptor, name); return name; }
private static void testSignatureName( String className, String innerClassName, String fqName, String outerClassName, List<String> innerClassNameList) { JvmClassName mapEntryName = JvmClassName.bySignatureName(className); assertEquals(innerClassName, mapEntryName.getInternalName()); assertEquals(fqName, mapEntryName.getFqName().asString()); assertEquals(outerClassName, mapEntryName.getOuterClassFqName().asString()); assertEquals(innerClassNameList, mapEntryName.getInnerClassNameList()); }
@Override public void visitClass(JetClass klass) { ClassDescriptor classDescriptor = bindingContext.get(CLASS, klass); // working around a problem with shallow analysis if (classDescriptor == null) return; String name = getName(classDescriptor); recordClosure( bindingTrace, klass, classDescriptor, peekFromStack(classStack), JvmClassName.byInternalName(name), false); classStack.push(classDescriptor); nameStack.push(name); super.visitClass(klass); nameStack.pop(); classStack.pop(); }
@Override public void visitNamedFunction(JetNamedFunction function) { FunctionDescriptor functionDescriptor = (FunctionDescriptor) bindingContext.get(DECLARATION_TO_DESCRIPTOR, function); // working around a problem with shallow analysis if (functionDescriptor == null) return; DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration(); if (containingDeclaration instanceof ClassDescriptor) { nameStack.push(peekFromStack(nameStack) + '$' + function.getName()); super.visitNamedFunction(function); nameStack.pop(); } else if (containingDeclaration instanceof NamespaceDescriptor) { String peek = peekFromStack(nameStack); if (peek.isEmpty()) { peek = JvmAbi.PACKAGE_CLASS; } else { peek += "/" + JvmAbi.PACKAGE_CLASS; } nameStack.push(peek + '$' + function.getName()); super.visitNamedFunction(function); nameStack.pop(); } else { String name = inventAnonymousClassName(function); ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor); recordClosure( bindingTrace, function, classDescriptor, peekFromStack(classStack), JvmClassName.byInternalName(name), true); classStack.push(classDescriptor); nameStack.push(name); super.visitNamedFunction(function); nameStack.pop(); classStack.pop(); } }
@Override public void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression) { FunctionDescriptor functionDescriptor = (FunctionDescriptor) bindingContext.get(DECLARATION_TO_DESCRIPTOR, expression); // working around a problem with shallow analysis if (functionDescriptor == null) return; String name = inventAnonymousClassName(expression); ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor); recordClosure( bindingTrace, expression, classDescriptor, peekFromStack(classStack), JvmClassName.byInternalName(name), true); classStack.push(classDescriptor); nameStack.push(name); super.visitFunctionLiteralExpression(expression); nameStack.pop(); classStack.pop(); }
@NotNull private static JvmClassName classNameFromAsmDesc(@NotNull String desc) { assert desc.startsWith("L") && desc.endsWith(";") : "Not a JVM descriptor: " + desc; return JvmClassName.byInternalName(desc.substring(1, desc.length() - 1)); }
@NotNull public LineResult eval(@NotNull String line) { ++lineNumber; FqName scriptFqName = new FqName("Line" + lineNumber); Type scriptClassType = asmTypeByFqNameWithoutInnerClasses(scriptFqName); StringBuilder fullText = new StringBuilder(); for (String prevLine : previousIncompleteLines) { fullText.append(prevLine + "\n"); } fullText.append(line); LightVirtualFile virtualFile = new LightVirtualFile( "line" + lineNumber + JetParserDefinition.STD_SCRIPT_EXT, JetLanguage.INSTANCE, fullText.toString()); virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET); JetFile psiFile = (JetFile) ((PsiFileFactoryImpl) PsiFileFactory.getInstance(jetCoreEnvironment.getProject())) .trySetupPsiForFile(virtualFile, JetLanguage.INSTANCE, true, false); MessageCollectorToString errorCollector = new MessageCollectorToString(); AnalyzerWithCompilerReport.SyntaxErrorReport syntaxErrorReport = AnalyzerWithCompilerReport.reportSyntaxErrors(psiFile, errorCollector); if (syntaxErrorReport.isOnlyErrorAtEof()) { previousIncompleteLines.add(line); return LineResult.incomplete(); } previousIncompleteLines.clear(); if (syntaxErrorReport.isHasErrors()) { return LineResult.error(errorCollector.getString()); } prepareForTheNextReplLine(topDownAnalysisContext); trace.clearDiagnostics(); psiFile.getScript().putUserData(ScriptHeaderResolver.PRIORITY_KEY, lineNumber); ScriptDescriptor scriptDescriptor = doAnalyze(psiFile, errorCollector); if (scriptDescriptor == null) { return LineResult.error(errorCollector.getString()); } List<Pair<ScriptDescriptor, Type>> earlierScripts = Lists.newArrayList(); for (EarlierLine earlierLine : earlierLines) { earlierScripts.add( Pair.create(earlierLine.getScriptDescriptor(), earlierLine.getClassType())); } BindingContext bindingContext = AnalyzeExhaust.success(trace.getBindingContext(), module).getBindingContext(); GenerationState generationState = new GenerationState( psiFile.getProject(), ClassBuilderFactories.BINARIES, bindingContext, Collections.singletonList(psiFile), CompilerArgumentsUtil.DEFAULT_INLINE_FLAG); compileScript( psiFile.getScript(), scriptClassType, earlierScripts, generationState, CompilationErrorHandler.THROW_EXCEPTION); for (OutputFile outputFile : generationState.getFactory().asList()) { classLoader.addClass( JvmClassName.byInternalName(outputFile.getRelativePath().replaceFirst("\\.class$", "")), outputFile.asByteArray()); } try { Class<?> scriptClass = classLoader.loadClass(scriptFqName.asString()); Class<?>[] constructorParams = new Class<?>[earlierLines.size()]; Object[] constructorArgs = new Object[earlierLines.size()]; for (int i = 0; i < earlierLines.size(); ++i) { constructorParams[i] = earlierLines.get(i).getScriptClass(); constructorArgs[i] = earlierLines.get(i).getScriptInstance(); } Constructor<?> scriptInstanceConstructor = scriptClass.getConstructor(constructorParams); Object scriptInstance; try { scriptInstance = scriptInstanceConstructor.newInstance(constructorArgs); } catch (Throwable e) { return LineResult.error(Throwables.getStackTraceAsString(e)); } Field rvField = scriptClass.getDeclaredField("rv"); rvField.setAccessible(true); Object rv = rvField.get(scriptInstance); earlierLines.add( new EarlierLine(line, scriptDescriptor, scriptClass, scriptInstance, scriptClassType)); return LineResult.successful( rv, KotlinBuiltIns.getInstance() .getUnitType() .equals(scriptDescriptor.getScriptCodeDescriptor().getReturnType())); } catch (Throwable e) { PrintWriter writer = new PrintWriter(System.err); classLoader.dumpClasses(writer); writer.flush(); throw UtilsPackage.rethrow(e); } }
@NotNull public static JvmClassName bySignatureName(@NotNull String signatureName) { JvmClassName className = new JvmClassName(signatureNameToInternalName(signatureName)); className.signatureName = signatureName; return className; }
/** WARNING: fq name cannot be uniquely mapped to JVM class name. */ @NotNull public static JvmClassName byFqNameWithoutInnerClasses(@NotNull FqName fqName) { JvmClassName r = new JvmClassName(fqNameToInternalName(fqName)); r.fqName = fqName; return r; }