Merge branch 'master' into ElliotM-for-loop-indices
This commit is contained in:
Generated
+2
@@ -2,12 +2,14 @@
|
||||
<dictionary name="abreslav">
|
||||
<words>
|
||||
<w>accessor</w>
|
||||
<w>covariantly</w>
|
||||
<w>deserialized</w>
|
||||
<w>dominator</w>
|
||||
<w>inferrer</w>
|
||||
<w>iterable</w>
|
||||
<w>nondeterministic</w>
|
||||
<w>nullable</w>
|
||||
<w>overridable</w>
|
||||
<w>pseudocode</w>
|
||||
<w>substitutor</w>
|
||||
<w>subtyping</w>
|
||||
|
||||
Generated
+1
@@ -2,6 +2,7 @@
|
||||
<dictionary name="geevee">
|
||||
<words>
|
||||
<w>builtins</w>
|
||||
<w>callables</w>
|
||||
<w>klass</w>
|
||||
<w>proto</w>
|
||||
<w>protoc</w>
|
||||
|
||||
Generated
-2
@@ -7,8 +7,6 @@
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="file://$PROJECT_DIR$/libraries/stdlib/src" />
|
||||
<root url="file://$PROJECT_DIR$/core/builtins/src" />
|
||||
<root url="file://$PROJECT_DIR$/core/runtime.jvm/src" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
Generated
+1
-1
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="IDEA" type="Application" factoryName="Application">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<option name="MAIN_CLASS_NAME" value="com.intellij.idea.Main" />
|
||||
<option name="VM_PARAMETERS" value="-Xmx800m -XX:ReservedCodeCacheSize=64m -XX:MaxPermSize=450m -XX:+HeapDumpOnOutOfMemoryError -ea -Didea.is.internal=true -Didea.debug.mode=true -Didea.system.path=../system-idea -Didea.config.path=../config-idea -Dapple.laf.useScreenMenuBar=true -Dapple.awt.graphics.UseQuartz=true -Dsun.io.useCanonCaches=false -Dplugin.path=$PROJECT_DIR$/out/artifacts/Kotlin,$PROJECT_DIR$/out/artifacts/KotlinAndroidExtensions -Dkotlin.internal.mode.enabled=true" />
|
||||
<option name="VM_PARAMETERS" value="-Xmx800m -XX:ReservedCodeCacheSize=64m -XX:MaxPermSize=450m -XX:+HeapDumpOnOutOfMemoryError -ea -Didea.is.internal=true -Didea.debug.mode=true -Didea.system.path=../system-idea -Didea.config.path=../config-idea -Dapple.laf.useScreenMenuBar=true -Dapple.awt.graphics.UseQuartz=true -Dsun.io.useCanonCaches=false -Dplugin.path=$PROJECT_DIR$/out/artifacts/Kotlin,$PROJECT_DIR$/out/artifacts/KotlinAndroidExtensions -Dkotlin.internal.mode.enabled=true -Didea.additional.classpath=../idea-kotlin-runtime/kotlin-runtime.jar" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/ideaSDK/bin" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="IDEA (No ProcessCanceledException)" type="Application" factoryName="Application">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<option name="MAIN_CLASS_NAME" value="com.intellij.idea.Main" />
|
||||
<option name="VM_PARAMETERS" value="-Xmx800m -XX:ReservedCodeCacheSize=64m -XX:MaxPermSize=250m -XX:+HeapDumpOnOutOfMemoryError -ea -Didea.is.internal=true -Didea.debug.mode=true -Didea.system.path=../system-idea -Didea.config.path=../config-idea -Dapple.laf.useScreenMenuBar=true -Dapple.awt.graphics.UseQuartz=true -Dsun.io.useCanonCaches=false -Dplugin.path=$PROJECT_DIR$/out/artifacts/Kotlin,$PROJECT_DIR$/out/artifacts/KotlinAndroidExtensions -Didea.ProcessCanceledException=disabled -Dkotlin.internal.mode.enabled=true" />
|
||||
<option name="VM_PARAMETERS" value="-Xmx800m -XX:ReservedCodeCacheSize=64m -XX:MaxPermSize=250m -XX:+HeapDumpOnOutOfMemoryError -ea -Didea.is.internal=true -Didea.debug.mode=true -Didea.system.path=../system-idea -Didea.config.path=../config-idea -Dapple.laf.useScreenMenuBar=true -Dapple.awt.graphics.UseQuartz=true -Dsun.io.useCanonCaches=false -Dplugin.path=$PROJECT_DIR$/out/artifacts/Kotlin,$PROJECT_DIR$/out/artifacts/KotlinAndroidExtensions -Didea.ProcessCanceledException=disabled -Dkotlin.internal.mode.enabled=true -Didea.additional.classpath=../idea-kotlin-runtime/kotlin-runtime.jar" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/ideaSDK/bin" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
|
||||
@@ -937,6 +937,7 @@
|
||||
<zip destfile="${output}/kotlin-test-data.zip">
|
||||
<zipfileset dir="compiler/testData" prefix="compiler"/>
|
||||
<zipfileset dir="idea/testData" prefix="ide"/>
|
||||
<zipfileset dir="idea/idea-completion/testData" prefix="ide/completion"/>
|
||||
</zip>
|
||||
</target>
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.jetbrains.kotlin.backend.common;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -29,7 +28,7 @@ import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.calls.CallResolverUtil;
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.CallResolverUtilPackage;
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
@@ -62,7 +61,7 @@ public class CodegenUtil {
|
||||
) {
|
||||
Collection<FunctionDescriptor> functions = owner.getDefaultType().getMemberScope().getFunctions(name);
|
||||
for (FunctionDescriptor function : functions) {
|
||||
if (!CallResolverUtil.isOrOverridesSynthesized(function)
|
||||
if (!CallResolverUtilPackage.isOrOverridesSynthesized(function)
|
||||
&& function.getTypeParameters().isEmpty()
|
||||
&& valueParameterClassesMatch(function.getValueParameters(), Arrays.asList(valueParameterClassifiers))
|
||||
&& rawTypeMatches(function.getReturnType(), returnedClassifier)) {
|
||||
|
||||
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.OverrideResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.CallResolverUtil
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isOrOverridesSynthesized
|
||||
|
||||
public fun <Signature> generateBridgesForFunctionDescriptor(
|
||||
descriptor: FunctionDescriptor,
|
||||
@@ -69,7 +69,7 @@ private data class DescriptorBasedFunctionHandle(val descriptor: FunctionDescrip
|
||||
*/
|
||||
public fun findTraitImplementation(descriptor: CallableMemberDescriptor): CallableMemberDescriptor? {
|
||||
if (descriptor.getKind().isReal()) return null
|
||||
if (CallResolverUtil.isOrOverridesSynthesized(descriptor)) return null
|
||||
if (isOrOverridesSynthesized(descriptor)) return null
|
||||
|
||||
val implementation = findImplementationFromInterface(descriptor) ?: return null
|
||||
val immediateConcreteSuper = firstSuperMethodFromKotlin(descriptor, implementation) ?: return null
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import java.util.*
|
||||
|
||||
public class AccessorForConstructorDescriptor(
|
||||
@@ -38,6 +39,8 @@ public class AccessorForConstructorDescriptor(
|
||||
|
||||
override fun isPrimary(): Boolean = false
|
||||
|
||||
override fun getReturnType(): JetType = super<AbstractAccessorForFunctionDescriptor>.getReturnType()!!
|
||||
|
||||
init {
|
||||
initialize(
|
||||
DescriptorUtils.getReceiverParameterType(getExtensionReceiverParameter()),
|
||||
|
||||
@@ -24,8 +24,10 @@ import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationTarget;
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.resolve.AnnotationTargetChecker;
|
||||
import org.jetbrains.kotlin.resolve.constants.*;
|
||||
import org.jetbrains.kotlin.resolve.constants.StringValue;
|
||||
import org.jetbrains.kotlin.types.Flexibility;
|
||||
@@ -34,8 +36,10 @@ import org.jetbrains.kotlin.types.TypeUtils;
|
||||
import org.jetbrains.kotlin.types.TypesPackage;
|
||||
import org.jetbrains.org.objectweb.asm.*;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getClassObjectType;
|
||||
@@ -119,6 +123,13 @@ public abstract class AnnotationCodegen {
|
||||
generateNullabilityAnnotation(descriptor.getReturnType(), annotationDescriptorsAlreadyPresent);
|
||||
}
|
||||
}
|
||||
if (annotated instanceof ClassDescriptor) {
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) annotated;
|
||||
if (classDescriptor.getKind() == ClassKind.ANNOTATION_CLASS) {
|
||||
generateRetentionAnnotation(classDescriptor, annotationDescriptorsAlreadyPresent);
|
||||
generateTargetAnnotation(classDescriptor, annotationDescriptorsAlreadyPresent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isInvisibleFromTheOutside(@Nullable DeclarationDescriptor descriptor) {
|
||||
@@ -160,6 +171,56 @@ public abstract class AnnotationCodegen {
|
||||
generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, annotationClass);
|
||||
}
|
||||
|
||||
private static final Map<AnnotationTarget, ElementType> annotationTargetMap =
|
||||
new EnumMap<AnnotationTarget, ElementType>(AnnotationTarget.class);
|
||||
|
||||
static {
|
||||
annotationTargetMap.put(AnnotationTarget.PACKAGE, ElementType.PACKAGE);
|
||||
annotationTargetMap.put(AnnotationTarget.CLASSIFIER, ElementType.TYPE);
|
||||
annotationTargetMap.put(AnnotationTarget.ANNOTATION_CLASS, ElementType.ANNOTATION_TYPE);
|
||||
annotationTargetMap.put(AnnotationTarget.CONSTRUCTOR, ElementType.CONSTRUCTOR);
|
||||
annotationTargetMap.put(AnnotationTarget.LOCAL_VARIABLE, ElementType.LOCAL_VARIABLE);
|
||||
annotationTargetMap.put(AnnotationTarget.FUNCTION, ElementType.METHOD);
|
||||
annotationTargetMap.put(AnnotationTarget.PROPERTY_GETTER, ElementType.METHOD);
|
||||
annotationTargetMap.put(AnnotationTarget.PROPERTY_SETTER, ElementType.METHOD);
|
||||
annotationTargetMap.put(AnnotationTarget.FIELD, ElementType.FIELD);
|
||||
annotationTargetMap.put(AnnotationTarget.VALUE_PARAMETER, ElementType.PARAMETER);
|
||||
}
|
||||
|
||||
private void generateTargetAnnotation(@NotNull ClassDescriptor classDescriptor, @NotNull Set<String> annotationDescriptorsAlreadyPresent) {
|
||||
String descriptor = Type.getType(Target.class).getDescriptor();
|
||||
if (!annotationDescriptorsAlreadyPresent.add(descriptor)) return;
|
||||
Set<AnnotationTarget> targets = AnnotationTargetChecker.INSTANCE$.possibleTargetSet(classDescriptor);
|
||||
Set<ElementType> javaTargets;
|
||||
if (targets == null) {
|
||||
javaTargets = getJavaTargetList(classDescriptor);
|
||||
if (javaTargets == null) return;
|
||||
}
|
||||
else {
|
||||
javaTargets = EnumSet.noneOf(ElementType.class);
|
||||
for (AnnotationTarget target : targets) {
|
||||
if (annotationTargetMap.get(target) == null) continue;
|
||||
javaTargets.add(annotationTargetMap.get(target));
|
||||
}
|
||||
}
|
||||
AnnotationVisitor visitor = visitAnnotation(descriptor, true);
|
||||
AnnotationVisitor arrayVisitor = visitor.visitArray("value");
|
||||
for (ElementType javaTarget : javaTargets) {
|
||||
arrayVisitor.visitEnum(null, Type.getType(ElementType.class).getDescriptor(), javaTarget.name());
|
||||
}
|
||||
arrayVisitor.visitEnd();
|
||||
visitor.visitEnd();
|
||||
}
|
||||
|
||||
private void generateRetentionAnnotation(@NotNull ClassDescriptor classDescriptor, @NotNull Set<String> annotationDescriptorsAlreadyPresent) {
|
||||
RetentionPolicy policy = getRetentionPolicy(classDescriptor);
|
||||
String descriptor = Type.getType(Retention.class).getDescriptor();
|
||||
if (!annotationDescriptorsAlreadyPresent.add(descriptor)) return;
|
||||
AnnotationVisitor visitor = visitAnnotation(descriptor, true);
|
||||
visitor.visitEnum("value", Type.getType(RetentionPolicy.class).getDescriptor(), policy.name());
|
||||
visitor.visitEnd();
|
||||
}
|
||||
|
||||
private void generateAnnotationIfNotPresent(Set<String> annotationDescriptorsAlreadyPresent, Class<?> annotationClass) {
|
||||
String descriptor = Type.getType(annotationClass).getDescriptor();
|
||||
if (!annotationDescriptorsAlreadyPresent.contains(descriptor)) {
|
||||
@@ -172,9 +233,9 @@ public abstract class AnnotationCodegen {
|
||||
return !type.isMarkedNullable() && classifier instanceof TypeParameterDescriptor && TypeUtils.hasNullableSuperType(type);
|
||||
}
|
||||
|
||||
public void generateAnnotationDefaultValue(@NotNull CompileTimeConstant value, @NotNull JetType expectedType) {
|
||||
public void generateAnnotationDefaultValue(@NotNull ConstantValue<?> value, @NotNull JetType expectedType) {
|
||||
AnnotationVisitor visitor = visitAnnotation(null, false); // Parameters are unimportant
|
||||
genCompileTimeValue(null, value, expectedType, visitor);
|
||||
genCompileTimeValue(null, value, visitor);
|
||||
visitor.visitEnd();
|
||||
}
|
||||
|
||||
@@ -197,17 +258,16 @@ public abstract class AnnotationCodegen {
|
||||
}
|
||||
|
||||
private void genAnnotationArguments(AnnotationDescriptor annotationDescriptor, AnnotationVisitor annotationVisitor) {
|
||||
for (Map.Entry<ValueParameterDescriptor, CompileTimeConstant<?>> entry : annotationDescriptor.getAllValueArguments().entrySet()) {
|
||||
for (Map.Entry<ValueParameterDescriptor, ConstantValue<?>> entry : annotationDescriptor.getAllValueArguments().entrySet()) {
|
||||
ValueParameterDescriptor descriptor = entry.getKey();
|
||||
String name = descriptor.getName().asString();
|
||||
genCompileTimeValue(name, entry.getValue(), descriptor.getType(), annotationVisitor);
|
||||
genCompileTimeValue(name, entry.getValue(), annotationVisitor);
|
||||
}
|
||||
}
|
||||
|
||||
private void genCompileTimeValue(
|
||||
@Nullable final String name,
|
||||
@NotNull CompileTimeConstant<?> value,
|
||||
@NotNull final JetType expectedType,
|
||||
@NotNull ConstantValue<?> value,
|
||||
@NotNull final AnnotationVisitor annotationVisitor
|
||||
) {
|
||||
AnnotationArgumentVisitor argumentVisitor = new AnnotationArgumentVisitor<Void, Void>() {
|
||||
@@ -259,15 +319,15 @@ public abstract class AnnotationCodegen {
|
||||
@Override
|
||||
public Void visitEnumValue(EnumValue value, Void data) {
|
||||
String propertyName = value.getValue().getName().asString();
|
||||
annotationVisitor.visitEnum(name, typeMapper.mapType(value.getType(KotlinBuiltIns.getInstance())).getDescriptor(), propertyName);
|
||||
annotationVisitor.visitEnum(name, typeMapper.mapType(value.getType()).getDescriptor(), propertyName);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitArrayValue(ArrayValue value, Void data) {
|
||||
AnnotationVisitor visitor = annotationVisitor.visitArray(name);
|
||||
for (CompileTimeConstant<?> argument : value.getValue()) {
|
||||
genCompileTimeValue(null, argument, value.getType(KotlinBuiltIns.getInstance()), visitor);
|
||||
for (ConstantValue<?> argument : value.getValue()) {
|
||||
genCompileTimeValue(null, argument, visitor);
|
||||
}
|
||||
visitor.visitEnd();
|
||||
return null;
|
||||
@@ -288,14 +348,7 @@ public abstract class AnnotationCodegen {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitNumberTypeValue(IntegerValueTypeConstant value, Void data) {
|
||||
Object numberType = value.getValue(expectedType);
|
||||
annotationVisitor.visit(name, numberType);
|
||||
return null;
|
||||
}
|
||||
|
||||
private Void visitSimpleValue(CompileTimeConstant value) {
|
||||
private Void visitSimpleValue(ConstantValue<?> value) {
|
||||
annotationVisitor.visit(name, value.getValue());
|
||||
return null;
|
||||
}
|
||||
@@ -310,7 +363,7 @@ public abstract class AnnotationCodegen {
|
||||
return visitUnsupportedValue(value);
|
||||
}
|
||||
|
||||
private Void visitUnsupportedValue(CompileTimeConstant value) {
|
||||
private Void visitUnsupportedValue(ConstantValue<?> value) {
|
||||
throw new IllegalStateException("Don't know how to compile annotation value " + value);
|
||||
}
|
||||
};
|
||||
@@ -318,13 +371,70 @@ public abstract class AnnotationCodegen {
|
||||
value.accept(argumentVisitor, null);
|
||||
}
|
||||
|
||||
private enum KotlinRetention {
|
||||
SOURCE(RetentionPolicy.SOURCE),
|
||||
BINARY(RetentionPolicy.CLASS),
|
||||
RUNTIME(RetentionPolicy.RUNTIME);
|
||||
|
||||
final RetentionPolicy mapped;
|
||||
|
||||
KotlinRetention(RetentionPolicy mapped) {
|
||||
this.mapped = mapped;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Set<ElementType> getJavaTargetList(ClassDescriptor descriptor) {
|
||||
AnnotationDescriptor targetAnnotation = descriptor.getAnnotations().findAnnotation(new FqName(Target.class.getName()));
|
||||
if (targetAnnotation != null) {
|
||||
Collection<ConstantValue<?>> valueArguments = targetAnnotation.getAllValueArguments().values();
|
||||
if (!valueArguments.isEmpty()) {
|
||||
ConstantValue<?> compileTimeConstant = valueArguments.iterator().next();
|
||||
if (compileTimeConstant instanceof ArrayValue) {
|
||||
List<? extends ConstantValue<?>> values = ((ArrayValue) compileTimeConstant).getValue();
|
||||
Set<ElementType> result = EnumSet.noneOf(ElementType.class);
|
||||
for (ConstantValue<?> value : values) {
|
||||
if (value instanceof EnumValue) {
|
||||
ClassDescriptor enumEntry = ((EnumValue) value).getValue();
|
||||
JetType classObjectType = getClassObjectType(enumEntry);
|
||||
if (classObjectType != null) {
|
||||
if ("java/lang/annotation/ElementType".equals(typeMapper.mapType(classObjectType).getInternalName())) {
|
||||
result.add(ElementType.valueOf(enumEntry.getName().asString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private RetentionPolicy getRetentionPolicy(@NotNull Annotated descriptor) {
|
||||
AnnotationDescriptor kotlinAnnotation = descriptor.getAnnotations().findAnnotation(KotlinBuiltIns.FQ_NAMES.annotation);
|
||||
if (kotlinAnnotation != null) {
|
||||
for (Map.Entry<ValueParameterDescriptor, ConstantValue<?>> argument : kotlinAnnotation.getAllValueArguments().entrySet()) {
|
||||
if ("retention".equals(argument.getKey().getName().asString()) && argument.getValue() instanceof EnumValue) {
|
||||
ClassDescriptor enumEntry = ((EnumValue) argument.getValue()).getValue();
|
||||
JetType classObjectType = getClassObjectType(enumEntry);
|
||||
if (classObjectType != null) {
|
||||
if ("kotlin/annotation/AnnotationRetention".equals(typeMapper.mapType(classObjectType).getInternalName())) {
|
||||
String entryName = enumEntry.getName().asString();
|
||||
for (KotlinRetention retention : KotlinRetention.values()) {
|
||||
if (retention.name().equals(entryName)) return retention.mapped;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AnnotationDescriptor retentionAnnotation = descriptor.getAnnotations().findAnnotation(new FqName(Retention.class.getName()));
|
||||
if (retentionAnnotation != null) {
|
||||
Collection<CompileTimeConstant<?>> valueArguments = retentionAnnotation.getAllValueArguments().values();
|
||||
Collection<ConstantValue<?>> valueArguments = retentionAnnotation.getAllValueArguments().values();
|
||||
if (!valueArguments.isEmpty()) {
|
||||
CompileTimeConstant<?> compileTimeConstant = valueArguments.iterator().next();
|
||||
ConstantValue<?> compileTimeConstant = valueArguments.iterator().next();
|
||||
if (compileTimeConstant instanceof EnumValue) {
|
||||
ClassDescriptor enumEntry = ((EnumValue) compileTimeConstant).getValue();
|
||||
JetType classObjectType = getClassObjectType(enumEntry);
|
||||
@@ -337,7 +447,7 @@ public abstract class AnnotationCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
return RetentionPolicy.CLASS;
|
||||
return RetentionPolicy.RUNTIME;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.load.java.JavaVisibilities;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor;
|
||||
import org.jetbrains.kotlin.jvm.RuntimeAssertionInfo;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage;
|
||||
@@ -45,7 +46,6 @@ import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPackage;
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType;
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
||||
import org.jetbrains.kotlin.types.Approximation;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
import org.jetbrains.kotlin.types.TypesPackage;
|
||||
import org.jetbrains.org.objectweb.asm.*;
|
||||
@@ -637,10 +637,10 @@ public class AsmUtil {
|
||||
public static StackValue genNotNullAssertions(
|
||||
@NotNull GenerationState state,
|
||||
@NotNull final StackValue stackValue,
|
||||
@Nullable final Approximation.Info approximationInfo
|
||||
@Nullable final RuntimeAssertionInfo runtimeAssertionInfo
|
||||
) {
|
||||
if (!state.isCallAssertionsEnabled()) return stackValue;
|
||||
if (approximationInfo == null || !TypesPackage.assertNotNull(approximationInfo)) return stackValue;
|
||||
if (runtimeAssertionInfo == null || !runtimeAssertionInfo.getNeedNotNullAssertion()) return stackValue;
|
||||
|
||||
return new StackValue(stackValue.type) {
|
||||
|
||||
@@ -649,7 +649,7 @@ public class AsmUtil {
|
||||
stackValue.put(type, v);
|
||||
if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
|
||||
v.dup();
|
||||
v.visitLdcInsn(approximationInfo.getMessage());
|
||||
v.visitLdcInsn(runtimeAssertionInfo.getMessage());
|
||||
v.invokestatic("kotlin/jvm/internal/Intrinsics", "checkExpressionValueIsNotNull",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;)V", false);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsnOpcode
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.fakeAlwaysFalseIfeq
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.fakeAlwaysTrueIfeq
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
@@ -50,7 +49,7 @@ open class BranchedValue(
|
||||
open fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
|
||||
if (arg1 is CondJump) arg1.condJump(jumpLabel, v, jumpIfFalse) else arg1.put(operandType, v)
|
||||
arg2?.put(operandType, v)
|
||||
v.visitJumpInsn(patchOpcode(if (jumpIfFalse) opcode else negatedOperations[opcode], v), jumpLabel);
|
||||
v.visitJumpInsn(patchOpcode(if (jumpIfFalse) opcode else negatedOperations[opcode]!!, v), jumpLabel);
|
||||
}
|
||||
|
||||
open fun loopJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
|
||||
|
||||
@@ -21,10 +21,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.backend.common.bridges.BridgesPackage;
|
||||
import org.jetbrains.kotlin.codegen.context.ClassContext;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
@@ -80,7 +77,7 @@ public abstract class ClassBodyCodegen extends MemberCodegen<JetClassOrObject> {
|
||||
}
|
||||
}
|
||||
|
||||
generatePrimaryConstructorProperties(propertyCodegen, myClass);
|
||||
generatePrimaryConstructorProperties();
|
||||
}
|
||||
|
||||
private static boolean shouldProcessFirst(JetDeclaration declaration) {
|
||||
@@ -101,8 +98,8 @@ public abstract class ClassBodyCodegen extends MemberCodegen<JetClassOrObject> {
|
||||
}
|
||||
}
|
||||
|
||||
private void generatePrimaryConstructorProperties(PropertyCodegen propertyCodegen, JetClassOrObject origin) {
|
||||
boolean isAnnotation = origin instanceof JetClass && ((JetClass) origin).isAnnotation();
|
||||
private void generatePrimaryConstructorProperties() {
|
||||
boolean isAnnotation = descriptor.getKind() == ClassKind.ANNOTATION_CLASS;
|
||||
for (JetParameter p : getPrimaryConstructorParameters()) {
|
||||
if (p.hasValOrVar()) {
|
||||
PropertyDescriptor propertyDescriptor = bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, p);
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import kotlin.KotlinPackage;
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -31,11 +32,13 @@ import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils;
|
||||
import org.jetbrains.kotlin.psi.JetElement;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions;
|
||||
import org.jetbrains.kotlin.utils.UtilsPackage;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
@@ -46,6 +49,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.ExpressionCodegen.generateClassLiteralReference;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConst;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.CLOSURE;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClass;
|
||||
@@ -53,6 +57,7 @@ import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticC
|
||||
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getBuiltIns;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.OtherOrigin;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class ClosureCodegen extends MemberCodegen<JetElement> {
|
||||
@@ -61,6 +66,7 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
|
||||
private final SamType samType;
|
||||
private final JetType superClassType;
|
||||
private final List<JetType> superInterfaceTypes;
|
||||
private final FunctionDescriptor functionReferenceTarget;
|
||||
private final FunctionGenerationStrategy strategy;
|
||||
private final CalculatedClosure closure;
|
||||
private final Type asmType;
|
||||
@@ -76,6 +82,7 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
|
||||
@Nullable SamType samType,
|
||||
@NotNull ClosureContext context,
|
||||
@NotNull KotlinSyntheticClass.Kind syntheticClassKind,
|
||||
@Nullable FunctionDescriptor functionReferenceTarget,
|
||||
@NotNull FunctionGenerationStrategy strategy,
|
||||
@NotNull MemberCodegen<?> parentCodegen,
|
||||
@NotNull ClassBuilder classBuilder
|
||||
@@ -86,6 +93,7 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
|
||||
this.classDescriptor = context.getContextDescriptor();
|
||||
this.samType = samType;
|
||||
this.syntheticClassKind = syntheticClassKind;
|
||||
this.functionReferenceTarget = functionReferenceTarget;
|
||||
this.strategy = strategy;
|
||||
|
||||
if (samType == null) {
|
||||
@@ -189,10 +197,14 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
|
||||
functionCodegen.generateBridges(descriptorForBridges);
|
||||
}
|
||||
|
||||
this.constructor = generateConstructor(superClassAsmType);
|
||||
if (functionReferenceTarget != null) {
|
||||
generateFunctionReferenceMethods(functionReferenceTarget);
|
||||
}
|
||||
|
||||
this.constructor = generateConstructor();
|
||||
|
||||
if (isConst(closure)) {
|
||||
generateConstInstance();
|
||||
generateConstInstance(asmType, asmType, UtilsPackage.<InstructionAdapter>doNothing());
|
||||
}
|
||||
|
||||
genClosureFields(closure, v, typeMapper);
|
||||
@@ -214,77 +226,39 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public StackValue putInstanceOnStack(
|
||||
@NotNull final ExpressionCodegen codegen,
|
||||
@Nullable final FunctionDescriptor functionReferenceTarget
|
||||
) {
|
||||
return StackValue.operation(asmType, new Function1<InstructionAdapter, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(InstructionAdapter v) {
|
||||
if (isConst(closure)) {
|
||||
v.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor());
|
||||
public StackValue putInstanceOnStack(@NotNull final ExpressionCodegen codegen) {
|
||||
return StackValue.operation(
|
||||
functionReferenceTarget != null ? K_FUNCTION : asmType,
|
||||
new Function1<InstructionAdapter, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(InstructionAdapter v) {
|
||||
if (isConst(closure)) {
|
||||
v.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor());
|
||||
}
|
||||
else {
|
||||
v.anew(asmType);
|
||||
v.dup();
|
||||
|
||||
codegen.pushClosureOnStack(classDescriptor, true, codegen.defaultCallGenerator);
|
||||
v.invokespecial(asmType.getInternalName(), "<init>", constructor.getDescriptor(), false);
|
||||
}
|
||||
|
||||
if (functionReferenceTarget != null) {
|
||||
v.invokestatic(REFLECTION, "function", Type.getMethodDescriptor(K_FUNCTION, FUNCTION_REFERENCE), false);
|
||||
}
|
||||
|
||||
return Unit.INSTANCE$;
|
||||
}
|
||||
}
|
||||
else {
|
||||
v.anew(asmType);
|
||||
v.dup();
|
||||
|
||||
codegen.pushClosureOnStack(classDescriptor, true, codegen.defaultCallGenerator);
|
||||
v.invokespecial(asmType.getInternalName(), "<init>", constructor.getDescriptor(), false);
|
||||
}
|
||||
|
||||
if (functionReferenceTarget != null) {
|
||||
equipFunctionReferenceWithReflection(v, functionReferenceTarget);
|
||||
}
|
||||
|
||||
return Unit.INSTANCE$;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void equipFunctionReferenceWithReflection(@NotNull InstructionAdapter v, @NotNull FunctionDescriptor target) {
|
||||
DeclarationDescriptor container = target.getContainingDeclaration();
|
||||
|
||||
Type type;
|
||||
if (container instanceof PackageFragmentDescriptor) {
|
||||
type = target.getExtensionReceiverParameter() != null
|
||||
? K_TOP_LEVEL_EXTENSION_FUNCTION
|
||||
: K_TOP_LEVEL_FUNCTION;
|
||||
}
|
||||
else if (container instanceof ClassDescriptor) {
|
||||
type = K_MEMBER_FUNCTION;
|
||||
}
|
||||
else {
|
||||
type = K_LOCAL_FUNCTION;
|
||||
}
|
||||
|
||||
Method method = method("function", K_FUNCTION, FUNCTION_REFERENCE);
|
||||
v.invokestatic(REFLECTION, method.getName(), method.getDescriptor(), false);
|
||||
StackValue.coerce(K_FUNCTION, type, v);
|
||||
}
|
||||
|
||||
|
||||
private void generateConstInstance() {
|
||||
MethodVisitor mv = v.newMethod(OtherOrigin(element, funDescriptor), ACC_STATIC | ACC_SYNTHETIC, "<clinit>", "()V", null, ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
|
||||
v.newField(OtherOrigin(element, funDescriptor), ACC_STATIC | ACC_FINAL | ACC_PUBLIC, JvmAbi.INSTANCE_FIELD, asmType.getDescriptor(), null, null);
|
||||
|
||||
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
||||
mv.visitCode();
|
||||
iv.anew(asmType);
|
||||
iv.dup();
|
||||
iv.invokespecial(asmType.getInternalName(), "<init>", "()V", false);
|
||||
iv.putstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor());
|
||||
mv.visitInsn(RETURN);
|
||||
FunctionCodegen.endVisit(mv, "<clinit>", element);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void generateBridge(@NotNull Method bridge, @NotNull Method delegate) {
|
||||
if (bridge.equals(delegate)) return;
|
||||
|
||||
MethodVisitor mv =
|
||||
v.newMethod(OtherOrigin(element, funDescriptor), ACC_PUBLIC | ACC_BRIDGE, bridge.getName(), bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
v.newMethod(OtherOrigin(element, funDescriptor), ACC_PUBLIC | ACC_BRIDGE,
|
||||
bridge.getName(), bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
|
||||
if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
|
||||
|
||||
@@ -295,17 +269,18 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
|
||||
|
||||
iv.load(0, asmType);
|
||||
|
||||
ReceiverParameterDescriptor receiver = funDescriptor.getExtensionReceiverParameter();
|
||||
int count = 1;
|
||||
if (receiver != null) {
|
||||
StackValue.local(count, bridge.getArgumentTypes()[count - 1]).put(typeMapper.mapType(receiver.getType()), iv);
|
||||
count++;
|
||||
}
|
||||
Type[] myParameterTypes = bridge.getArgumentTypes();
|
||||
|
||||
List<ValueParameterDescriptor> params = funDescriptor.getValueParameters();
|
||||
for (ValueParameterDescriptor param : params) {
|
||||
StackValue.local(count, bridge.getArgumentTypes()[count - 1]).put(typeMapper.mapType(param.getType()), iv);
|
||||
count++;
|
||||
List<ParameterDescriptor> calleeParameters = KotlinPackage.plus(
|
||||
UtilsPackage.<ParameterDescriptor>singletonOrEmptyList(funDescriptor.getExtensionReceiverParameter()),
|
||||
funDescriptor.getValueParameters()
|
||||
);
|
||||
|
||||
int slot = 1;
|
||||
for (int i = 0; i < calleeParameters.size(); i++) {
|
||||
Type type = myParameterTypes[i];
|
||||
StackValue.local(slot, type).put(typeMapper.mapType(calleeParameters.get(i)), iv);
|
||||
slot += type.getSize();
|
||||
}
|
||||
|
||||
iv.invokevirtual(asmType.getInternalName(), delegate.getName(), delegate.getDescriptor(), false);
|
||||
@@ -316,8 +291,79 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
|
||||
FunctionCodegen.endVisit(mv, "bridge", element);
|
||||
}
|
||||
|
||||
// TODO: ImplementationBodyCodegen.markLineNumberForSyntheticFunction?
|
||||
private void generateFunctionReferenceMethods(@NotNull FunctionDescriptor descriptor) {
|
||||
int flags = ACC_PUBLIC | ACC_FINAL;
|
||||
boolean generateBody = state.getClassBuilderMode() == ClassBuilderMode.FULL;
|
||||
|
||||
{
|
||||
MethodVisitor mv =
|
||||
v.newMethod(NO_ORIGIN, flags, "getOwner", Type.getMethodDescriptor(K_DECLARATION_CONTAINER_TYPE), null, null);
|
||||
if (generateBody) {
|
||||
mv.visitCode();
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
generateCallableReferenceDeclarationContainer(iv, descriptor, typeMapper);
|
||||
iv.areturn(K_DECLARATION_CONTAINER_TYPE);
|
||||
FunctionCodegen.endVisit(iv, "function reference getOwner", element);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
MethodVisitor mv =
|
||||
v.newMethod(NO_ORIGIN, flags, "getName", Type.getMethodDescriptor(JAVA_STRING_TYPE), null, null);
|
||||
if (generateBody) {
|
||||
mv.visitCode();
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
iv.aconst(descriptor.getName().asString());
|
||||
iv.areturn(JAVA_STRING_TYPE);
|
||||
FunctionCodegen.endVisit(iv, "function reference getName", element);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
MethodVisitor mv = v.newMethod(NO_ORIGIN, flags, "getSignature", Type.getMethodDescriptor(JAVA_STRING_TYPE), null, null);
|
||||
if (generateBody) {
|
||||
mv.visitCode();
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
Method method = typeMapper.mapSignature(descriptor).getAsmMethod();
|
||||
iv.aconst(method.getName() + method.getDescriptor());
|
||||
iv.areturn(JAVA_STRING_TYPE);
|
||||
FunctionCodegen.endVisit(iv, "function reference getSignature", element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void generateCallableReferenceDeclarationContainer(
|
||||
@NotNull InstructionAdapter iv,
|
||||
@NotNull CallableDescriptor descriptor,
|
||||
@NotNull JetTypeMapper typeMapper
|
||||
) {
|
||||
DeclarationDescriptor container = descriptor.getContainingDeclaration();
|
||||
if (container instanceof ClassDescriptor) {
|
||||
// TODO: getDefaultType() here is wrong and won't work for arrays
|
||||
StackValue value = generateClassLiteralReference(typeMapper, ((ClassDescriptor) container).getDefaultType());
|
||||
value.put(K_CLASS_TYPE, iv);
|
||||
}
|
||||
else if (container instanceof PackageFragmentDescriptor) {
|
||||
String packageClassInternalName = PackageClassUtils.getPackageClassInternalName(
|
||||
((PackageFragmentDescriptor) container).getFqName()
|
||||
);
|
||||
iv.getstatic(packageClassInternalName, JvmAbi.KOTLIN_PACKAGE_FIELD_NAME, K_PACKAGE_TYPE.getDescriptor());
|
||||
}
|
||||
else if (container instanceof ScriptDescriptor) {
|
||||
// TODO: correct container for scripts (KScript?)
|
||||
StackValue value = generateClassLiteralReference(
|
||||
typeMapper, ((ScriptDescriptor) container).getClassDescriptor().getDefaultType()
|
||||
);
|
||||
value.put(K_CLASS_TYPE, iv);
|
||||
}
|
||||
else {
|
||||
iv.aconst(null);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Method generateConstructor(@NotNull Type superClassAsmType) {
|
||||
private Method generateConstructor() {
|
||||
List<FieldInfo> args = calculateConstructorParameters(typeMapper, closure, asmType);
|
||||
|
||||
Type[] argTypes = fieldListToTypeArray(args);
|
||||
|
||||
+17
-15
@@ -18,23 +18,25 @@ package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.*
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.MutableClassDescriptor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.OverrideResolver
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
import java.util.LinkedHashSet
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import java.util.ArrayList
|
||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker
|
||||
import java.util.HashSet
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_ABSTRACT
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_PUBLIC
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_SYNTHETIC
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import java.util.ArrayList
|
||||
import java.util.HashSet
|
||||
import java.util.LinkedHashSet
|
||||
|
||||
/**
|
||||
* Generates exception-throwing stubs for methods from mutable collection classes not implemented in Kotlin classes which inherit only from
|
||||
@@ -127,7 +129,7 @@ class CollectionStubMethodGenerator(
|
||||
private fun findRelevantSuperCollectionClasses(): Collection<CollectionClassPair> {
|
||||
fun pair(readOnlyClass: ClassDescriptor, mutableClass: ClassDescriptor) = CollectionClassPair(readOnlyClass, mutableClass)
|
||||
|
||||
val collectionClasses = with(KotlinBuiltIns.getInstance()) {
|
||||
val collectionClasses = with(descriptor.builtIns) {
|
||||
listOf(
|
||||
pair(getCollection(), getMutableCollection()),
|
||||
pair(getSet(), getMutableSet()),
|
||||
@@ -164,7 +166,7 @@ class CollectionStubMethodGenerator(
|
||||
val result = ArrayList<FunctionDescriptor>()
|
||||
|
||||
OverrideResolver.generateOverridesInAClass(klass, listOf(), object : OverridingUtil.DescriptorSink {
|
||||
override fun addToScope(fakeOverride: CallableMemberDescriptor) {
|
||||
override fun addFakeOverride(fakeOverride: CallableMemberDescriptor) {
|
||||
if (fakeOverride !is FunctionDescriptor) return
|
||||
if (fakeOverride.findOverriddenFromDirectSuperClass(mutableCollectionClass) != null) {
|
||||
result.add(fakeOverride)
|
||||
|
||||
@@ -206,6 +206,7 @@ public class DefaultParameterValueSubstitutor(val state: GenerationState) {
|
||||
|
||||
private fun isEmptyConstructorNeeded(constructorDescriptor: ConstructorDescriptor, classOrObject: JetClassOrObject): Boolean {
|
||||
val classDescriptor = constructorDescriptor.getContainingDeclaration()
|
||||
if (classDescriptor.getKind() != ClassKind.CLASS) return false
|
||||
|
||||
if (classOrObject.isLocal()) return false
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
|
||||
import org.jetbrains.kotlin.codegen.context.*;
|
||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
|
||||
import org.jetbrains.kotlin.codegen.inline.*;
|
||||
@@ -45,13 +46,15 @@ import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
|
||||
import org.jetbrains.kotlin.codegen.when.SwitchCodegen;
|
||||
import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.ScriptCodeDescriptor;
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils;
|
||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||
import org.jetbrains.kotlin.jvm.RuntimeAssertionInfo;
|
||||
import org.jetbrains.kotlin.jvm.bindingContextSlices.BindingContextSlicesPackage;
|
||||
import org.jetbrains.kotlin.lexer.JetTokens;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
|
||||
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
|
||||
@@ -60,22 +63,20 @@ import org.jetbrains.kotlin.resolve.BindingContextUtils;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage;
|
||||
import org.jetbrains.kotlin.resolve.calls.CallResolverUtil;
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.CallResolverUtilPackage;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*;
|
||||
import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
|
||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject;
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant;
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.EvaluatePackage;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage;
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.*;
|
||||
import org.jetbrains.kotlin.types.Approximation;
|
||||
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
import org.jetbrains.kotlin.types.TypeProjection;
|
||||
import org.jetbrains.kotlin.types.TypeUtils;
|
||||
@@ -85,7 +86,6 @@ import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -104,7 +104,6 @@ import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.OtherOrigin;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.TraitImpl;
|
||||
import static org.jetbrains.kotlin.serialization.deserialization.DeserializationPackage.findClassAcrossModuleDependencies;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implements LocalLookup {
|
||||
@@ -282,12 +281,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
|
||||
StackValue stackValue = selector.accept(visitor, receiver);
|
||||
|
||||
Approximation.Info approximationInfo = null;
|
||||
RuntimeAssertionInfo runtimeAssertionInfo = null;
|
||||
if (selector instanceof JetExpression) {
|
||||
approximationInfo = bindingContext.get(BindingContext.EXPRESSION_RESULT_APPROXIMATION, (JetExpression) selector);
|
||||
runtimeAssertionInfo = bindingContext.get(BindingContextSlicesPackage.getRUNTIME_ASSERTION_INFO(), (JetExpression) selector);
|
||||
}
|
||||
|
||||
return genNotNullAssertions(state, stackValue, approximationInfo);
|
||||
return genNotNullAssertions(state, stackValue, runtimeAssertionInfo);
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
throw e;
|
||||
@@ -1293,20 +1292,19 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
|
||||
@Override
|
||||
public StackValue visitConstantExpression(@NotNull JetConstantExpression expression, StackValue receiver) {
|
||||
CompileTimeConstant<?> compileTimeValue = getCompileTimeConstant(expression, bindingContext);
|
||||
ConstantValue<?> compileTimeValue = getCompileTimeConstant(expression, bindingContext);
|
||||
assert compileTimeValue != null;
|
||||
return StackValue.constant(compileTimeValue.getValue(), expressionType(expression));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static CompileTimeConstant getCompileTimeConstant(@NotNull JetExpression expression, @NotNull BindingContext bindingContext) {
|
||||
public static ConstantValue<?> getCompileTimeConstant(@NotNull JetExpression expression, @NotNull BindingContext bindingContext) {
|
||||
CompileTimeConstant<?> compileTimeValue = ConstantExpressionEvaluator.getConstant(expression, bindingContext);
|
||||
if (compileTimeValue instanceof IntegerValueTypeConstant) {
|
||||
JetType expectedType = bindingContext.getType(expression);
|
||||
assert expectedType != null : "Expression is not type checked: " + expression.getText();
|
||||
return EvaluatePackage.createCompileTimeConstantWithType((IntegerValueTypeConstant) compileTimeValue, expectedType);
|
||||
if (compileTimeValue == null) {
|
||||
return null;
|
||||
}
|
||||
return compileTimeValue;
|
||||
JetType expectedType = bindingContext.getType(expression);
|
||||
return compileTimeValue.toConstantValue(expectedType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1429,7 +1427,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
);
|
||||
|
||||
ClosureCodegen closureCodegen = new ClosureCodegen(
|
||||
state, declaration, samType, context.intoClosure(descriptor, this, typeMapper), kind, strategy, parentCodegen, cv
|
||||
state, declaration, samType, context.intoClosure(descriptor, this, typeMapper), kind,
|
||||
functionReferenceTarget, strategy, parentCodegen, cv
|
||||
);
|
||||
|
||||
closureCodegen.generate();
|
||||
@@ -1439,7 +1438,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
propagateChildReifiedTypeParametersUsages(closureCodegen.getReifiedTypeParametersUsages());
|
||||
}
|
||||
|
||||
return closureCodegen.putInstanceOnStack(this, functionReferenceTarget);
|
||||
return closureCodegen.putInstanceOnStack(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2038,14 +2037,18 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
return localOrCaptured;
|
||||
}
|
||||
|
||||
if (descriptor instanceof ValueParameterDescriptor && descriptor.getContainingDeclaration() instanceof ScriptDescriptor) {
|
||||
ScriptDescriptor scriptDescriptor = (ScriptDescriptor) descriptor.getContainingDeclaration();
|
||||
DeclarationDescriptor container = descriptor.getContainingDeclaration();
|
||||
if (descriptor instanceof ValueParameterDescriptor && container instanceof ScriptCodeDescriptor) {
|
||||
ScriptCodeDescriptor scriptCodeDescriptor = (ScriptCodeDescriptor) container;
|
||||
ScriptDescriptor scriptDescriptor = (ScriptDescriptor) scriptCodeDescriptor.getContainingDeclaration();
|
||||
Type scriptClassType = asmTypeForScriptDescriptor(bindingContext, scriptDescriptor);
|
||||
ValueParameterDescriptor valueParameterDescriptor = (ValueParameterDescriptor) descriptor;
|
||||
ClassDescriptor scriptClass = bindingContext.get(CLASS_FOR_SCRIPT, scriptDescriptor);
|
||||
//noinspection ConstantConditions
|
||||
StackValue script = StackValue.thisOrOuter(this, scriptClass, false, false);
|
||||
Type fieldType = typeMapper.mapType(valueParameterDescriptor);
|
||||
return StackValue.field(fieldType, scriptClassType, valueParameterDescriptor.getName().getIdentifier(), false, script, valueParameterDescriptor);
|
||||
return StackValue.field(fieldType, scriptClassType, valueParameterDescriptor.getName().getIdentifier(), false, script,
|
||||
valueParameterDescriptor);
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("don't know how to generate reference " + descriptor);
|
||||
@@ -2142,6 +2145,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
@NotNull MethodKind methodKind,
|
||||
StackValue receiver
|
||||
) {
|
||||
if (propertyDescriptor instanceof SyntheticJavaPropertyDescriptor) {
|
||||
return intermediateValueForSyntheticExtensionProperty((SyntheticJavaPropertyDescriptor) propertyDescriptor, receiver);
|
||||
}
|
||||
|
||||
DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
|
||||
|
||||
boolean isBackingFieldInAnotherClass = AsmUtil.isPropertyWithBackingFieldInOuterClass(propertyDescriptor);
|
||||
@@ -2164,10 +2171,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
if (isBackingFieldInAnotherClass && forceField) {
|
||||
backingFieldContext = context.findParentContextWithDescriptor(containingDeclaration.getContainingDeclaration());
|
||||
int flags = AsmUtil.getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegatedProperty);
|
||||
skipPropertyAccessors = (flags & ACC_PRIVATE) == 0 || methodKind == MethodKind.SYNTHETIC_ACCESSOR || methodKind == MethodKind.INITIALIZER;
|
||||
skipPropertyAccessors =
|
||||
(flags & ACC_PRIVATE) == 0 || methodKind == MethodKind.SYNTHETIC_ACCESSOR || methodKind == MethodKind.INITIALIZER;
|
||||
if (!skipPropertyAccessors) {
|
||||
propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(propertyDescriptor, true, delegateType);
|
||||
changeOwnerOnTypeMapping = changeOwnerOnTypeMapping && !(propertyDescriptor instanceof AccessorForPropertyBackingFieldInOuterClass);
|
||||
changeOwnerOnTypeMapping =
|
||||
changeOwnerOnTypeMapping && !(propertyDescriptor instanceof AccessorForPropertyBackingFieldInOuterClass);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2189,7 +2198,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
|
||||
PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
|
||||
if (getter != null) {
|
||||
callableGetter = typeMapper.mapToCallableMethod(getter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, context);
|
||||
callableGetter =
|
||||
typeMapper.mapToCallableMethod(getter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2200,14 +2210,16 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
callableSetter = null;
|
||||
}
|
||||
else {
|
||||
callableSetter = typeMapper.mapToCallableMethod(setter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, context);
|
||||
callableSetter =
|
||||
typeMapper.mapToCallableMethod(setter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
propertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor);
|
||||
Type backingFieldOwner = typeMapper.mapOwner(changeOwnerOnTypeMapping ? propertyDescriptor.getContainingDeclaration() : propertyDescriptor,
|
||||
Type backingFieldOwner =
|
||||
typeMapper.mapOwner(changeOwnerOnTypeMapping ? propertyDescriptor.getContainingDeclaration() : propertyDescriptor,
|
||||
isCallInsideSameModuleAsDeclared(propertyDescriptor, context, state.getOutDirectory()));
|
||||
|
||||
String fieldName;
|
||||
@@ -2224,9 +2236,18 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
}
|
||||
|
||||
return StackValue.property(propertyDescriptor, backingFieldOwner,
|
||||
typeMapper.mapType(isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()),
|
||||
isStaticBackingField, fieldName, callableGetter, callableSetter, state, receiver);
|
||||
typeMapper.mapType(
|
||||
isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()),
|
||||
isStaticBackingField, fieldName, callableGetter, callableSetter, state, receiver);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StackValue.Property intermediateValueForSyntheticExtensionProperty(@NotNull SyntheticJavaPropertyDescriptor propertyDescriptor, StackValue receiver) {
|
||||
Type type = typeMapper.mapType(propertyDescriptor.getOriginal().getType());
|
||||
CallableMethod callableGetter = typeMapper.mapToCallableMethod(propertyDescriptor.getGetMethod(), false, context);
|
||||
FunctionDescriptor setMethod = propertyDescriptor.getSetMethod();
|
||||
CallableMethod callableSetter = setMethod != null ? typeMapper.mapToCallableMethod(setMethod, false, context) : null;
|
||||
return StackValue.property(propertyDescriptor, null, type, false, null, callableGetter, callableSetter, state, receiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2329,7 +2350,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
@NotNull
|
||||
public StackValue invokeFunction(@NotNull Call call, @NotNull ResolvedCall<?> resolvedCall, @NotNull StackValue receiver) {
|
||||
FunctionDescriptor fd = accessibleFunctionDescriptor(resolvedCall);
|
||||
JetSuperExpression superCallExpression = CallResolverUtil.getSuperCallExpression(call);
|
||||
JetSuperExpression superCallExpression = CallResolverUtilPackage.getSuperCallExpression(call);
|
||||
boolean superCall = superCallExpression != null;
|
||||
|
||||
if (superCall && !isInterface(fd.getContainingDeclaration())) {
|
||||
@@ -2732,15 +2753,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
|
||||
@Override
|
||||
public StackValue visitClassLiteralExpression(@NotNull JetClassLiteralExpression expression, StackValue data) {
|
||||
checkReflectionIsAvailable(expression);
|
||||
|
||||
JetType type = bindingContext.getType(expression);
|
||||
assert type != null;
|
||||
|
||||
assert state.getReflectionTypes().getkClass().getTypeConstructor().equals(type.getConstructor())
|
||||
: "::class expression should be type checked to a KClass: " + type;
|
||||
|
||||
return generateClassLiteralReference(KotlinPackage.single(type.getArguments()).getType());
|
||||
return generateClassLiteralReference(typeMapper, KotlinPackage.single(type.getArguments()).getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2754,96 +2773,39 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
}
|
||||
|
||||
VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression);
|
||||
if (variableDescriptor == null) {
|
||||
throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText());
|
||||
if (variableDescriptor != null) {
|
||||
return generatePropertyReference(expression, variableDescriptor, resolvedCall);
|
||||
}
|
||||
|
||||
// TODO: this diagnostic should also be reported on function references once they obtain reflection
|
||||
checkReflectionIsAvailable(expression);
|
||||
|
||||
VariableDescriptor descriptor = (VariableDescriptor) resolvedCall.getResultingDescriptor();
|
||||
|
||||
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
|
||||
if (containingDeclaration instanceof PackageFragmentDescriptor) {
|
||||
return generateTopLevelPropertyReference(descriptor);
|
||||
}
|
||||
else if (containingDeclaration instanceof ClassDescriptor) {
|
||||
return generateMemberPropertyReference(descriptor, (ClassDescriptor) containingDeclaration);
|
||||
}
|
||||
else if (containingDeclaration instanceof ScriptDescriptor) {
|
||||
return generateMemberPropertyReference(descriptor, ((ScriptDescriptor) containingDeclaration).getClassDescriptor());
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Unsupported callable reference container: " + containingDeclaration);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkReflectionIsAvailable(@NotNull JetExpression expression) {
|
||||
if (findClassAcrossModuleDependencies(state.getModule(), JvmAbi.REFLECTION_FACTORY_IMPL) == null) {
|
||||
state.getDiagnostics().report(ErrorsJvm.NO_REFLECTION_IN_CLASS_PATH.on(expression, expression));
|
||||
}
|
||||
throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StackValue generateTopLevelPropertyReference(@NotNull final VariableDescriptor descriptor) {
|
||||
PackageFragmentDescriptor containingPackage = (PackageFragmentDescriptor) descriptor.getContainingDeclaration();
|
||||
final String packageClassInternalName = PackageClassUtils.getPackageClassInternalName(containingPackage.getFqName());
|
||||
|
||||
final ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
|
||||
final Method factoryMethod;
|
||||
if (receiverParameter != null) {
|
||||
Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_TYPE, getType(Class.class)};
|
||||
factoryMethod = descriptor.isVar()
|
||||
? method("mutableTopLevelExtensionProperty", K_MUTABLE_TOP_LEVEL_EXTENSION_PROPERTY_TYPE, parameterTypes)
|
||||
: method("topLevelExtensionProperty", K_TOP_LEVEL_EXTENSION_PROPERTY_TYPE, parameterTypes);
|
||||
}
|
||||
else {
|
||||
Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_TYPE};
|
||||
factoryMethod = descriptor.isVar()
|
||||
? method("mutableTopLevelVariable", K_MUTABLE_TOP_LEVEL_VARIABLE_TYPE, parameterTypes)
|
||||
: method("topLevelVariable", K_TOP_LEVEL_VARIABLE_TYPE, parameterTypes);
|
||||
}
|
||||
|
||||
return StackValue.operation(factoryMethod.getReturnType(), new Function1<InstructionAdapter, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(InstructionAdapter v) {
|
||||
v.visitLdcInsn(descriptor.getName().asString());
|
||||
v.getstatic(packageClassInternalName, JvmAbi.KOTLIN_PACKAGE_FIELD_NAME, K_PACKAGE_TYPE.getDescriptor());
|
||||
|
||||
if (receiverParameter != null) {
|
||||
putJavaLangClassInstance(v, typeMapper.mapType(receiverParameter));
|
||||
}
|
||||
|
||||
v.invokestatic(REFLECTION, factoryMethod.getName(), factoryMethod.getDescriptor(), false);
|
||||
return Unit.INSTANCE$;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StackValue generateMemberPropertyReference(
|
||||
@NotNull final VariableDescriptor descriptor,
|
||||
@NotNull final ClassDescriptor containingClass
|
||||
private StackValue generatePropertyReference(
|
||||
@NotNull JetCallableReferenceExpression expression,
|
||||
@NotNull VariableDescriptor variableDescriptor,
|
||||
@NotNull ResolvedCall<?> resolvedCall
|
||||
) {
|
||||
final Method factoryMethod = descriptor.isVar()
|
||||
? method("mutableMemberProperty", K_MUTABLE_MEMBER_PROPERTY_TYPE, JAVA_STRING_TYPE, K_CLASS_TYPE)
|
||||
: method("memberProperty", K_MEMBER_PROPERTY_TYPE, JAVA_STRING_TYPE, K_CLASS_TYPE);
|
||||
ClassDescriptor classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor);
|
||||
|
||||
return StackValue.operation(factoryMethod.getReturnType(), new Function1<InstructionAdapter, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(InstructionAdapter v) {
|
||||
v.visitLdcInsn(descriptor.getName().asString());
|
||||
StackValue receiverClass = generateClassLiteralReference(containingClass.getDefaultType());
|
||||
receiverClass.put(receiverClass.type, v);
|
||||
v.invokestatic(REFLECTION, factoryMethod.getName(), factoryMethod.getDescriptor(), false);
|
||||
ClassBuilder classBuilder = state.getFactory().newVisitor(
|
||||
OtherOrigin(expression),
|
||||
typeMapper.mapClass(classDescriptor),
|
||||
expression.getContainingFile()
|
||||
);
|
||||
|
||||
return Unit.INSTANCE$;
|
||||
}
|
||||
});
|
||||
@SuppressWarnings("unchecked")
|
||||
PropertyReferenceCodegen codegen = new PropertyReferenceCodegen(
|
||||
state, parentCodegen, context.intoAnonymousClass(classDescriptor, this, OwnerKind.IMPLEMENTATION),
|
||||
expression, classBuilder, classDescriptor, (ResolvedCall<VariableDescriptor>) resolvedCall
|
||||
);
|
||||
codegen.generate();
|
||||
|
||||
return codegen.putInstanceOnStack();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StackValue generateClassLiteralReference(@NotNull final JetType type) {
|
||||
public static StackValue generateClassLiteralReference(@NotNull final JetTypeMapper typeMapper, @NotNull final JetType type) {
|
||||
return StackValue.operation(K_CLASS_TYPE, new Function1<InstructionAdapter, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(InstructionAdapter v) {
|
||||
@@ -2851,7 +2813,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
|
||||
//noinspection ConstantConditions
|
||||
ModuleDescriptor module = DescriptorUtils.getContainingModule(descriptor);
|
||||
if (descriptor instanceof JavaClassDescriptor || module == module.getBuiltIns().getBuiltInsModule()) {
|
||||
// Instantiate annotation classes as foreign due to bug in JDK 6 and 7:
|
||||
// http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6857918
|
||||
if (descriptor instanceof JavaClassDescriptor || module == module.getBuiltIns().getBuiltInsModule() ||
|
||||
DescriptorUtils.isAnnotationClass(descriptor)) {
|
||||
putJavaLangClassInstance(v, classAsmType);
|
||||
wrapJavaClassIntoKClass(v);
|
||||
}
|
||||
@@ -3064,7 +3029,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
}
|
||||
|
||||
private boolean isIntZero(JetExpression expr, Type exprType) {
|
||||
CompileTimeConstant<?> exprValue = getCompileTimeConstant(expr, bindingContext);
|
||||
ConstantValue<?> exprValue = getCompileTimeConstant(expr, bindingContext);
|
||||
return isIntPrimitive(exprType) && exprValue != null && Integer.valueOf(0).equals(exprValue.getValue());
|
||||
}
|
||||
|
||||
@@ -3596,14 +3561,14 @@ The "returned" value of try expression with no finally is either the last expres
|
||||
return StackValue.operation(expectedAsmType, new Function1<InstructionAdapter, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(InstructionAdapter v) {
|
||||
|
||||
JetFinallySection finallyBlock = expression.getFinallyBlock();
|
||||
JetFinallySection finallyBlock = expression.getFinallyBlock();
|
||||
FinallyBlockStackElement finallyBlockStackElement = null;
|
||||
if (finallyBlock != null) {
|
||||
finallyBlockStackElement = new FinallyBlockStackElement(expression);
|
||||
blockStackElements.push(finallyBlockStackElement);
|
||||
}
|
||||
|
||||
//PseudoInsnsPackage.saveStackBeforeTryExpr(v);
|
||||
|
||||
Label tryStart = new Label();
|
||||
v.mark(tryStart);
|
||||
@@ -3667,6 +3632,7 @@ The "returned" value of try expression with no finally is either the last expres
|
||||
v.mark(defaultCatchStart);
|
||||
int savedException = myFrameMap.enterTemp(JAVA_THROWABLE_TYPE);
|
||||
v.store(savedException, JAVA_THROWABLE_TYPE);
|
||||
|
||||
Label defaultCatchEnd = new Label();
|
||||
v.mark(defaultCatchEnd);
|
||||
|
||||
@@ -3727,63 +3693,50 @@ The "returned" value of try expression with no finally is either the last expres
|
||||
|
||||
@Override
|
||||
public StackValue visitBinaryWithTypeRHSExpression(@NotNull JetBinaryExpressionWithTypeRHS expression, StackValue receiver) {
|
||||
JetSimpleNameExpression operationSign = expression.getOperationReference();
|
||||
final IElementType opToken = operationSign.getReferencedNameElementType();
|
||||
JetExpression left = expression.getLeft();
|
||||
final IElementType opToken = expression.getOperationReference().getReferencedNameElementType();
|
||||
if (opToken == JetTokens.COLON) {
|
||||
return gen(expression.getLeft());
|
||||
return gen(left);
|
||||
}
|
||||
else {
|
||||
JetTypeReference typeReference = expression.getRight();
|
||||
final JetType rightType = bindingContext.get(TYPE, typeReference);
|
||||
assert rightType != null;
|
||||
|
||||
Type rightTypeAsm = boxType(asmType(rightType));
|
||||
final JetExpression left = expression.getLeft();
|
||||
final JetType rightType = bindingContext.get(TYPE, expression.getRight());
|
||||
assert rightType != null;
|
||||
|
||||
DeclarationDescriptor descriptor = rightType.getConstructor().getDeclarationDescriptor();
|
||||
if (descriptor instanceof ClassDescriptor || descriptor instanceof TypeParameterDescriptor) {
|
||||
final StackValue value = genQualified(receiver, left);
|
||||
final StackValue value = genQualified(receiver, left);
|
||||
|
||||
return StackValue.operation(rightTypeAsm, new Function1<InstructionAdapter, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(InstructionAdapter v) {
|
||||
value.put(boxType(value.type), v);
|
||||
return StackValue.operation(boxType(asmType(rightType)), new Function1<InstructionAdapter, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(InstructionAdapter v) {
|
||||
value.put(boxType(value.type), v);
|
||||
|
||||
if (value.type == Type.VOID_TYPE) {
|
||||
v.aconst(null);
|
||||
}
|
||||
else if (opToken != JetTokens.AS_SAFE) {
|
||||
if (!TypeUtils.isNullableType(rightType)) {
|
||||
v.dup();
|
||||
Label nonnull = new Label();
|
||||
v.ifnonnull(nonnull);
|
||||
JetType leftType = bindingContext.getType(left);
|
||||
assert leftType != null;
|
||||
genThrow(v, "kotlin/TypeCastException", DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(leftType) +
|
||||
" cannot be cast to " +
|
||||
DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(rightType));
|
||||
v.mark(nonnull);
|
||||
}
|
||||
}
|
||||
else {
|
||||
v.dup();
|
||||
generateInstanceOfInstruction(rightType);
|
||||
Label ok = new Label();
|
||||
v.ifne(ok);
|
||||
v.pop();
|
||||
v.aconst(null);
|
||||
v.mark(ok);
|
||||
}
|
||||
if (value.type == Type.VOID_TYPE) {
|
||||
StackValue.putUnitInstance(v);
|
||||
}
|
||||
|
||||
generateCheckCastInstruction(rightType);
|
||||
return Unit.INSTANCE$;
|
||||
if (opToken != JetTokens.AS_SAFE) {
|
||||
if (!TypeUtils.isNullableType(rightType)) {
|
||||
v.dup();
|
||||
Label nonnull = new Label();
|
||||
v.ifnonnull(nonnull);
|
||||
genThrow(v, "kotlin/TypeCastException", "null cannot be cast to non-null type " +
|
||||
DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(rightType));
|
||||
v.mark(nonnull);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
v.dup();
|
||||
generateInstanceOfInstruction(rightType);
|
||||
Label ok = new Label();
|
||||
v.ifne(ok);
|
||||
v.pop();
|
||||
v.aconst(null);
|
||||
v.mark(ok);
|
||||
}
|
||||
|
||||
generateCheckCastInstruction(rightType);
|
||||
return Unit.INSTANCE$;
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Don't know how to handle non-class types in as/as? : " + descriptor);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,7 +20,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.builtins.CompanionObjectMapping;
|
||||
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
@@ -46,18 +45,6 @@ public class FieldInfo {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@NotNull
|
||||
public static FieldInfo deprecatedFieldForCompanionObject(@NotNull ClassDescriptor companionObject, @NotNull JetTypeMapper typeMapper) {
|
||||
assert DescriptorUtils.isCompanionObject(companionObject) : "Not a companion object: " + companionObject;
|
||||
return new FieldInfo(
|
||||
typeMapper.mapType((ClassifierDescriptor) companionObject.getContainingDeclaration()),
|
||||
typeMapper.mapType(companionObject),
|
||||
JvmAbi.DEPRECATED_COMPANION_OBJECT_FIELD,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FieldInfo createForHiddenField(@NotNull Type owner, @NotNull Type fieldType, @NotNull String fieldName) {
|
||||
return new FieldInfo(owner, fieldType, fieldName, false);
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.kotlin.jvm.RuntimeAssertionInfo;
|
||||
import org.jetbrains.kotlin.load.kotlin.nativeDeclarations.NativeDeclarationsPackage;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.psi.JetNamedFunction;
|
||||
@@ -42,17 +43,15 @@ import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage;
|
||||
import org.jetbrains.kotlin.resolve.calls.CallResolverUtil;
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.CallResolverUtilPackage;
|
||||
import org.jetbrains.kotlin.resolve.constants.ArrayValue;
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||
import org.jetbrains.kotlin.resolve.constants.KClassValue;
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage;
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
|
||||
import org.jetbrains.kotlin.types.Approximation;
|
||||
import org.jetbrains.kotlin.types.TypesPackage;
|
||||
import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
@@ -502,7 +501,7 @@ public class FunctionCodegen {
|
||||
if (isMethodOfAny(descriptor)) return;
|
||||
|
||||
// If the function doesn't have a physical declaration among super-functions, it's a SAM adapter or alike and doesn't need bridges
|
||||
if (CallResolverUtil.isOrOverridesSynthesized(descriptor)) return;
|
||||
if (CallResolverUtilPackage.isOrOverridesSynthesized(descriptor)) return;
|
||||
|
||||
Set<Bridge<Method>> bridgesToGenerate = BridgesPackage.generateBridgesForFunctionDescriptor(
|
||||
descriptor,
|
||||
@@ -539,7 +538,7 @@ public class FunctionCodegen {
|
||||
AnnotationDescriptor annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.throws"));
|
||||
if (annotation == null) return ArrayUtil.EMPTY_STRING_ARRAY;
|
||||
|
||||
Collection<CompileTimeConstant<?>> values = annotation.getAllValueArguments().values();
|
||||
Collection<ConstantValue<?>> values = annotation.getAllValueArguments().values();
|
||||
if (values.isEmpty()) return ArrayUtil.EMPTY_STRING_ARRAY;
|
||||
|
||||
Object value = values.iterator().next();
|
||||
@@ -548,9 +547,9 @@ public class FunctionCodegen {
|
||||
|
||||
List<String> strings = ContainerUtil.mapNotNull(
|
||||
arrayValue.getValue(),
|
||||
new Function<CompileTimeConstant<?>, String>() {
|
||||
new Function<ConstantValue<?>, String>() {
|
||||
@Override
|
||||
public String fun(CompileTimeConstant<?> constant) {
|
||||
public String fun(ConstantValue<?> constant) {
|
||||
if (constant instanceof KClassValue) {
|
||||
KClassValue classValue = (KClassValue) constant;
|
||||
ClassDescriptor classDescriptor = DescriptorUtils.getClassDescriptorForType(classValue.getValue());
|
||||
@@ -834,10 +833,10 @@ public class FunctionCodegen {
|
||||
StackValue stackValue = AsmUtil.genNotNullAssertions(
|
||||
state,
|
||||
StackValue.onStack(delegateToMethod.getReturnType()),
|
||||
TypesPackage.getApproximationTo(
|
||||
delegatedTo.getReturnType(),
|
||||
RuntimeAssertionInfo.create(
|
||||
delegateFunction.getReturnType(),
|
||||
new Approximation.DataFlowExtras.OnlyMessage(delegatedTo.getName() + "(...)")
|
||||
delegatedTo.getReturnType(),
|
||||
new RuntimeAssertionInfo.DataFlowExtras.OnlyMessage(delegatedTo.getName() + "(...)")
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
+9
-2
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import kotlin.KotlinPackage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
@@ -133,8 +134,14 @@ public class FunctionReferenceGenerationStrategy extends FunctionGenerationStrat
|
||||
}
|
||||
|
||||
private void computeAndSaveArguments(@NotNull List<? extends ValueArgument> fakeArguments, @NotNull ExpressionCodegen codegen) {
|
||||
for (ValueParameterDescriptor parameter : callableDescriptor.getValueParameters()) {
|
||||
ValueArgument fakeArgument = fakeArguments.get(parameter.getIndex());
|
||||
int receivers = (referencedFunction.getDispatchReceiverParameter() != null ? 1 : 0) +
|
||||
(referencedFunction.getExtensionReceiverParameter() != null ? 1 : 0);
|
||||
|
||||
List<ValueParameterDescriptor> parameters = KotlinPackage.drop(callableDescriptor.getValueParameters(), receivers);
|
||||
for (int i = 0; i < parameters.size(); i++) {
|
||||
ValueParameterDescriptor parameter = parameters.get(i);
|
||||
ValueArgument fakeArgument = fakeArguments.get(i);
|
||||
|
||||
Type type = state.getTypeMapper().mapType(parameter);
|
||||
int localIndex = codegen.myFrameMap.getIndex(parameter);
|
||||
codegen.tempVariables.put(fakeArgument.getArgumentExpression(), StackValue.local(localIndex, type));
|
||||
|
||||
@@ -43,14 +43,13 @@ import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinClass;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage;
|
||||
import org.jetbrains.kotlin.resolve.calls.CallResolverUtil;
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.CallResolverUtilPackage;
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument;
|
||||
@@ -139,7 +138,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
isAbstract = true;
|
||||
isInterface = true;
|
||||
}
|
||||
else if (jetClass.isAnnotation()) {
|
||||
else if (descriptor.getKind() == ClassKind.ANNOTATION_CLASS) {
|
||||
isAbstract = true;
|
||||
isInterface = true;
|
||||
isAnnotation = true;
|
||||
@@ -240,13 +239,20 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
kind = KotlinClass.Kind.ANONYMOUS_OBJECT;
|
||||
}
|
||||
else if (isTopLevelOrInnerClass(descriptor)) {
|
||||
kind = KotlinClass.Kind.CLASS;
|
||||
// Default value is Kind.CLASS
|
||||
kind = null;
|
||||
}
|
||||
else {
|
||||
// LOCAL_CLASS is also written to inner classes of local classes
|
||||
kind = KotlinClass.Kind.LOCAL_CLASS;
|
||||
}
|
||||
|
||||
// Temporarily write class kind anyway because old compiler may not expect its absence
|
||||
// TODO: remove after M13
|
||||
if (kind == null) {
|
||||
kind = KotlinClass.Kind.CLASS;
|
||||
}
|
||||
|
||||
DescriptorSerializer serializer =
|
||||
DescriptorSerializer.create(descriptor, new JvmSerializerExtension(v.getSerializationBindings(), typeMapper));
|
||||
|
||||
@@ -258,11 +264,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
AnnotationVisitor av = v.getVisitor().visitAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_CLASS), true);
|
||||
av.visit(JvmAnnotationNames.ABI_VERSION_FIELD_NAME, JvmAbi.VERSION);
|
||||
av.visitEnum(
|
||||
JvmAnnotationNames.KIND_FIELD_NAME,
|
||||
Type.getObjectType(KotlinClass.KIND_INTERNAL_NAME).getDescriptor(),
|
||||
kind.toString()
|
||||
);
|
||||
//noinspection ConstantConditions
|
||||
if (kind != null) {
|
||||
av.visitEnum(
|
||||
JvmAnnotationNames.KIND_FIELD_NAME,
|
||||
Type.getObjectType(KotlinClass.KIND_INTERNAL_NAME).getDescriptor(),
|
||||
kind.toString()
|
||||
);
|
||||
}
|
||||
AnnotationVisitor array = av.visitArray(JvmAnnotationNames.DATA_FIELD_NAME);
|
||||
for (String string : BitEncoding.encodeBytes(SerializationUtil.serializeClassData(data))) {
|
||||
array.visit(null, string);
|
||||
@@ -394,7 +403,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
private boolean isGenericToArrayPresent() {
|
||||
Collection<FunctionDescriptor> functions = descriptor.getDefaultType().getMemberScope().getFunctions(Name.identifier("toArray"));
|
||||
for (FunctionDescriptor function : functions) {
|
||||
if (CallResolverUtil.isOrOverridesSynthesized(function)) {
|
||||
if (CallResolverUtilPackage.isOrOverridesSynthesized(function)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1008,12 +1017,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
StackValue.Field field = StackValue.singleton(companionObjectDescriptor, typeMapper);
|
||||
v.newField(OtherOrigin(companionObject), ACC_PUBLIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null);
|
||||
|
||||
StackValue.Field deprecatedField = StackValue.deprecatedCompanionObjectAccessor(companionObjectDescriptor, typeMapper);
|
||||
FieldVisitor fv = v.newField(OtherOrigin(companionObject), ACC_PUBLIC | ACC_STATIC | ACC_FINAL | ACC_DEPRECATED,
|
||||
deprecatedField.name, deprecatedField.type.getDescriptor(), null, null);
|
||||
|
||||
fv.visitAnnotation(asmDescByFqNameWithoutInnerClasses(new FqName("java.lang.Deprecated")), true).visitEnd();
|
||||
|
||||
if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
|
||||
|
||||
if (!isCompanionObjectWithBackingFieldsInOuter(companionObjectDescriptor)) {
|
||||
@@ -1074,7 +1077,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
codegen.v.dup();
|
||||
StackValue instance = StackValue.onStack(typeMapper.mapClass(companionObject));
|
||||
StackValue.singleton(companionObject, typeMapper).store(instance, codegen.v, true);
|
||||
StackValue.deprecatedCompanionObjectAccessor(companionObject, typeMapper).store(instance, codegen.v, true);
|
||||
}
|
||||
|
||||
private void generatePrimaryConstructor(final DelegationFieldsInfo delegationFieldsInfo) {
|
||||
|
||||
@@ -29,15 +29,15 @@ import org.jetbrains.kotlin.storage.LockBasedStorageManager;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getBuiltIns;
|
||||
|
||||
public class JvmRuntimeTypes {
|
||||
private final ClassDescriptor lambda;
|
||||
private final ClassDescriptor functionReference;
|
||||
private final List<ClassDescriptor> propertyReferences;
|
||||
private final List<ClassDescriptor> mutablePropertyReferences;
|
||||
|
||||
public JvmRuntimeTypes() {
|
||||
ModuleDescriptorImpl module = new ModuleDescriptorImpl(
|
||||
@@ -49,6 +49,13 @@ public class JvmRuntimeTypes {
|
||||
|
||||
this.lambda = createClass(kotlinJvmInternal, "Lambda");
|
||||
this.functionReference = createClass(kotlinJvmInternal, "FunctionReference");
|
||||
this.propertyReferences = new ArrayList<ClassDescriptor>(3);
|
||||
this.mutablePropertyReferences = new ArrayList<ClassDescriptor>(3);
|
||||
|
||||
for (int i = 0; i <= 2; i++) {
|
||||
propertyReferences.add(createClass(kotlinJvmInternal, "PropertyReference" + i));
|
||||
mutablePropertyReferences.add(createClass(kotlinJvmInternal, "MutablePropertyReference" + i));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -98,4 +105,11 @@ public class JvmRuntimeTypes {
|
||||
|
||||
return Arrays.asList(functionReference.getDefaultType(), functionType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JetType getSupertypeForPropertyReference(@NotNull PropertyDescriptor descriptor) {
|
||||
int arity = (descriptor.getExtensionReceiverParameter() != null ? 1 : 0) +
|
||||
(descriptor.getDispatchReceiverParameter() != null ? 1 : 0);
|
||||
return (descriptor.isVar() ? mutablePropertyReferences : propertyReferences).get(arity).getDefaultType();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ import static org.jetbrains.kotlin.codegen.JvmSerializationBindings.*;
|
||||
public class JvmSerializerExtension extends SerializerExtension {
|
||||
private final JvmSerializationBindings bindings;
|
||||
private final JetTypeMapper typeMapper;
|
||||
private final AnnotationSerializer annotationSerializer = new AnnotationSerializer();
|
||||
|
||||
public JvmSerializerExtension(@NotNull JvmSerializationBindings bindings, @NotNull JetTypeMapper typeMapper) {
|
||||
this.bindings = bindings;
|
||||
@@ -77,7 +78,7 @@ public class JvmSerializerExtension extends SerializerExtension {
|
||||
public void serializeType(@NotNull JetType type, @NotNull ProtoBuf.Type.Builder proto, @NotNull StringTable stringTable) {
|
||||
// TODO: don't store type annotations in our binary metadata on Java 8, use *TypeAnnotations attributes instead
|
||||
for (AnnotationDescriptor annotation : type.getAnnotations()) {
|
||||
proto.addExtension(JvmProtoBuf.typeAnnotation, AnnotationSerializer.INSTANCE$.serializeAnnotation(annotation, stringTable));
|
||||
proto.addExtension(JvmProtoBuf.typeAnnotation, annotationSerializer.serializeAnnotation(annotation, stringTable));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function0;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.context.*;
|
||||
@@ -37,8 +39,7 @@ import org.jetbrains.kotlin.resolve.BindingContextUtils;
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace;
|
||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant;
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage;
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager;
|
||||
@@ -377,26 +378,28 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
|
||||
|
||||
JetExpression initializer = property.getInitializer();
|
||||
|
||||
CompileTimeConstant<?> initializerValue;
|
||||
if (property.isVar() && initializer != null) {
|
||||
BindingTrace tempTrace = TemporaryBindingTrace.create(state.getBindingTrace(), "property initializer");
|
||||
initializerValue = ConstantExpressionEvaluator.evaluate(initializer, tempTrace, propertyDescriptor.getType());
|
||||
}
|
||||
else {
|
||||
initializerValue = propertyDescriptor.getCompileTimeInitializer();
|
||||
}
|
||||
ConstantValue<?> initializerValue = computeInitializerValue(property, propertyDescriptor, initializer);
|
||||
// we must write constant values for fields in light classes,
|
||||
// because Java's completion for annotation arguments uses this information
|
||||
if (initializerValue == null) return state.getClassBuilderMode() != ClassBuilderMode.LIGHT_CLASSES;
|
||||
|
||||
//TODO: OPTIMIZATION: don't initialize static final fields
|
||||
|
||||
Object value = initializerValue instanceof IntegerValueTypeConstant
|
||||
? ((IntegerValueTypeConstant) initializerValue).getValue(propertyDescriptor.getType())
|
||||
: initializerValue.getValue();
|
||||
JetType jetType = getPropertyOrDelegateType(property, propertyDescriptor);
|
||||
Type type = typeMapper.mapType(jetType);
|
||||
return !skipDefaultValue(propertyDescriptor, value, type);
|
||||
return !skipDefaultValue(propertyDescriptor, initializerValue.getValue(), type);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ConstantValue<?> computeInitializerValue(
|
||||
@NotNull JetProperty property,
|
||||
@NotNull PropertyDescriptor propertyDescriptor,
|
||||
@Nullable JetExpression initializer
|
||||
) {
|
||||
if (property.isVar() && initializer != null) {
|
||||
BindingTrace tempTrace = TemporaryBindingTrace.create(state.getBindingTrace(), "property initializer");
|
||||
return ConstantExpressionEvaluator.evaluateToConstantValue(initializer, tempTrace, propertyDescriptor.getType());
|
||||
}
|
||||
return propertyDescriptor.getCompileTimeInitializer();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -532,4 +535,22 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
|
||||
}
|
||||
return sourceMapper;
|
||||
}
|
||||
|
||||
protected void generateConstInstance(
|
||||
@NotNull Type thisAsmType,
|
||||
@NotNull Type fieldAsmType,
|
||||
@NotNull Function1<InstructionAdapter, Unit> initialization
|
||||
) {
|
||||
v.newField(OtherOrigin(element), ACC_STATIC | ACC_FINAL | ACC_PUBLIC, JvmAbi.INSTANCE_FIELD, fieldAsmType.getDescriptor(),
|
||||
null, null);
|
||||
|
||||
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
||||
InstructionAdapter iv = createOrGetClInitCodegen().v;
|
||||
iv.anew(thisAsmType);
|
||||
iv.dup();
|
||||
iv.invokespecial(thisAsmType.getInternalName(), "<init>", "()V", false);
|
||||
initialization.invoke(iv);
|
||||
iv.putstatic(thisAsmType.getInternalName(), JvmAbi.INSTANCE_FIELD, fieldAsmType.getDescriptor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -26,14 +25,14 @@ import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorFactory;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor;
|
||||
import org.jetbrains.kotlin.types.ErrorUtils;
|
||||
@@ -181,7 +180,7 @@ public class PropertyCodegen {
|
||||
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
||||
JetExpression defaultValue = p.getDefaultValue();
|
||||
if (defaultValue != null) {
|
||||
CompileTimeConstant<?> constant = ExpressionCodegen.getCompileTimeConstant(defaultValue, bindingContext);
|
||||
ConstantValue<?> constant = ExpressionCodegen.getCompileTimeConstant(defaultValue, bindingContext);
|
||||
assert constant != null : "Default value for annotation parameter should be compile time value: " + defaultValue.getText();
|
||||
AnnotationCodegen annotationCodegen = AnnotationCodegen.forAnnotationDefaultValue(mv, typeMapper);
|
||||
annotationCodegen.generateAnnotationDefaultValue(constant, descriptor.getType());
|
||||
@@ -256,9 +255,19 @@ public class PropertyCodegen {
|
||||
|
||||
ClassBuilder builder = v;
|
||||
|
||||
boolean hasPublicFieldAnnotation = AnnotationsPackage.findPublicFieldAnnotation(propertyDescriptor) != null;
|
||||
|
||||
FieldOwnerContext backingFieldContext = context;
|
||||
if (AsmUtil.isInstancePropertyWithStaticBackingField(propertyDescriptor) ) {
|
||||
modifiers |= ACC_STATIC | getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegate);
|
||||
modifiers |= ACC_STATIC;
|
||||
|
||||
if (hasPublicFieldAnnotation && !isDelegate) {
|
||||
modifiers |= ACC_PUBLIC;
|
||||
}
|
||||
else {
|
||||
modifiers |= getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegate);
|
||||
}
|
||||
|
||||
if (AsmUtil.isPropertyWithBackingFieldInOuterClass(propertyDescriptor)) {
|
||||
ImplementationBodyCodegen codegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen();
|
||||
builder = codegen.v;
|
||||
@@ -266,6 +275,9 @@ public class PropertyCodegen {
|
||||
v.getSerializationBindings().put(STATIC_FIELD_IN_OUTER_CLASS, propertyDescriptor);
|
||||
}
|
||||
}
|
||||
else if (!isDelegate && hasPublicFieldAnnotation) {
|
||||
modifiers |= ACC_PUBLIC;
|
||||
}
|
||||
else if (kind != OwnerKind.PACKAGE || isDelegate) {
|
||||
modifiers |= ACC_PRIVATE;
|
||||
}
|
||||
@@ -299,7 +311,7 @@ public class PropertyCodegen {
|
||||
Object value = null;
|
||||
|
||||
if (shouldWriteFieldInitializer(propertyDescriptor)) {
|
||||
CompileTimeConstant<?> initializer = propertyDescriptor.getCompileTimeInitializer();
|
||||
ConstantValue<?> initializer = propertyDescriptor.getCompileTimeInitializer();
|
||||
if (initializer != null) {
|
||||
value = initializer.getValue();
|
||||
}
|
||||
@@ -477,16 +489,6 @@ public class PropertyCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getterName(Name propertyName) {
|
||||
return JvmAbi.GETTER_PREFIX + StringUtil.capitalizeWithJavaBeanConvention(propertyName.asString());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String setterName(Name propertyName) {
|
||||
return JvmAbi.SETTER_PREFIX + StringUtil.capitalizeWithJavaBeanConvention(propertyName.asString());
|
||||
}
|
||||
|
||||
public void genDelegate(@NotNull PropertyDescriptor delegate, @NotNull PropertyDescriptor delegateTo, @NotNull StackValue field) {
|
||||
ClassDescriptor toClass = (ClassDescriptor) delegateTo.getContainingDeclaration();
|
||||
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil.method
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil.writeKotlinSyntheticClassAnnotation
|
||||
import org.jetbrains.kotlin.codegen.context.ClassContext
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.JetCallableReferenceExpression
|
||||
import org.jetbrains.kotlin.resolve.DescriptorFactory
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ScriptReceiver
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_FINAL
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_PUBLIC
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_SUPER
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.V1_6
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
|
||||
public class PropertyReferenceCodegen(
|
||||
state: GenerationState,
|
||||
parentCodegen: MemberCodegen<*>,
|
||||
context: ClassContext,
|
||||
expression: JetCallableReferenceExpression,
|
||||
classBuilder: ClassBuilder,
|
||||
private val classDescriptor: ClassDescriptor,
|
||||
private val resolvedCall: ResolvedCall<VariableDescriptor>
|
||||
) : MemberCodegen<JetCallableReferenceExpression>(state, parentCodegen, context, expression, classBuilder) {
|
||||
private val target = resolvedCall.getResultingDescriptor()
|
||||
private val asmType = typeMapper.mapClass(classDescriptor)
|
||||
|
||||
// e.g. MutablePropertyReference0
|
||||
private val superAsmType = typeMapper.mapClass(classDescriptor.getSuperClassNotAny().sure { "No super class for $classDescriptor" })
|
||||
|
||||
// e.g. mutableProperty0(Lkotlin/jvm/internal/MutablePropertyReference0;)Lkotlin/reflect/KMutableProperty0;
|
||||
private val wrapperMethod: Method
|
||||
|
||||
init {
|
||||
val hasReceiver = target.getDispatchReceiverParameter() != null || target.getExtensionReceiverParameter() != null
|
||||
val isMutable = target.isVar()
|
||||
|
||||
wrapperMethod = when {
|
||||
hasReceiver -> when {
|
||||
isMutable -> method("mutableProperty1", K_MUTABLE_PROPERTY1_TYPE, MUTABLE_PROPERTY_REFERENCE1)
|
||||
else -> method("property1", K_PROPERTY1_TYPE, PROPERTY_REFERENCE1)
|
||||
}
|
||||
else -> when {
|
||||
isMutable -> method("mutableProperty0", K_MUTABLE_PROPERTY0_TYPE, MUTABLE_PROPERTY_REFERENCE0)
|
||||
else -> method("property0", K_PROPERTY0_TYPE, PROPERTY_REFERENCE0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateDeclaration() {
|
||||
v.defineClass(
|
||||
element,
|
||||
V1_6,
|
||||
ACC_FINAL or ACC_SUPER or AsmUtil.getVisibilityAccessFlagForAnonymous(classDescriptor),
|
||||
asmType.getInternalName(),
|
||||
null,
|
||||
superAsmType.getInternalName(),
|
||||
emptyArray()
|
||||
)
|
||||
|
||||
v.visitSource(element.getContainingFile().getName(), null)
|
||||
}
|
||||
|
||||
// TODO: ImplementationBodyCodegen.markLineNumberForSyntheticFunction?
|
||||
override fun generateBody() {
|
||||
generateConstInstance(asmType, wrapperMethod.getReturnType()) { iv ->
|
||||
iv.invokestatic(REFLECTION, wrapperMethod.getName(), wrapperMethod.getDescriptor(), false)
|
||||
}
|
||||
|
||||
generateMethod("property reference init", 0, method("<init>", Type.VOID_TYPE)) {
|
||||
load(0, OBJECT_TYPE)
|
||||
invokespecial(superAsmType.getInternalName(), "<init>", "()V", false)
|
||||
}
|
||||
|
||||
generateMethod("property reference getOwner", ACC_PUBLIC, method("getOwner", K_DECLARATION_CONTAINER_TYPE)) {
|
||||
ClosureCodegen.generateCallableReferenceDeclarationContainer(this, target, typeMapper)
|
||||
}
|
||||
|
||||
generateMethod("property reference getName", ACC_PUBLIC, method("getName", JAVA_STRING_TYPE)) {
|
||||
aconst(target.getName().asString())
|
||||
}
|
||||
|
||||
generateMethod("property reference getSignature", ACC_PUBLIC, method("getSignature", JAVA_STRING_TYPE)) {
|
||||
target as PropertyDescriptor
|
||||
|
||||
val getter = target.getGetter() ?: run {
|
||||
val defaultGetter = DescriptorFactory.createDefaultGetter(target)
|
||||
defaultGetter.initialize(target.getType())
|
||||
defaultGetter
|
||||
}
|
||||
|
||||
val method = typeMapper.mapSignature(getter).getAsmMethod()
|
||||
aconst(method.getName() + method.getDescriptor())
|
||||
}
|
||||
|
||||
generateAccessors()
|
||||
}
|
||||
|
||||
private fun generateAccessors() {
|
||||
val dispatchReceiver = resolvedCall.getDispatchReceiver()
|
||||
val extensionReceiver = resolvedCall.getExtensionReceiver()
|
||||
val receiverType =
|
||||
when {
|
||||
dispatchReceiver is ScriptReceiver -> {
|
||||
// TODO: fix receiver for scripts, see ScriptReceiver#getType
|
||||
dispatchReceiver.getDeclarationDescriptor().getClassDescriptor().getDefaultType()
|
||||
}
|
||||
dispatchReceiver.exists() -> dispatchReceiver.getType()
|
||||
extensionReceiver.exists() -> extensionReceiver.getType()
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun generateAccessor(method: Method, accessorBody: InstructionAdapter.(StackValue) -> Unit) {
|
||||
generateMethod("property reference $method", ACC_PUBLIC, method) {
|
||||
// Note: this descriptor is an inaccurate representation of the get/set method. In particular, it has incorrect
|
||||
// return type and value parameter types. However, it's created only to be able to use
|
||||
// ExpressionCodegen#intermediateValueForProperty, which is poorly coupled with everything else.
|
||||
val fakeDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||
classDescriptor, Annotations.EMPTY, Name.identifier(method.getName()), CallableMemberDescriptor.Kind.DECLARATION,
|
||||
SourceElement.NO_SOURCE
|
||||
)
|
||||
fakeDescriptor.initialize(null, classDescriptor.getThisAsReceiverParameter(), emptyList(), emptyList(),
|
||||
classDescriptor.builtIns.getAnyType(), Modality.OPEN, Visibilities.PUBLIC)
|
||||
|
||||
val fakeCodegen = ExpressionCodegen(
|
||||
this, FrameMap(), OBJECT_TYPE, context.intoFunction(fakeDescriptor), state, this@PropertyReferenceCodegen
|
||||
)
|
||||
|
||||
val receiver =
|
||||
if (receiverType != null) StackValue.coercion(StackValue.local(1, OBJECT_TYPE), typeMapper.mapType(receiverType))
|
||||
else StackValue.none()
|
||||
val value = fakeCodegen.intermediateValueForProperty(target as PropertyDescriptor, false, null, receiver)
|
||||
|
||||
accessorBody(value)
|
||||
}
|
||||
}
|
||||
|
||||
val getterParameters = if (receiverType != null) arrayOf(OBJECT_TYPE) else emptyArray()
|
||||
generateAccessor(method("get", OBJECT_TYPE, *getterParameters)) { value ->
|
||||
value.put(OBJECT_TYPE, this)
|
||||
}
|
||||
|
||||
if (!target.isVar()) return
|
||||
|
||||
val setterParameters = (getterParameters + arrayOf(OBJECT_TYPE))
|
||||
generateAccessor(method("set", Type.VOID_TYPE, *setterParameters)) { value ->
|
||||
// Hard-coded 1 or 2 is safe here because there's only java/lang/Object in the signature, no double/long parameters
|
||||
value.store(StackValue.local(if (receiverType != null) 2 else 1, OBJECT_TYPE), this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateMethod(debugString: String, access: Int, method: Method, generate: InstructionAdapter.() -> Unit) {
|
||||
val mv = v.newMethod(JvmDeclarationOrigin.NO_ORIGIN, access, method.getName(), method.getDescriptor(), null, null)
|
||||
|
||||
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
||||
val iv = InstructionAdapter(mv)
|
||||
iv.visitCode()
|
||||
iv.generate()
|
||||
iv.areturn(method.getReturnType())
|
||||
FunctionCodegen.endVisit(mv, debugString, element)
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateKotlinAnnotation() {
|
||||
writeKotlinSyntheticClassAnnotation(v, KotlinSyntheticClass.Kind.CALLABLE_REFERENCE_WRAPPER)
|
||||
}
|
||||
|
||||
public fun putInstanceOnStack(): StackValue =
|
||||
StackValue.operation(wrapperMethod.getReturnType()) { iv ->
|
||||
iv.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, wrapperMethod.getReturnType().getDescriptor())
|
||||
}
|
||||
}
|
||||
@@ -248,7 +248,7 @@ public abstract class StackValue {
|
||||
@NotNull
|
||||
public static Property property(
|
||||
@NotNull PropertyDescriptor descriptor,
|
||||
@NotNull Type backingFieldOwner,
|
||||
@Nullable Type backingFieldOwner,
|
||||
@NotNull Type type,
|
||||
boolean isStaticBackingField,
|
||||
@Nullable String fieldName,
|
||||
@@ -552,10 +552,6 @@ public abstract class StackValue {
|
||||
return field(FieldInfo.createForSingleton(classDescriptor, typeMapper));
|
||||
}
|
||||
|
||||
public static Field deprecatedCompanionObjectAccessor(ClassDescriptor classDescriptor, JetTypeMapper typeMapper) {
|
||||
return field(FieldInfo.deprecatedFieldForCompanionObject(classDescriptor, typeMapper));
|
||||
}
|
||||
|
||||
public static StackValue operation(Type type, Function1<InstructionAdapter, Unit> lambda) {
|
||||
return new OperationStackValue(type, lambda);
|
||||
}
|
||||
@@ -993,7 +989,7 @@ public abstract class StackValue {
|
||||
private final String fieldName;
|
||||
|
||||
public Property(
|
||||
@NotNull PropertyDescriptor descriptor, @NotNull Type backingFieldOwner,
|
||||
@NotNull PropertyDescriptor descriptor, @Nullable Type backingFieldOwner,
|
||||
@Nullable CallableMethod getter, @Nullable CallableMethod setter, boolean isStaticBackingField,
|
||||
@Nullable String fieldName, @NotNull Type type, @NotNull GenerationState state,
|
||||
@NotNull StackValue receiver
|
||||
@@ -1011,6 +1007,7 @@ public abstract class StackValue {
|
||||
public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
|
||||
if (getter == null) {
|
||||
assert fieldName != null : "Property should have either a getter or a field name: " + descriptor;
|
||||
assert backingFieldOwner != null : "Property should have either a getter or a backingFieldOwner: " + descriptor;
|
||||
v.visitFieldInsn(isStaticPut ? GETSTATIC : GETFIELD, backingFieldOwner.getInternalName(), fieldName, this.type.getDescriptor());
|
||||
genNotNullAssertionForField(v, state, descriptor);
|
||||
coerceTo(type, v);
|
||||
@@ -1026,6 +1023,7 @@ public abstract class StackValue {
|
||||
coerceFrom(topOfStackType, v);
|
||||
if (setter == null) {
|
||||
assert fieldName != null : "Property should have either a setter or a field name: " + descriptor;
|
||||
assert backingFieldOwner != null : "Property should have either a setter or a backingFieldOwner: " + descriptor;
|
||||
v.visitFieldInsn(isStaticStore ? PUTSTATIC : PUTFIELD, backingFieldOwner.getInternalName(), fieldName, this.type.getDescriptor());
|
||||
}
|
||||
else {
|
||||
|
||||
+32
-18
@@ -45,7 +45,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||
import org.jetbrains.kotlin.resolve.constants.EnumValue;
|
||||
import org.jetbrains.kotlin.resolve.constants.NullValue;
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope;
|
||||
@@ -84,15 +84,15 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ClassDescriptor recordClassForFunction(
|
||||
private ClassDescriptor recordClassForCallable(
|
||||
@NotNull JetElement element,
|
||||
@NotNull FunctionDescriptor funDescriptor,
|
||||
@NotNull CallableDescriptor callableDescriptor,
|
||||
@NotNull Collection<JetType> supertypes,
|
||||
@NotNull String name
|
||||
) {
|
||||
String simpleName = name.substring(name.lastIndexOf('/') + 1);
|
||||
ClassDescriptorImpl classDescriptor = new ClassDescriptorImpl(
|
||||
correctContainerForLambda(funDescriptor, element),
|
||||
correctContainerForLambda(callableDescriptor, element),
|
||||
Name.special("<closure-" + simpleName + ">"),
|
||||
Modality.FINAL,
|
||||
supertypes,
|
||||
@@ -100,13 +100,13 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
);
|
||||
classDescriptor.initialize(JetScope.Empty.INSTANCE$, Collections.<ConstructorDescriptor>emptySet(), null);
|
||||
|
||||
bindingTrace.record(CLASS_FOR_FUNCTION, funDescriptor, classDescriptor);
|
||||
bindingTrace.record(CLASS_FOR_CALLABLE, callableDescriptor, classDescriptor);
|
||||
return classDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private DeclarationDescriptor correctContainerForLambda(@NotNull FunctionDescriptor descriptor, @NotNull JetElement function) {
|
||||
private DeclarationDescriptor correctContainerForLambda(@NotNull CallableDescriptor descriptor, @NotNull JetElement function) {
|
||||
DeclarationDescriptor container = descriptor.getContainingDeclaration();
|
||||
|
||||
// In almost all cases the function's direct container is the correct container to consider in JVM back-end
|
||||
@@ -286,7 +286,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
|
||||
String name = inventAnonymousClassName(expression);
|
||||
Collection<JetType> supertypes = runtimeTypes.getSupertypesForClosure(functionDescriptor);
|
||||
ClassDescriptor classDescriptor = recordClassForFunction(functionLiteral, functionDescriptor, supertypes, name);
|
||||
ClassDescriptor classDescriptor = recordClassForCallable(functionLiteral, functionDescriptor, supertypes, name);
|
||||
recordClosure(classDescriptor, name);
|
||||
|
||||
classStack.push(classDescriptor);
|
||||
@@ -298,17 +298,31 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
|
||||
@Override
|
||||
public void visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression) {
|
||||
FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
|
||||
// working around a problem with shallow analysis
|
||||
if (functionDescriptor == null) return;
|
||||
|
||||
ResolvedCall<?> referencedFunction = CallUtilPackage.getResolvedCall(expression.getCallableReference(), bindingContext);
|
||||
if (referencedFunction == null) return;
|
||||
Collection<JetType> supertypes =
|
||||
runtimeTypes.getSupertypesForFunctionReference((FunctionDescriptor) referencedFunction.getResultingDescriptor());
|
||||
CallableDescriptor target = referencedFunction.getResultingDescriptor();
|
||||
|
||||
CallableDescriptor callableDescriptor;
|
||||
Collection<JetType> supertypes;
|
||||
|
||||
if (target instanceof FunctionDescriptor) {
|
||||
callableDescriptor = bindingContext.get(FUNCTION, expression);
|
||||
if (callableDescriptor == null) return;
|
||||
|
||||
supertypes = runtimeTypes.getSupertypesForFunctionReference((FunctionDescriptor) target);
|
||||
}
|
||||
else if (target instanceof PropertyDescriptor) {
|
||||
callableDescriptor = bindingContext.get(VARIABLE, expression);
|
||||
if (callableDescriptor == null) return;
|
||||
|
||||
supertypes = Collections.singleton(runtimeTypes.getSupertypeForPropertyReference((PropertyDescriptor) target));
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
String name = inventAnonymousClassName(expression);
|
||||
ClassDescriptor classDescriptor = recordClassForFunction(expression, functionDescriptor, supertypes, name);
|
||||
ClassDescriptor classDescriptor = recordClassForCallable(expression, callableDescriptor, supertypes, name);
|
||||
recordClosure(classDescriptor, name);
|
||||
|
||||
classStack.push(classDescriptor);
|
||||
@@ -354,7 +368,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
else {
|
||||
String name = inventAnonymousClassName(function);
|
||||
Collection<JetType> supertypes = runtimeTypes.getSupertypesForClosure(functionDescriptor);
|
||||
ClassDescriptor classDescriptor = recordClassForFunction(function, functionDescriptor, supertypes, name);
|
||||
ClassDescriptor classDescriptor = recordClassForCallable(function, functionDescriptor, supertypes, name);
|
||||
recordClosure(classDescriptor, name);
|
||||
|
||||
classStack.push(classDescriptor);
|
||||
@@ -523,7 +537,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
|
||||
WhenByEnumsMapping mapping = new WhenByEnumsMapping(classDescriptor, currentClassName, fieldNumber);
|
||||
|
||||
for (CompileTimeConstant constant : SwitchCodegenUtil.getAllConstants(expression, bindingContext)) {
|
||||
for (ConstantValue<?> constant : SwitchCodegenUtil.getAllConstants(expression, bindingContext)) {
|
||||
if (constant instanceof NullValue) continue;
|
||||
|
||||
assert constant instanceof EnumValue : "expression in when should be EnumValue";
|
||||
@@ -540,9 +554,9 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
SwitchCodegenUtil.checkAllItemsAreConstantsSatisfying(
|
||||
expression,
|
||||
bindingContext,
|
||||
new Function1<CompileTimeConstant, Boolean>() {
|
||||
new Function1<ConstantValue<?>, Boolean>() {
|
||||
@Override
|
||||
public Boolean invoke(@NotNull CompileTimeConstant constant) {
|
||||
public Boolean invoke(@NotNull ConstantValue<?> constant) {
|
||||
return constant instanceof EnumValue || constant instanceof NullValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.codegen.binding;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.codegen.JvmCodegenUtil;
|
||||
import org.jetbrains.kotlin.codegen.SamType;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
@@ -32,6 +31,7 @@ import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage;
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope;
|
||||
import org.jetbrains.kotlin.util.slicedMap.BasicWritableSlice;
|
||||
import org.jetbrains.kotlin.util.slicedMap.Slices;
|
||||
@@ -40,16 +40,14 @@ import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isInterface;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.*;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
|
||||
import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getResolvedCall;
|
||||
import static org.jetbrains.kotlin.resolve.source.SourcePackage.toSourceElement;
|
||||
|
||||
public class CodegenBinding {
|
||||
public static final WritableSlice<ClassDescriptor, MutableClosure> CLOSURE = Slices.createSimpleSlice();
|
||||
|
||||
public static final WritableSlice<FunctionDescriptor, ClassDescriptor> CLASS_FOR_FUNCTION = Slices.createSimpleSlice();
|
||||
public static final WritableSlice<CallableDescriptor, ClassDescriptor> CLASS_FOR_CALLABLE = Slices.createSimpleSlice();
|
||||
|
||||
public static final WritableSlice<ScriptDescriptor, ClassDescriptor> CLASS_FOR_SCRIPT = Slices.createSimpleSlice();
|
||||
|
||||
@@ -110,34 +108,41 @@ public class CodegenBinding {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ClassDescriptor anonymousClassForFunction(
|
||||
public static ClassDescriptor anonymousClassForCallable(
|
||||
@NotNull BindingContext bindingContext,
|
||||
@NotNull FunctionDescriptor descriptor
|
||||
@NotNull CallableDescriptor descriptor
|
||||
) {
|
||||
//noinspection ConstantConditions
|
||||
return bindingContext.get(CLASS_FOR_FUNCTION, descriptor);
|
||||
return bindingContext.get(CLASS_FOR_CALLABLE, descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull JetElement expression) {
|
||||
if (expression instanceof JetObjectLiteralExpression) {
|
||||
JetObjectLiteralExpression jetObjectLiteralExpression = (JetObjectLiteralExpression) expression;
|
||||
expression = jetObjectLiteralExpression.getObjectDeclaration();
|
||||
expression = ((JetObjectLiteralExpression) expression).getObjectDeclaration();
|
||||
}
|
||||
|
||||
ClassDescriptor descriptor = bindingContext.get(CLASS, expression);
|
||||
if (descriptor == null) {
|
||||
SimpleFunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
|
||||
assert functionDescriptor != null : "Couldn't find function descriptor for " + PsiUtilPackage.getElementTextWithContext(expression);
|
||||
if (descriptor != null) {
|
||||
return getAsmType(bindingContext, descriptor);
|
||||
}
|
||||
|
||||
SimpleFunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
|
||||
if (functionDescriptor != null) {
|
||||
return asmTypeForAnonymousClass(bindingContext, functionDescriptor);
|
||||
}
|
||||
|
||||
return getAsmType(bindingContext, descriptor);
|
||||
VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression);
|
||||
if (variableDescriptor != null) {
|
||||
return asmTypeForAnonymousClass(bindingContext, variableDescriptor);
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Couldn't compute ASM type for " + PsiUtilPackage.getElementTextWithContext(expression));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull FunctionDescriptor descriptor) {
|
||||
return getAsmType(bindingContext, anonymousClassForFunction(bindingContext, descriptor));
|
||||
public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull CallableDescriptor descriptor) {
|
||||
return getAsmType(bindingContext, anonymousClassForCallable(bindingContext, descriptor));
|
||||
}
|
||||
|
||||
public static boolean canHaveOuter(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor classDescriptor) {
|
||||
@@ -202,7 +207,8 @@ public class CodegenBinding {
|
||||
String simpleName = asmType.getInternalName().substring(asmType.getInternalName().lastIndexOf('/') + 1);
|
||||
ClassDescriptorImpl classDescriptor =
|
||||
new ClassDescriptorImpl(descriptor, Name.special("<script-" + simpleName + ">"), Modality.FINAL,
|
||||
Collections.singleton(KotlinBuiltIns.getInstance().getAnyType()), toSourceElement(script));
|
||||
Collections.singleton(DescriptorUtilPackage.getBuiltIns(descriptor).getAnyType()),
|
||||
toSourceElement(script));
|
||||
classDescriptor.initialize(JetScope.Empty.INSTANCE$, Collections.<ConstructorDescriptor>emptySet(), null);
|
||||
|
||||
recordClosure(trace, classDescriptor, null, asmType);
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.codegen.OwnerKind;
|
||||
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.anonymousClassForFunction;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.anonymousClassForCallable;
|
||||
|
||||
public class ClosureContext extends ClassContext {
|
||||
private final FunctionDescriptor functionDescriptor;
|
||||
@@ -33,7 +33,7 @@ public class ClosureContext extends ClassContext {
|
||||
@Nullable CodegenContext parentContext,
|
||||
@NotNull LocalLookup localLookup
|
||||
) {
|
||||
super(typeMapper, anonymousClassForFunction(typeMapper.getBindingContext(), functionDescriptor),
|
||||
super(typeMapper, anonymousClassForCallable(typeMapper.getBindingContext(), functionDescriptor),
|
||||
OwnerKind.IMPLEMENTATION, parentContext, localLookup);
|
||||
|
||||
this.functionDescriptor = functionDescriptor;
|
||||
|
||||
@@ -103,7 +103,7 @@ public interface LocalLookup {
|
||||
BindingContext bindingContext = state.getBindingContext();
|
||||
Type localType = asmTypeForAnonymousClass(bindingContext, vd);
|
||||
|
||||
MutableClosure localFunClosure = bindingContext.get(CLOSURE, bindingContext.get(CLASS_FOR_FUNCTION, vd));
|
||||
MutableClosure localFunClosure = bindingContext.get(CLOSURE, bindingContext.get(CLASS_FOR_CALLABLE, vd));
|
||||
if (localFunClosure != null && JvmCodegenUtil.isConst(localFunClosure)) {
|
||||
// This is an optimization: we can obtain an instance of a const closure simply by GETSTATIC ...$instance
|
||||
// (instead of passing this instance to the constructor and storing as a field)
|
||||
|
||||
@@ -61,4 +61,9 @@ public class ScriptContext extends FieldOwnerContext<ClassDescriptor> {
|
||||
}
|
||||
return "script$" + (index + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Script: " + getContextDescriptor().getName().asString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ public class InlineCodegenUtil {
|
||||
return type.getInternalName();
|
||||
} else if (currentDescriptor instanceof FunctionDescriptor) {
|
||||
ClassDescriptor descriptor =
|
||||
typeMapper.getBindingContext().get(CodegenBinding.CLASS_FOR_FUNCTION, (FunctionDescriptor) currentDescriptor);
|
||||
typeMapper.getBindingContext().get(CodegenBinding.CLASS_FOR_CALLABLE, (FunctionDescriptor) currentDescriptor);
|
||||
if (descriptor != null) {
|
||||
Type type = typeMapper.mapType(descriptor);
|
||||
return type.getInternalName();
|
||||
@@ -471,6 +471,32 @@ public class InlineCodegenUtil {
|
||||
"()V", false);
|
||||
}
|
||||
|
||||
public static boolean isInlineMarker(AbstractInsnNode insn) {
|
||||
return isInlineMarker(insn, null);
|
||||
}
|
||||
|
||||
public static boolean isInlineMarker(AbstractInsnNode insn, String name) {
|
||||
if (insn instanceof MethodInsnNode) {
|
||||
MethodInsnNode methodInsnNode = (MethodInsnNode) insn;
|
||||
return insn.getOpcode() == Opcodes.INVOKESTATIC &&
|
||||
methodInsnNode.owner.equals(INLINE_MARKER_CLASS_NAME) &&
|
||||
(name != null ? methodInsnNode.name.equals(name)
|
||||
: methodInsnNode.name.equals(INLINE_MARKER_BEFORE_METHOD_NAME) ||
|
||||
methodInsnNode.name.equals(INLINE_MARKER_AFTER_METHOD_NAME));
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isBeforeInlineMarker(AbstractInsnNode insn) {
|
||||
return isInlineMarker(insn, INLINE_MARKER_BEFORE_METHOD_NAME);
|
||||
}
|
||||
|
||||
public static boolean isAfterInlineMarker(AbstractInsnNode insn) {
|
||||
return isInlineMarker(insn, INLINE_MARKER_AFTER_METHOD_NAME);
|
||||
}
|
||||
|
||||
public static int getLoadStoreArgSize(int opcode) {
|
||||
return opcode == Opcodes.DSTORE || opcode == Opcodes.LSTORE || opcode == Opcodes.DLOAD || opcode == Opcodes.LLOAD ? 2 : 1;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner {
|
||||
functionDescriptor = bindingContext.get(BindingContext.FUNCTION, expression);
|
||||
assert functionDescriptor != null : "Function is not resolved to descriptor: " + expression.getText();
|
||||
|
||||
classDescriptor = anonymousClassForFunction(bindingContext, functionDescriptor);
|
||||
classDescriptor = anonymousClassForCallable(bindingContext, functionDescriptor);
|
||||
closureClassType = asmTypeForAnonymousClass(bindingContext, functionDescriptor);
|
||||
|
||||
closure = bindingContext.get(CLOSURE, classDescriptor);
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.codegen.ClosureCodegen;
|
||||
import org.jetbrains.kotlin.codegen.StackValue;
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods;
|
||||
import org.jetbrains.kotlin.codegen.optimization.MandatoryMethodTransformer;
|
||||
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass;
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache;
|
||||
@@ -373,6 +374,8 @@ public class MethodInliner {
|
||||
protected MethodNode markPlacesForInlineAndRemoveInlinable(@NotNull MethodNode node, int finallyDeepShift) {
|
||||
node = prepareNode(node, finallyDeepShift);
|
||||
|
||||
MandatoryMethodTransformer.INSTANCE$.transform("fake", node);
|
||||
|
||||
Analyzer<SourceValue> analyzer = new Analyzer<SourceValue>(new SourceInterpreter()) {
|
||||
@NotNull
|
||||
@Override
|
||||
|
||||
@@ -284,7 +284,7 @@ class RawFileMapping(val name: String, val path: String) {
|
||||
if (rangeMappings.isNotEmpty() && isLastMapped && couldFoldInRange(lastMappedWithNewIndex, source)) {
|
||||
rangeMapping = rangeMappings.last()
|
||||
rangeMapping.range += source - lastMappedWithNewIndex
|
||||
dest = lineMappings[lastMappedWithNewIndex] + source - lastMappedWithNewIndex
|
||||
dest = lineMappings[lastMappedWithNewIndex]!! + source - lastMappedWithNewIndex
|
||||
}
|
||||
else {
|
||||
dest = currentIndex + 1
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen.intrinsics
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil.numberFunctionOperandType
|
||||
import org.jetbrains.kotlin.codegen.Callable
|
||||
import org.jetbrains.kotlin.codegen.CallableMethod
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ISHL
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ISHR
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.IUSHR
|
||||
@@ -34,8 +35,11 @@ public class BinaryOp(private val opcode: Int) : IntrinsicMethod() {
|
||||
val operandType = numberFunctionOperandType(returnType)
|
||||
val paramType = if (shift()) Type.INT_TYPE else operandType
|
||||
|
||||
return createBinaryIntrinsicCallable(operandType, paramType, operandType) {
|
||||
v -> v.visitInsn(returnType.getOpcode(opcode))
|
||||
return createBinaryIntrinsicCallable(returnType, paramType, operandType) {
|
||||
v ->
|
||||
v.visitInsn(returnType.getOpcode(opcode));
|
||||
if (operandType != returnType)
|
||||
StackValue.coerce(operandType, returnType, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-156
@@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.MethodAnalyzer
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsnOpcode
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.parseOrNull
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.*
|
||||
import java.util.*
|
||||
import kotlin.properties.Delegates
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class FixStackBeforeJumpTransformer : MethodTransformer() {
|
||||
public override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
val jumpsToFix = linkedSetOf<JumpInsnNode>()
|
||||
val fakesToGotos = arrayListOf<AbstractInsnNode>()
|
||||
val fakesToRemove = arrayListOf<AbstractInsnNode>()
|
||||
|
||||
methodNode.instructions.forEach { insnNode ->
|
||||
when {
|
||||
PseudoInsnOpcode.FIX_STACK_BEFORE_JUMP.isa(insnNode) -> {
|
||||
val next = insnNode.getNext()
|
||||
assert(next.getOpcode() == Opcodes.GOTO,
|
||||
"Instruction after ${PseudoInsnOpcode.FIX_STACK_BEFORE_JUMP} should be GOTO")
|
||||
jumpsToFix.add(next as JumpInsnNode)
|
||||
}
|
||||
PseudoInsnOpcode.FAKE_ALWAYS_TRUE_IFEQ.isa(insnNode) -> {
|
||||
assert(insnNode.getNext().getOpcode() == Opcodes.IFEQ,
|
||||
"Instruction after ${PseudoInsnOpcode.FAKE_ALWAYS_TRUE_IFEQ} should be IFEQ")
|
||||
fakesToGotos.add(insnNode)
|
||||
}
|
||||
PseudoInsnOpcode.FAKE_ALWAYS_FALSE_IFEQ.isa(insnNode) -> {
|
||||
assert(insnNode.getNext().getOpcode() == Opcodes.IFEQ,
|
||||
"Instruction after ${PseudoInsnOpcode.FAKE_ALWAYS_FALSE_IFEQ} should be IFEQ")
|
||||
fakesToRemove.add(insnNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (jumpsToFix.isEmpty() && fakesToGotos.isEmpty() && fakesToRemove.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
if (jumpsToFix.isNotEmpty()) {
|
||||
val analyzer = StackDepthAnalyzer(internalClassName, methodNode, jumpsToFix)
|
||||
val frames = analyzer.analyze()
|
||||
|
||||
val actions = arrayListOf<() -> Unit>()
|
||||
|
||||
for (jumpNode in jumpsToFix) {
|
||||
val jumpIndex = methodNode.instructions.indexOf(jumpNode)
|
||||
val labelIndex = methodNode.instructions.indexOf(jumpNode.label)
|
||||
|
||||
val DEAD_CODE = -1 // Stack size is always non-negative for live code
|
||||
val actualStackSize = frames[jumpIndex]?.getStackSize() ?: DEAD_CODE
|
||||
val expectedStackSize = frames[labelIndex]?.getStackSize() ?: DEAD_CODE
|
||||
|
||||
if (actualStackSize != DEAD_CODE && expectedStackSize != DEAD_CODE) {
|
||||
assert(expectedStackSize <= actualStackSize,
|
||||
"Label at $labelIndex, jump at $jumpIndex: stack underflow: $expectedStackSize > $actualStackSize")
|
||||
val frame = frames[jumpIndex]!!
|
||||
actions.add({ replaceMarkerWithPops(methodNode, jumpNode.getPrevious(), expectedStackSize, frame) })
|
||||
}
|
||||
else if (actualStackSize != DEAD_CODE && expectedStackSize == DEAD_CODE) {
|
||||
throw AssertionError("Live jump $jumpIndex to dead label $labelIndex")
|
||||
}
|
||||
else {
|
||||
val marker = jumpNode.getPrevious()
|
||||
actions.add({ methodNode.instructions.remove(marker) })
|
||||
}
|
||||
}
|
||||
|
||||
actions.forEach { it() }
|
||||
}
|
||||
|
||||
for (marker in fakesToGotos) {
|
||||
replaceAlwaysTrueIfeqWithGoto(methodNode, marker)
|
||||
}
|
||||
|
||||
for (marker in fakesToRemove) {
|
||||
removeAlwaysFalseIfeq(methodNode, marker)
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeAlwaysFalseIfeq(methodNode: MethodNode, nodeToReplace: AbstractInsnNode) {
|
||||
with (methodNode.instructions) {
|
||||
remove(nodeToReplace.getNext())
|
||||
remove(nodeToReplace)
|
||||
}
|
||||
}
|
||||
|
||||
private fun replaceAlwaysTrueIfeqWithGoto(methodNode: MethodNode, nodeToReplace: AbstractInsnNode) {
|
||||
with (methodNode.instructions) {
|
||||
val next = nodeToReplace.getNext() as JumpInsnNode
|
||||
insertBefore(nodeToReplace, JumpInsnNode(Opcodes.GOTO, next.label))
|
||||
remove(nodeToReplace)
|
||||
remove(next)
|
||||
}
|
||||
}
|
||||
|
||||
private fun replaceMarkerWithPops(methodNode: MethodNode, nodeToReplace: AbstractInsnNode, expectedStackSize: Int, frame: Frame<BasicValue>) {
|
||||
with (methodNode.instructions) {
|
||||
while (frame.getStackSize() > expectedStackSize) {
|
||||
val top = frame.pop()
|
||||
insertBefore(nodeToReplace, getPopInstruction(top))
|
||||
}
|
||||
remove(nodeToReplace)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPopInstruction(top: BasicValue) =
|
||||
InsnNode(when (top.getSize()) {
|
||||
1 -> Opcodes.POP
|
||||
2 -> Opcodes.POP2
|
||||
else -> throw AssertionError("Unexpected value type size")
|
||||
})
|
||||
|
||||
private class StackDepthAnalyzer(
|
||||
owner: String,
|
||||
methodNode: MethodNode,
|
||||
val markedJumps: Set<JumpInsnNode>
|
||||
) : MethodAnalyzer<BasicValue>(owner, methodNode, OptimizationBasicInterpreter()) {
|
||||
protected override fun visitControlFlowEdge(insn: Int, successor: Int): Boolean {
|
||||
val insnNode = instructions[insn]
|
||||
return !(insnNode is JumpInsnNode && markedJumps.contains(insnNode))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private inline fun InsnList.forEach(block: (AbstractInsnNode) -> Unit) {
|
||||
val iter = this.iterator()
|
||||
while (iter.hasNext()) {
|
||||
val insn = iter.next()
|
||||
block(insn)
|
||||
}
|
||||
}
|
||||
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
|
||||
public object LabelNormalizationMethodTransformer : MethodTransformer() {
|
||||
val newLabelNodes = hashMapOf<LabelNode, LabelNode>()
|
||||
val removedLabelNodes = hashSetOf<LabelNode>()
|
||||
|
||||
public override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
newLabelNodes.clear()
|
||||
removedLabelNodes.clear()
|
||||
|
||||
with(methodNode.instructions) {
|
||||
insertBefore(getFirst(), LabelNode(Label()))
|
||||
insert(getLast(), LabelNode(Label()))
|
||||
}
|
||||
|
||||
rewriteLabelInsns(methodNode)
|
||||
if (removedLabelNodes.isEmpty()) return
|
||||
|
||||
rewriteInsns(methodNode)
|
||||
rewriteTryCatchBlocks(methodNode)
|
||||
rewriteLocalVars(methodNode)
|
||||
}
|
||||
|
||||
private fun rewriteLabelInsns(methodNode: MethodNode) {
|
||||
var prevLabelNode: LabelNode? = null
|
||||
var thisNode = methodNode.instructions.getFirst()
|
||||
while (thisNode != null) {
|
||||
if (thisNode is LabelNode) {
|
||||
if (prevLabelNode != null) {
|
||||
newLabelNodes[thisNode] = prevLabelNode
|
||||
removedLabelNodes.add(thisNode)
|
||||
thisNode = methodNode.instructions.removeNodeGetNext(thisNode)
|
||||
}
|
||||
else {
|
||||
prevLabelNode = thisNode
|
||||
newLabelNodes[thisNode] = thisNode
|
||||
thisNode = thisNode.getNext()
|
||||
}
|
||||
}
|
||||
else {
|
||||
prevLabelNode = null
|
||||
thisNode = thisNode.getNext()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun rewriteInsns(methodNode: MethodNode) {
|
||||
var thisNode = methodNode.instructions.getFirst()
|
||||
while (thisNode != null) {
|
||||
thisNode = when (thisNode) {
|
||||
is JumpInsnNode ->
|
||||
rewriteJumpInsn(methodNode, thisNode)
|
||||
is LineNumberNode ->
|
||||
rewriteLineNumberNode(methodNode, thisNode)
|
||||
is LookupSwitchInsnNode ->
|
||||
rewriteLookupSwitchInsn(methodNode, thisNode)
|
||||
is TableSwitchInsnNode ->
|
||||
rewriteTableSwitchInsn(methodNode, thisNode)
|
||||
is FrameNode ->
|
||||
rewriteFrameNode(methodNode, thisNode)
|
||||
else ->
|
||||
thisNode.getNext()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun rewriteLineNumberNode(methodNode: MethodNode, oldLineNode: LineNumberNode): AbstractInsnNode? {
|
||||
if (isRemoved(oldLineNode.start)) {
|
||||
val newLineNode = oldLineNode.clone(newLabelNodes)
|
||||
return methodNode.instructions.replaceNodeGetNext(oldLineNode, newLineNode)
|
||||
}
|
||||
else {
|
||||
return oldLineNode.getNext()
|
||||
}
|
||||
}
|
||||
|
||||
private fun rewriteJumpInsn(methodNode: MethodNode, oldJumpNode: JumpInsnNode): AbstractInsnNode? {
|
||||
if (isRemoved(oldJumpNode.label)) {
|
||||
val newJumpNode = oldJumpNode.clone(newLabelNodes)
|
||||
return methodNode.instructions.replaceNodeGetNext(oldJumpNode, newJumpNode)
|
||||
}
|
||||
else {
|
||||
return oldJumpNode.getNext()
|
||||
}
|
||||
}
|
||||
|
||||
private fun rewriteLookupSwitchInsn(methodNode: MethodNode, oldSwitchNode: LookupSwitchInsnNode): AbstractInsnNode? =
|
||||
methodNode.instructions.replaceNodeGetNext(oldSwitchNode, oldSwitchNode.clone(newLabelNodes))
|
||||
|
||||
private fun rewriteTableSwitchInsn(methodNode: MethodNode, oldSwitchNode: TableSwitchInsnNode): AbstractInsnNode? =
|
||||
methodNode.instructions.replaceNodeGetNext(oldSwitchNode, oldSwitchNode.clone(newLabelNodes))
|
||||
|
||||
private fun rewriteFrameNode(methodNode: MethodNode, oldFrameNode: FrameNode): AbstractInsnNode? =
|
||||
methodNode.instructions.replaceNodeGetNext(oldFrameNode, oldFrameNode.clone(newLabelNodes))
|
||||
|
||||
private fun rewriteTryCatchBlocks(methodNode: MethodNode) {
|
||||
methodNode.tryCatchBlocks = methodNode.tryCatchBlocks.map { oldTcb ->
|
||||
if (isRemoved(oldTcb.start) || isRemoved(oldTcb.end) || isRemoved(oldTcb.handler)) {
|
||||
val newTcb = TryCatchBlockNode(getNew(oldTcb.start), getNew(oldTcb.end), getNew(oldTcb.handler), oldTcb.type)
|
||||
newTcb.visibleTypeAnnotations = oldTcb.visibleTypeAnnotations
|
||||
newTcb.invisibleTypeAnnotations = oldTcb.invisibleTypeAnnotations
|
||||
newTcb
|
||||
}
|
||||
else {
|
||||
oldTcb
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun rewriteLocalVars(methodNode: MethodNode) {
|
||||
methodNode.localVariables = methodNode.localVariables.map { oldVar ->
|
||||
if (isRemoved(oldVar.start) || isRemoved(oldVar.end)) {
|
||||
LocalVariableNode(oldVar.name, oldVar.desc, oldVar.signature, getNew(oldVar.start), getNew(oldVar.end), oldVar.index)
|
||||
}
|
||||
else {
|
||||
oldVar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isRemoved(labelNode: LabelNode): Boolean = removedLabelNodes.contains(labelNode)
|
||||
private fun getNew(oldLabelNode: LabelNode): LabelNode = newLabelNodes[oldLabelNode]!!
|
||||
}
|
||||
|
||||
private fun InsnList.replaceNodeGetNext(oldNode: AbstractInsnNode, newNode: AbstractInsnNode): AbstractInsnNode? {
|
||||
insertBefore(oldNode, newNode)
|
||||
remove(oldNode)
|
||||
return newNode.getNext()
|
||||
}
|
||||
|
||||
private fun InsnList.removeNodeGetNext(oldNode: AbstractInsnNode): AbstractInsnNode? {
|
||||
val next = oldNode.getNext()
|
||||
remove(oldNode)
|
||||
return next
|
||||
}
|
||||
+10
-11
@@ -14,16 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.constants
|
||||
package org.jetbrains.kotlin.codegen.optimization
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransformer
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
|
||||
public class KClassValue(type: JetType) : CompileTimeConstant<JetType>(type, true, false, false) {
|
||||
override fun getType(kotlinBuiltIns: KotlinBuiltIns) = value
|
||||
override fun getValue(): JetType = value.getArguments().single().getType()
|
||||
|
||||
override fun <R, D> accept(visitor: AnnotationArgumentVisitor<R, D>, data: D) = visitor.visitKClassValue(this, data)
|
||||
}
|
||||
public object MandatoryMethodTransformer : MethodTransformer() {
|
||||
public override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
LabelNormalizationMethodTransformer.transform(internalClassName, methodNode)
|
||||
FixStackMethodTransformer.transform(internalClassName, methodNode)
|
||||
}
|
||||
}
|
||||
+3
-9
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantBoxingMethodTransformer;
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantNullCheckMethodTransformer;
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.CommonPackage;
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransformer;
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
@@ -36,16 +37,11 @@ import java.util.List;
|
||||
public class OptimizationMethodVisitor extends MethodVisitor {
|
||||
private static final int MEMORY_LIMIT_BY_METHOD_MB = 50;
|
||||
|
||||
private static final MethodTransformer[] MANDATORY_TRANSFORMERS = new MethodTransformer[] {
|
||||
new FixStackBeforeJumpTransformer()
|
||||
};
|
||||
|
||||
private static final MethodTransformer[] OPTIMIZATION_TRANSFORMERS = new MethodTransformer[] {
|
||||
new RedundantNullCheckMethodTransformer(),
|
||||
new RedundantBoxingMethodTransformer(),
|
||||
new DeadCodeEliminationMethodTransformer(),
|
||||
new RedundantGotoMethodTransformer(),
|
||||
new StoreStackBeforeInlineMethodTransformer()
|
||||
new RedundantGotoMethodTransformer()
|
||||
};
|
||||
|
||||
private final MethodNode methodNode;
|
||||
@@ -79,9 +75,7 @@ public class OptimizationMethodVisitor extends MethodVisitor {
|
||||
super.visitEnd();
|
||||
|
||||
if (shouldBeTransformed(methodNode)) {
|
||||
for (MethodTransformer transformer : MANDATORY_TRANSFORMERS) {
|
||||
transformer.transform("fake", methodNode);
|
||||
}
|
||||
MandatoryMethodTransformer.INSTANCE$.transform("fake", methodNode);
|
||||
if (canBeOptimized(methodNode) && !disableOptimization) {
|
||||
for (MethodTransformer transformer : OPTIMIZATION_TRANSFORMERS) {
|
||||
transformer.transform("fake", methodNode);
|
||||
|
||||
-220
@@ -1,220 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
import org.jetbrains.org.objectweb.asm.tree.VarInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import com.intellij.util.containers.Stack
|
||||
|
||||
class StoreStackBeforeInlineMethodTransformer : MethodTransformer() {
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
val frames = MethodTransformer.analyze(internalClassName, methodNode, OptimizationBasicInterpreter())
|
||||
if (needToProcess(methodNode, frames)) {
|
||||
process(methodNode, frames)
|
||||
}
|
||||
else {
|
||||
removeInlineMarkers(methodNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun needToProcess(node: MethodNode, frames: Array<Frame<BasicValue>?>): Boolean {
|
||||
val insns = node.instructions.toArray()
|
||||
var balance = 0
|
||||
var isThereAnyInlineMarker = false
|
||||
|
||||
for ((insn, frame) in insns.zip(frames)) {
|
||||
if (isInlineMarker(insn)) {
|
||||
isThereAnyInlineMarker = true
|
||||
|
||||
// inline marker is not available
|
||||
if (frame == null) return false
|
||||
}
|
||||
|
||||
if (isBeforeInlineMarker(insn)) {
|
||||
balance++
|
||||
}
|
||||
else if(isAfterInlineMarker(insn)) {
|
||||
balance--
|
||||
}
|
||||
|
||||
if (balance < 0) return false
|
||||
}
|
||||
|
||||
return balance == 0 && isThereAnyInlineMarker
|
||||
}
|
||||
|
||||
private fun isBeforeInlineMarker(insn: AbstractInsnNode) = isInlineMarker(insn, InlineCodegenUtil.INLINE_MARKER_BEFORE_METHOD_NAME)
|
||||
|
||||
private fun isAfterInlineMarker(insn: AbstractInsnNode) = isInlineMarker(insn, InlineCodegenUtil.INLINE_MARKER_AFTER_METHOD_NAME)
|
||||
|
||||
private fun isInlineMarker(insn: AbstractInsnNode, markerName: String? = null): Boolean {
|
||||
return insn.getOpcode() == Opcodes.INVOKESTATIC &&
|
||||
insn is MethodInsnNode &&
|
||||
insn.owner == InlineCodegenUtil.INLINE_MARKER_CLASS_NAME &&
|
||||
if (markerName != null) markerName == insn.name else (
|
||||
insn.name == InlineCodegenUtil.INLINE_MARKER_BEFORE_METHOD_NAME ||
|
||||
insn.name == InlineCodegenUtil.INLINE_MARKER_AFTER_METHOD_NAME
|
||||
)
|
||||
}
|
||||
|
||||
private fun process(methodNode: MethodNode, frames: Array<Frame<BasicValue>?>) {
|
||||
val insns = methodNode.instructions.toArray()
|
||||
|
||||
val storedValuesDescriptorsStack = Stack<StoredStackValuesDescriptor>()
|
||||
var firstAvailableVarIndex = methodNode.maxLocals
|
||||
var currentStoredValuesCount = 0
|
||||
|
||||
for ((insn, frame) in insns.zip(frames)) {
|
||||
if (isBeforeInlineMarker(insn)) {
|
||||
frame ?: throw AssertionError("process method shouldn't be called if frame is null before inline marker")
|
||||
|
||||
val desc = storeStackValues(methodNode, frame, insn, firstAvailableVarIndex, currentStoredValuesCount)
|
||||
|
||||
firstAvailableVarIndex += desc.storedStackSize
|
||||
currentStoredValuesCount += desc.storedValuesCount
|
||||
storedValuesDescriptorsStack.push(desc)
|
||||
}
|
||||
else if (isAfterInlineMarker(insn)) {
|
||||
frame ?: throw AssertionError("process method shouldn't be called if frame is null before inline marker")
|
||||
|
||||
val desc = storedValuesDescriptorsStack.pop() ?:
|
||||
throw AssertionError("should be non null becase markers are balanced")
|
||||
|
||||
loadStackValues(methodNode, frame, insn, desc)
|
||||
firstAvailableVarIndex -= desc.storedStackSize
|
||||
currentStoredValuesCount -= desc.storedValuesCount
|
||||
}
|
||||
|
||||
if (isInlineMarker(insn)) {
|
||||
methodNode.instructions.remove(insn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class StoredStackValuesDescriptor(
|
||||
val values: List<BasicValue>,
|
||||
val firstVariableIndex: Int,
|
||||
val storedStackSize: Int,
|
||||
alreadyStoredValuesCount: Int
|
||||
) {
|
||||
val nextFreeVarIndex : Int get() = firstVariableIndex + storedStackSize
|
||||
val storedValuesCount: Int get() = values.size()
|
||||
val isStored: Boolean get() = storedValuesCount > 0
|
||||
val totalValuesCountOnStackBeforeInline = alreadyStoredValuesCount + storedValuesCount
|
||||
}
|
||||
|
||||
private fun removeInlineMarkers(node: MethodNode) {
|
||||
for (insn in node.instructions.toArray()) {
|
||||
if (isInlineMarker(insn)) {
|
||||
node.instructions.remove(insn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun storeStackValues(
|
||||
node: MethodNode,
|
||||
frame: Frame<BasicValue>,
|
||||
beforeInlineMarker: AbstractInsnNode,
|
||||
firstAvailableVarIndex: Int,
|
||||
alreadyStoredValuesCount: Int
|
||||
) : StoredStackValuesDescriptor {
|
||||
var stackSize = 0
|
||||
|
||||
val values = frame.getStackValuesStartingFrom(alreadyStoredValuesCount)
|
||||
|
||||
for (value in values.reverse()) {
|
||||
node.instructions.insertBefore(
|
||||
beforeInlineMarker,
|
||||
VarInsnNode(
|
||||
value.getType()!!.getOpcode(Opcodes.ISTORE),
|
||||
firstAvailableVarIndex + stackSize
|
||||
)
|
||||
)
|
||||
stackSize += value.getSize()
|
||||
}
|
||||
|
||||
node.updateMaxLocals(firstAvailableVarIndex + stackSize)
|
||||
|
||||
return StoredStackValuesDescriptor(values, firstAvailableVarIndex, stackSize, alreadyStoredValuesCount)
|
||||
}
|
||||
|
||||
private fun loadStackValues(
|
||||
node: MethodNode,
|
||||
frame: Frame<BasicValue>,
|
||||
afterInlineMarker: AbstractInsnNode,
|
||||
desc: StoredStackValuesDescriptor
|
||||
) {
|
||||
if (!desc.isStored) return
|
||||
|
||||
val insns = node.instructions
|
||||
var returnValueVarIndex = -1
|
||||
var returnType : Type? = null
|
||||
|
||||
if (frame.getStackSize() != desc.totalValuesCountOnStackBeforeInline) {
|
||||
// only returned value
|
||||
assert(
|
||||
(frame.getStackSize() - desc.totalValuesCountOnStackBeforeInline) == 1,
|
||||
"Stack sizes should not differ by more than 1 (returned value)"
|
||||
)
|
||||
|
||||
returnValueVarIndex = desc.nextFreeVarIndex
|
||||
returnType = frame.getStack(frame.getStackSize() - 1)!!.getType()
|
||||
node.updateMaxLocals(returnValueVarIndex + returnType!!.getSize())
|
||||
|
||||
insns.insertBefore(
|
||||
afterInlineMarker,
|
||||
VarInsnNode(returnType!!.getOpcode(Opcodes.ISTORE), returnValueVarIndex)
|
||||
)
|
||||
}
|
||||
|
||||
var currentVarIndex = desc.firstVariableIndex + desc.storedStackSize
|
||||
|
||||
for (value in desc.values) {
|
||||
currentVarIndex -= value.getSize()
|
||||
insns.insertBefore(
|
||||
afterInlineMarker,
|
||||
VarInsnNode(
|
||||
value.getType()!!.getOpcode(Opcodes.ILOAD),
|
||||
currentVarIndex
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (returnValueVarIndex != -1) {
|
||||
insns.insertBefore(
|
||||
afterInlineMarker,
|
||||
VarInsnNode(returnType!!.getOpcode(Opcodes.ILOAD), returnValueVarIndex)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <V : BasicValue> Frame<V>.getStackValuesStartingFrom(from: Int): List<V> =
|
||||
IntRange(from, getStackSize() - 1).map { getStack(it) }.requireNoNulls()
|
||||
|
||||
private fun MethodNode.updateMaxLocals(newMaxLocals: Int) {
|
||||
maxLocals = Math.max(maxLocals, newMaxLocals)
|
||||
}
|
||||
+14
-8
@@ -44,7 +44,11 @@ public open class MethodAnalyzer<V : Value>(
|
||||
|
||||
protected open fun newFrame(nLocals: Int, nStack: Int): Frame<V> = Frame(nLocals, nStack)
|
||||
|
||||
protected open fun newFrame(src: Frame<out V>): Frame<V> = Frame(src)
|
||||
protected open fun newFrame(src: Frame<out V>): Frame<V> {
|
||||
val frame = newFrame(src.getLocals(), src.getMaxStackSize())
|
||||
frame.init(src)
|
||||
return frame
|
||||
}
|
||||
|
||||
protected open fun visitControlFlowEdge(insn: Int, successor: Int): Boolean = true
|
||||
|
||||
@@ -94,12 +98,12 @@ public open class MethodAnalyzer<V : Value>(
|
||||
}
|
||||
|
||||
handlers[insn]?.forEach { tcb ->
|
||||
val type = Type.getObjectType(tcb.type?:"java/lang/Throwable")
|
||||
val exnType = Type.getObjectType(tcb.type?:"java/lang/Throwable")
|
||||
val jump = instructions.indexOf(tcb.handler)
|
||||
if (visitControlFlowExceptionEdge(insn, tcb)) {
|
||||
handler.init(f)
|
||||
handler.clearStack()
|
||||
handler.push(interpreter.newValue(type))
|
||||
handler.push(interpreter.newValue(exnType))
|
||||
mergeControlFlowEdge(jump, handler)
|
||||
}
|
||||
}
|
||||
@@ -117,6 +121,9 @@ public open class MethodAnalyzer<V : Value>(
|
||||
return frames
|
||||
}
|
||||
|
||||
public fun getFrame(insn: AbstractInsnNode): Frame<V>? =
|
||||
frames[instructions.indexOf(insn)]
|
||||
|
||||
private fun checkAssertions() {
|
||||
if (instructions.toArray() any { it.getOpcode() == Opcodes.JSR || it.getOpcode() == Opcodes.RET })
|
||||
throw AssertionError("Subroutines are deprecated since Java 6")
|
||||
@@ -170,9 +177,9 @@ public open class MethodAnalyzer<V : Value>(
|
||||
val ctype = Type.getObjectType(owner)
|
||||
current.setLocal(local++, interpreter.newValue(ctype))
|
||||
}
|
||||
for (i in args.indices) {
|
||||
current.setLocal(local++, interpreter.newValue(args[i]))
|
||||
if (args[i].getSize() == 2) {
|
||||
for (arg in args) {
|
||||
current.setLocal(local++, interpreter.newValue(arg))
|
||||
if (arg.getSize() == 2) {
|
||||
current.setLocal(local++, interpreter.newValue(null))
|
||||
}
|
||||
}
|
||||
@@ -185,8 +192,7 @@ public open class MethodAnalyzer<V : Value>(
|
||||
}
|
||||
|
||||
private fun computeExceptionHandlersForEachInsn(m: MethodNode) {
|
||||
for (i in m.tryCatchBlocks.indices) {
|
||||
val tcb = m.tryCatchBlocks.get(i)
|
||||
for (tcb in m.tryCatchBlocks) {
|
||||
val begin = instructions.indexOf(tcb.start)
|
||||
val end = instructions.indexOf(tcb.end)
|
||||
for (j in begin..end - 1) {
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.jetbrains.kotlin.codegen.optimization.common
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.InsnList
|
||||
import org.jetbrains.org.objectweb.asm.tree.LabelNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
@@ -28,7 +30,9 @@ val AbstractInsnNode.isMeaningful : Boolean get() =
|
||||
else -> true
|
||||
}
|
||||
|
||||
class InsnSequence(val from: AbstractInsnNode, val to: AbstractInsnNode?) : Sequence<AbstractInsnNode> {
|
||||
public class InsnSequence(val from: AbstractInsnNode, val to: AbstractInsnNode?) : Sequence<AbstractInsnNode> {
|
||||
public constructor(insnList: InsnList) : this(insnList.getFirst(), null)
|
||||
|
||||
override fun iterator(): Iterator<AbstractInsnNode> {
|
||||
return object : Iterator<AbstractInsnNode> {
|
||||
var current: AbstractInsnNode? = from
|
||||
@@ -77,3 +81,22 @@ abstract class BasicValueWrapper(val wrappedValue: BasicValue?) : BasicValue(wra
|
||||
return super.equals(other) && this.javaClass == other?.javaClass
|
||||
}
|
||||
}
|
||||
|
||||
inline fun AbstractInsnNode.findNextOrNull(predicate: (AbstractInsnNode) -> Boolean): AbstractInsnNode? {
|
||||
var finger = this.getNext()
|
||||
while (finger != null && !predicate(finger)) {
|
||||
finger = finger.getNext()
|
||||
}
|
||||
return finger
|
||||
}
|
||||
|
||||
inline fun AbstractInsnNode.findPreviousOrNull(predicate: (AbstractInsnNode) -> Boolean): AbstractInsnNode? {
|
||||
var finger = this.getPrevious()
|
||||
while (finger != null && !predicate(finger)) {
|
||||
finger = finger.getPrevious()
|
||||
}
|
||||
return finger
|
||||
}
|
||||
|
||||
fun AbstractInsnNode.hasOpcode(): Boolean =
|
||||
getOpcode() >= 0
|
||||
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.fixStack
|
||||
|
||||
import com.sun.xml.internal.ws.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.findNextOrNull
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.hasOpcode
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import org.jetbrains.org.objectweb.asm.util.Printer
|
||||
|
||||
private class DecompiledTryDescriptor(val tryStartLabel: LabelNode) {
|
||||
var defaultHandlerTcb : TryCatchBlockNode? = null
|
||||
val handlerStartLabels = hashSetOf<LabelNode>()
|
||||
}
|
||||
|
||||
private fun TryCatchBlockNode.isDefaultHandlerNode(): Boolean =
|
||||
start == handler
|
||||
|
||||
private fun MethodNode.debugString(tcb: TryCatchBlockNode): String =
|
||||
"TCB<${instructions.indexOf(tcb.start)}, ${instructions.indexOf(tcb.end)}, ${instructions.indexOf(tcb.handler)}>"
|
||||
|
||||
internal fun insertTryCatchBlocksMarkers(methodNode: MethodNode) {
|
||||
if (methodNode.tryCatchBlocks.isEmpty()) return
|
||||
|
||||
val decompiledTryDescriptorForStart = linkedMapOf<LabelNode, DecompiledTryDescriptor>()
|
||||
val decompiledTryDescriptorForHandler = hashMapOf<LabelNode, DecompiledTryDescriptor>()
|
||||
|
||||
for (tcb in methodNode.tryCatchBlocks) {
|
||||
if (tcb.isDefaultHandlerNode()) {
|
||||
assert(decompiledTryDescriptorForHandler.containsKey(tcb.start),
|
||||
"${methodNode.debugString(tcb)}: default handler should occur after some regular handler")
|
||||
}
|
||||
|
||||
val decompiledTryDescriptor = decompiledTryDescriptorForHandler.getOrPut(tcb.handler) {
|
||||
decompiledTryDescriptorForStart.getOrPut(tcb.start) {
|
||||
DecompiledTryDescriptor(tcb.start)
|
||||
}
|
||||
}
|
||||
with(decompiledTryDescriptor) {
|
||||
handlerStartLabels.add(tcb.handler)
|
||||
|
||||
if (tcb.isDefaultHandlerNode()) {
|
||||
assert(defaultHandlerTcb == null) {
|
||||
"${methodNode.debugString(tcb)}: default handler is already found: ${methodNode.debugString(defaultHandlerTcb!!)}"
|
||||
}
|
||||
|
||||
defaultHandlerTcb = tcb
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val doneTryStartLabels = hashSetOf<LabelNode>()
|
||||
val doneHandlerLabels = hashSetOf<LabelNode>()
|
||||
|
||||
for (decompiledTryDescriptor in decompiledTryDescriptorForStart.values()) {
|
||||
with(decompiledTryDescriptor) {
|
||||
if (!doneTryStartLabels.contains(tryStartLabel)) {
|
||||
doneTryStartLabels.add(tryStartLabel)
|
||||
|
||||
val nopNode = tryStartLabel.findNextOrNull { it.hasOpcode() }!!
|
||||
assert(nopNode.getOpcode() == Opcodes.NOP,
|
||||
"${methodNode.instructions.indexOf(nopNode)}: try block should start with NOP")
|
||||
|
||||
methodNode.instructions.insertBefore(tryStartLabel, PseudoInsn.SAVE_STACK_BEFORE_TRY.createInsnNode())
|
||||
methodNode.instructions.insert(nopNode, PseudoInsn.RESTORE_STACK_IN_TRY_CATCH.createInsnNode())
|
||||
}
|
||||
|
||||
for (handlerStartLabel in handlerStartLabels) {
|
||||
if (!doneHandlerLabels.contains(handlerStartLabel)) {
|
||||
doneHandlerLabels.add(handlerStartLabel)
|
||||
|
||||
val storeNode = handlerStartLabel.findNextOrNull { it.hasOpcode() }!!
|
||||
assert(storeNode.getOpcode() == Opcodes.ASTORE,
|
||||
"${methodNode.instructions.indexOf(storeNode)}: handler should start with ASTORE")
|
||||
|
||||
methodNode.instructions.insert(storeNode, PseudoInsn.RESTORE_STACK_IN_TRY_CATCH.createInsnNode())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.fixStack
|
||||
|
||||
import com.intellij.util.SmartList
|
||||
import com.intellij.util.containers.Stack
|
||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.MethodAnalyzer
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.JumpInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.TryCatchBlockNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
|
||||
import java.util.*
|
||||
|
||||
public class FixStackAnalyzer(
|
||||
owner: String,
|
||||
methodNode: MethodNode,
|
||||
val context: FixStackContext
|
||||
) : MethodAnalyzer<BasicValue>(owner, methodNode, OptimizationBasicInterpreter()) {
|
||||
val savedStacks = hashMapOf<AbstractInsnNode, List<BasicValue>>()
|
||||
var maxExtraStackSize = 0; private set
|
||||
|
||||
protected override fun visitControlFlowEdge(insn: Int, successor: Int): Boolean {
|
||||
val insnNode = instructions[insn]
|
||||
return !(insnNode is JumpInsnNode && context.breakContinueGotoNodes.contains(insnNode))
|
||||
}
|
||||
|
||||
protected override fun newFrame(nLocals: Int, nStack: Int): Frame<BasicValue> =
|
||||
FixStackFrame(nLocals, nStack)
|
||||
|
||||
private fun indexOf(node: AbstractInsnNode) = method.instructions.indexOf(node)
|
||||
|
||||
public inner class FixStackFrame(nLocals: Int, nStack: Int) : Frame<BasicValue>(nLocals, nStack) {
|
||||
val extraStack = Stack<BasicValue>()
|
||||
|
||||
public override fun init(src: Frame<out BasicValue>): Frame<BasicValue> {
|
||||
extraStack.clear()
|
||||
extraStack.addAll((src as FixStackFrame).extraStack)
|
||||
return super.init(src)
|
||||
}
|
||||
|
||||
public override fun clearStack() {
|
||||
extraStack.clear()
|
||||
super.clearStack()
|
||||
}
|
||||
|
||||
public override fun execute(insn: AbstractInsnNode, interpreter: Interpreter<BasicValue>) {
|
||||
when {
|
||||
PseudoInsn.SAVE_STACK_BEFORE_TRY.isa(insn) ->
|
||||
executeSaveStackBeforeTry(insn)
|
||||
PseudoInsn.RESTORE_STACK_IN_TRY_CATCH.isa(insn) ->
|
||||
executeRestoreStackInTryCatch(insn)
|
||||
InlineCodegenUtil.isBeforeInlineMarker(insn) ->
|
||||
executeBeforeInlineCallMarker(insn)
|
||||
InlineCodegenUtil.isAfterInlineMarker(insn) ->
|
||||
executeAfterInlineCallMarker(insn)
|
||||
}
|
||||
|
||||
super.execute(insn, interpreter)
|
||||
}
|
||||
|
||||
public fun getStackContent(): List<BasicValue> {
|
||||
val savedStack = arrayListOf<BasicValue>()
|
||||
IntRange(0, super.getStackSize() - 1).mapTo(savedStack) { super.getStack(it) }
|
||||
savedStack.addAll(extraStack)
|
||||
return savedStack
|
||||
}
|
||||
|
||||
public override fun push(value: BasicValue) {
|
||||
if (super.getStackSize() < getMaxStackSize()) {
|
||||
super.push(value)
|
||||
}
|
||||
else {
|
||||
extraStack.add(value)
|
||||
maxExtraStackSize = Math.max(maxExtraStackSize, extraStack.size())
|
||||
}
|
||||
}
|
||||
|
||||
public fun pushAll(values: Collection<BasicValue>) {
|
||||
values.forEach { push(it) }
|
||||
}
|
||||
|
||||
public override fun pop(): BasicValue {
|
||||
if (extraStack.isNotEmpty()) {
|
||||
return extraStack.pop()
|
||||
}
|
||||
else {
|
||||
return super.pop()
|
||||
}
|
||||
}
|
||||
|
||||
public override fun getStack(i: Int): BasicValue {
|
||||
if (i < super.getMaxStackSize()) {
|
||||
return super.getStack(i)
|
||||
}
|
||||
else {
|
||||
return extraStack[i - getMaxStackSize()]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun FixStackFrame.executeBeforeInlineCallMarker(insn: AbstractInsnNode) {
|
||||
saveStackAndClear(insn)
|
||||
}
|
||||
|
||||
private fun FixStackFrame.saveStackAndClear(insn: AbstractInsnNode) {
|
||||
val savedValues = getStackContent()
|
||||
savedStacks[insn] = savedValues
|
||||
clearStack()
|
||||
}
|
||||
|
||||
private fun FixStackFrame.executeAfterInlineCallMarker(insn: AbstractInsnNode) {
|
||||
val beforeInlineMarker = context.openingInlineMethodMarker[insn]
|
||||
if (getStackSize() > 0) {
|
||||
val returnValue = pop()
|
||||
clearStack()
|
||||
val savedValues = savedStacks[beforeInlineMarker]
|
||||
pushAll(savedValues!!)
|
||||
push(returnValue)
|
||||
}
|
||||
else {
|
||||
val savedValues = savedStacks[beforeInlineMarker]
|
||||
pushAll(savedValues!!)
|
||||
}
|
||||
}
|
||||
|
||||
private fun FixStackFrame.executeRestoreStackInTryCatch(insn: AbstractInsnNode) {
|
||||
val saveNode = context.saveStackMarkerForRestoreMarker[insn]
|
||||
val savedValues = savedStacks.getOrElse(saveNode!!) {
|
||||
throw AssertionError("${indexOf(insn)}: Restore stack is unavailable for ${indexOf(saveNode)}")
|
||||
}
|
||||
pushAll(savedValues)
|
||||
}
|
||||
|
||||
private fun FixStackFrame.executeSaveStackBeforeTry(insn: AbstractInsnNode) {
|
||||
saveStackAndClear(insn)
|
||||
}
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.fixStack
|
||||
|
||||
import com.intellij.util.SmartList
|
||||
import com.intellij.util.containers.SmartHashSet
|
||||
import com.intellij.util.containers.Stack
|
||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.findPreviousOrNull
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.hasOpcode
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.forEachPseudoInsn
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.parsePseudoInsnOrNull
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import java.util.*
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
internal class FixStackContext(val methodNode: MethodNode) {
|
||||
val breakContinueGotoNodes = linkedSetOf<JumpInsnNode>()
|
||||
val fakeAlwaysTrueIfeqMarkers = arrayListOf<AbstractInsnNode>()
|
||||
val fakeAlwaysFalseIfeqMarkers = arrayListOf<AbstractInsnNode>()
|
||||
|
||||
val saveStackNodesForTryStartLabel = hashMapOf<LabelNode, AbstractInsnNode>()
|
||||
val saveStackMarkerForRestoreMarker = hashMapOf<AbstractInsnNode, AbstractInsnNode>()
|
||||
val restoreStackMarkersForSaveMarker = hashMapOf<AbstractInsnNode, MutableList<AbstractInsnNode>>()
|
||||
|
||||
val openingInlineMethodMarker = hashMapOf<AbstractInsnNode, AbstractInsnNode>()
|
||||
var consistentInlineMarkers: Boolean = true; private set
|
||||
|
||||
init {
|
||||
insertTryCatchBlocksMarkers(methodNode)
|
||||
|
||||
val inlineMarkersStack = Stack<AbstractInsnNode>()
|
||||
|
||||
InsnSequence(methodNode.instructions).forEach { insnNode ->
|
||||
val pseudoInsn = parsePseudoInsnOrNull(insnNode)
|
||||
when {
|
||||
pseudoInsn == PseudoInsn.FIX_STACK_BEFORE_JUMP ->
|
||||
visitFixStackBeforeJump(insnNode)
|
||||
pseudoInsn == PseudoInsn.FAKE_ALWAYS_TRUE_IFEQ ->
|
||||
visitFakeAlwaysTrueIfeq(insnNode)
|
||||
pseudoInsn == PseudoInsn.FAKE_ALWAYS_FALSE_IFEQ ->
|
||||
visitFakeAlwaysFalseIfeq(insnNode)
|
||||
pseudoInsn == PseudoInsn.SAVE_STACK_BEFORE_TRY ->
|
||||
visitSaveStackBeforeTry(insnNode)
|
||||
pseudoInsn == PseudoInsn.RESTORE_STACK_IN_TRY_CATCH ->
|
||||
visitRestoreStackInTryCatch(insnNode)
|
||||
InlineCodegenUtil.isBeforeInlineMarker(insnNode) -> {
|
||||
inlineMarkersStack.push(insnNode)
|
||||
}
|
||||
InlineCodegenUtil.isAfterInlineMarker(insnNode) -> {
|
||||
assert(inlineMarkersStack.isNotEmpty(), "Mismatching after inline method marker at ${indexOf(insnNode)}")
|
||||
openingInlineMethodMarker[insnNode] = inlineMarkersStack.pop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inlineMarkersStack.isNotEmpty()) {
|
||||
consistentInlineMarkers = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun visitFixStackBeforeJump(insnNode: AbstractInsnNode) {
|
||||
val next = insnNode.getNext()
|
||||
assert(next.getOpcode() == Opcodes.GOTO, "${indexOf(insnNode)}: should be followed by GOTO")
|
||||
breakContinueGotoNodes.add(next as JumpInsnNode)
|
||||
}
|
||||
|
||||
private fun visitFakeAlwaysTrueIfeq(insnNode: AbstractInsnNode) {
|
||||
assert(insnNode.getNext().getOpcode() == Opcodes.IFEQ, "${indexOf(insnNode)}: should be followed by IFEQ")
|
||||
fakeAlwaysTrueIfeqMarkers.add(insnNode)
|
||||
}
|
||||
|
||||
private fun visitFakeAlwaysFalseIfeq(insnNode: AbstractInsnNode) {
|
||||
assert(insnNode.getNext().getOpcode() == Opcodes.IFEQ, "${indexOf(insnNode)}: should be followed by IFEQ")
|
||||
fakeAlwaysFalseIfeqMarkers.add(insnNode)
|
||||
}
|
||||
|
||||
private fun visitSaveStackBeforeTry(insnNode: AbstractInsnNode) {
|
||||
val tryStartLabel = insnNode.getNext()
|
||||
assert(tryStartLabel is LabelNode, "${indexOf(insnNode)}: save should be followed by a label")
|
||||
saveStackNodesForTryStartLabel[tryStartLabel as LabelNode] = insnNode
|
||||
}
|
||||
|
||||
private fun visitRestoreStackInTryCatch(insnNode: AbstractInsnNode) {
|
||||
val restoreLabel = insnNode.findPreviousOrNull { it.hasOpcode() }!!.findPreviousOrNull { it is LabelNode || it.hasOpcode() }!!
|
||||
if (restoreLabel !is LabelNode) {
|
||||
throw AssertionError("${indexOf(insnNode)}: restore should be preceded by a catch block label")
|
||||
}
|
||||
val saveNodes = findMatchingSaveNodes(insnNode, restoreLabel)
|
||||
if (saveNodes.isEmpty()) {
|
||||
throw AssertionError("${indexOf(insnNode)}: in handler ${indexOf(restoreLabel)} restore is not matched with save")
|
||||
}
|
||||
else if (saveNodes.size() > 1) {
|
||||
throw AssertionError("${indexOf(insnNode)}: in handler ${indexOf(restoreLabel)} restore is matched with several saves")
|
||||
}
|
||||
val saveNode = saveNodes.first()
|
||||
saveStackMarkerForRestoreMarker[insnNode] = saveNode
|
||||
restoreStackMarkersForSaveMarker.getOrPut(saveNode, { SmartList<AbstractInsnNode>() }).add(insnNode)
|
||||
}
|
||||
|
||||
private fun findMatchingSaveNodes(insnNode: AbstractInsnNode, restoreLabel: LabelNode): List<AbstractInsnNode> {
|
||||
val saveNodes = SmartHashSet<AbstractInsnNode>()
|
||||
methodNode.tryCatchBlocks.forEach { tcb ->
|
||||
if (restoreLabel == tcb.start || restoreLabel == tcb.handler) {
|
||||
saveStackNodesForTryStartLabel[tcb.start]?.let { saveNodes.add(it) }
|
||||
}
|
||||
}
|
||||
return SmartList<AbstractInsnNode>(saveNodes)
|
||||
}
|
||||
|
||||
private fun indexOf(node: AbstractInsnNode) = methodNode.instructions.indexOf(node)
|
||||
|
||||
fun hasAnyMarkers(): Boolean =
|
||||
breakContinueGotoNodes.isNotEmpty() ||
|
||||
fakeAlwaysTrueIfeqMarkers.isNotEmpty() ||
|
||||
fakeAlwaysFalseIfeqMarkers.isNotEmpty() ||
|
||||
saveStackNodesForTryStartLabel.isNotEmpty() ||
|
||||
openingInlineMethodMarker.isNotEmpty()
|
||||
|
||||
fun isAnalysisRequired(): Boolean =
|
||||
breakContinueGotoNodes.isNotEmpty() ||
|
||||
saveStackNodesForTryStartLabel.isNotEmpty() ||
|
||||
openingInlineMethodMarker.isNotEmpty()
|
||||
|
||||
}
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.fixStack
|
||||
|
||||
import com.intellij.util.containers.Stack
|
||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.MethodAnalyzer
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.forEachPseudoInsn
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.parsePseudoInsnOrNull
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
|
||||
import java.util.*
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
public object FixStackMethodTransformer : MethodTransformer() {
|
||||
public override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
val context = FixStackContext(methodNode)
|
||||
|
||||
if (!context.hasAnyMarkers()) return
|
||||
|
||||
// If inline method markers are inconsistent, remove them now
|
||||
if (!context.consistentInlineMarkers) {
|
||||
InsnSequence(methodNode.instructions).forEach { insnNode ->
|
||||
if (InlineCodegenUtil.isInlineMarker(insnNode))
|
||||
methodNode.instructions.remove(insnNode)
|
||||
}
|
||||
}
|
||||
|
||||
if (context.isAnalysisRequired()) {
|
||||
val analyzer = FixStackAnalyzer(internalClassName, methodNode, context)
|
||||
analyzer.analyze()
|
||||
|
||||
methodNode.maxStack = methodNode.maxStack + analyzer.maxExtraStackSize
|
||||
|
||||
val actions = arrayListOf<() -> Unit>()
|
||||
|
||||
transformBreakContinueGotos(methodNode, context, actions, analyzer)
|
||||
|
||||
transformSaveRestoreStackMarkers(methodNode, context, actions, analyzer)
|
||||
|
||||
actions.forEach { it() }
|
||||
}
|
||||
|
||||
context.fakeAlwaysTrueIfeqMarkers.forEach { marker ->
|
||||
replaceAlwaysTrueIfeqWithGoto(methodNode, marker)
|
||||
}
|
||||
|
||||
context.fakeAlwaysFalseIfeqMarkers.forEach { marker ->
|
||||
removeAlwaysFalseIfeq(methodNode, marker)
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformBreakContinueGotos(
|
||||
methodNode: MethodNode,
|
||||
fixStackContext: FixStackContext,
|
||||
actions: MutableList<() -> Unit>,
|
||||
analyzer: FixStackAnalyzer
|
||||
) {
|
||||
fixStackContext.breakContinueGotoNodes.forEach { gotoNode ->
|
||||
val gotoIndex = methodNode.instructions.indexOf(gotoNode)
|
||||
val labelIndex = methodNode.instructions.indexOf(gotoNode.label)
|
||||
|
||||
val DEAD_CODE = -1 // Stack size is always non-negative
|
||||
val actualStackSize = analyzer.frames[gotoIndex]?.getStackSize() ?: DEAD_CODE
|
||||
val expectedStackSize = analyzer.frames[labelIndex]?.getStackSize() ?: DEAD_CODE
|
||||
|
||||
if (actualStackSize != DEAD_CODE && expectedStackSize != DEAD_CODE) {
|
||||
assert(expectedStackSize <= actualStackSize,
|
||||
"Label at $labelIndex, jump at $gotoIndex: stack underflow: $expectedStackSize > $actualStackSize")
|
||||
val frame = analyzer.frames[gotoIndex]!!
|
||||
actions.add({ replaceMarkerWithPops(methodNode, gotoNode.getPrevious(), expectedStackSize, frame) })
|
||||
}
|
||||
else if (actualStackSize != DEAD_CODE && expectedStackSize == DEAD_CODE) {
|
||||
throw AssertionError("Live jump $gotoIndex to dead label $labelIndex")
|
||||
}
|
||||
else {
|
||||
val marker = gotoNode.getPrevious()
|
||||
actions.add({ methodNode.instructions.remove(marker) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformSaveRestoreStackMarkers(
|
||||
methodNode: MethodNode,
|
||||
context: FixStackContext,
|
||||
actions: MutableList<() -> Unit>,
|
||||
analyzer: FixStackAnalyzer
|
||||
) {
|
||||
val localVariablesManager = LocalVariablesManager(context, methodNode)
|
||||
InsnSequence(methodNode.instructions).forEach { marker ->
|
||||
val pseudoInsn = parsePseudoInsnOrNull(marker)
|
||||
when {
|
||||
pseudoInsn == PseudoInsn.SAVE_STACK_BEFORE_TRY ->
|
||||
transformSaveStackMarker(methodNode, actions, analyzer, marker, localVariablesManager)
|
||||
pseudoInsn == PseudoInsn.RESTORE_STACK_IN_TRY_CATCH ->
|
||||
transformRestoreStackMarker(methodNode, actions, marker, localVariablesManager)
|
||||
InlineCodegenUtil.isBeforeInlineMarker(marker) ->
|
||||
transformBeforeInlineCallMarker(methodNode, actions, analyzer, marker, localVariablesManager)
|
||||
InlineCodegenUtil.isAfterInlineMarker(marker) ->
|
||||
transformAfterInlineCallMarker(methodNode, actions, analyzer, marker, localVariablesManager)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformSaveStackMarker(
|
||||
methodNode: MethodNode,
|
||||
actions: MutableList<() -> Unit>,
|
||||
analyzer: FixStackAnalyzer,
|
||||
marker: AbstractInsnNode,
|
||||
localVariablesManager: LocalVariablesManager
|
||||
) {
|
||||
val savedStackValues = analyzer.savedStacks[marker]
|
||||
if (savedStackValues != null) {
|
||||
val savedStackDescriptor = localVariablesManager.allocateVariablesForSaveStackMarker(marker, savedStackValues)
|
||||
actions.add({ saveStack(methodNode, marker, savedStackDescriptor, false) })
|
||||
}
|
||||
else {
|
||||
// marker is dead code
|
||||
localVariablesManager.allocateVariablesForSaveStackMarker(marker, emptyList())
|
||||
actions.add({ methodNode.instructions.remove(marker) })
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformRestoreStackMarker(
|
||||
methodNode: MethodNode,
|
||||
actions: MutableList<() -> Unit>,
|
||||
marker: AbstractInsnNode,
|
||||
localVariablesManager: LocalVariablesManager
|
||||
) {
|
||||
val savedStackDescriptor = localVariablesManager.getSavedStackDescriptorOrNull(marker)
|
||||
if (savedStackDescriptor != null) {
|
||||
actions.add({ restoreStack(methodNode, marker, savedStackDescriptor) })
|
||||
}
|
||||
else {
|
||||
// marker is dead code
|
||||
actions.add({ methodNode.instructions.remove(marker) })
|
||||
}
|
||||
localVariablesManager.markRestoreStackMarkerEmitted(marker)
|
||||
}
|
||||
|
||||
private fun transformAfterInlineCallMarker(
|
||||
methodNode: MethodNode,
|
||||
actions: MutableList<() -> Unit>,
|
||||
analyzer: FixStackAnalyzer,
|
||||
inlineMarker: AbstractInsnNode,
|
||||
localVariablesManager: LocalVariablesManager
|
||||
) {
|
||||
val savedStackDescriptor = localVariablesManager.getBeforeInlineDescriptor(inlineMarker)
|
||||
val afterInlineFrame = analyzer.getFrame(inlineMarker) as FixStackAnalyzer.FixStackFrame?
|
||||
if (afterInlineFrame != null && savedStackDescriptor.isNotEmpty()) {
|
||||
assert(afterInlineFrame.getStackSize() <= 1, "Inline method should not leave more than 1 value on stack")
|
||||
if (afterInlineFrame.getStackSize() == 1) {
|
||||
val afterInlineStackValues = afterInlineFrame.getStackContent()
|
||||
val returnValue = afterInlineStackValues.last()
|
||||
val returnValueLocalVarIndex = localVariablesManager.createReturnValueVariable(returnValue)
|
||||
actions.add({
|
||||
restoreStackWithReturnValue(methodNode, inlineMarker, savedStackDescriptor,
|
||||
returnValue, returnValueLocalVarIndex)
|
||||
})
|
||||
}
|
||||
else {
|
||||
actions.add({ restoreStack(methodNode, inlineMarker, savedStackDescriptor) })
|
||||
}
|
||||
}
|
||||
else {
|
||||
// after inline marker is dead code
|
||||
actions.add({ methodNode.instructions.remove(inlineMarker) })
|
||||
}
|
||||
localVariablesManager.markAfterInlineMarkerEmitted(inlineMarker)
|
||||
}
|
||||
|
||||
private fun transformBeforeInlineCallMarker(
|
||||
methodNode: MethodNode,
|
||||
actions: MutableList<() -> Unit>,
|
||||
analyzer: FixStackAnalyzer,
|
||||
inlineMarker: AbstractInsnNode,
|
||||
localVariablesManager: LocalVariablesManager
|
||||
) {
|
||||
val savedStackValues = analyzer.savedStacks[inlineMarker]
|
||||
if (savedStackValues != null) {
|
||||
val savedStackDescriptor = localVariablesManager.allocateVariablesForBeforeInlineMarker(inlineMarker, savedStackValues)
|
||||
actions.add({ saveStack(methodNode, inlineMarker, savedStackDescriptor, false) })
|
||||
}
|
||||
else {
|
||||
// before inline marker is dead code
|
||||
localVariablesManager.allocateVariablesForBeforeInlineMarker(inlineMarker, emptyList())
|
||||
actions.add({ methodNode.instructions.remove(inlineMarker) })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.fixStack
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
|
||||
internal class LocalVariablesManager(val context: FixStackContext, val methodNode: MethodNode) {
|
||||
private class AllocatedHandle(val savedStackDescriptor: SavedStackDescriptor, var numRestoreMarkers: Int) {
|
||||
fun isFullyEmitted(): Boolean =
|
||||
numRestoreMarkers == 0
|
||||
|
||||
fun markRestoreNodeEmitted() {
|
||||
assert(numRestoreMarkers > 0, "Emitted more restore markers than expected for $savedStackDescriptor")
|
||||
numRestoreMarkers--
|
||||
}
|
||||
}
|
||||
|
||||
private val initialMaxLocals = methodNode.maxLocals
|
||||
private val allocatedHandles = hashMapOf<AbstractInsnNode, AllocatedHandle>()
|
||||
|
||||
private fun updateMaxLocals(newValue: Int) {
|
||||
methodNode.maxLocals = Math.max(methodNode.maxLocals, newValue)
|
||||
}
|
||||
|
||||
fun allocateVariablesForSaveStackMarker(saveStackMarker: AbstractInsnNode, savedStackValues: List<BasicValue>): SavedStackDescriptor {
|
||||
val numRestoreStackMarkers = context.restoreStackMarkersForSaveMarker[saveStackMarker]!!.size()
|
||||
return allocateNewHandle(numRestoreStackMarkers, saveStackMarker, savedStackValues)
|
||||
}
|
||||
|
||||
private fun allocateNewHandle(numRestoreStackMarkers: Int, saveStackMarker: AbstractInsnNode, savedStackValues: List<BasicValue>): SavedStackDescriptor {
|
||||
val firstUnusedLocalVarIndex = getFirstUnusedLocalVariableIndex()
|
||||
val savedStackDescriptor = SavedStackDescriptor(savedStackValues, firstUnusedLocalVarIndex)
|
||||
updateMaxLocals(savedStackDescriptor.firstUnusedLocalVarIndex)
|
||||
val allocatedHandle = AllocatedHandle(savedStackDescriptor, numRestoreStackMarkers)
|
||||
allocatedHandles[saveStackMarker] = allocatedHandle
|
||||
return savedStackDescriptor
|
||||
}
|
||||
|
||||
fun getSavedStackDescriptorOrNull(restoreStackMarker: AbstractInsnNode): SavedStackDescriptor {
|
||||
val saveStackMarker = context.saveStackMarkerForRestoreMarker[restoreStackMarker]
|
||||
return allocatedHandles[saveStackMarker]!!.savedStackDescriptor
|
||||
}
|
||||
|
||||
private fun getFirstUnusedLocalVariableIndex(): Int =
|
||||
allocatedHandles.values().fold(initialMaxLocals) {
|
||||
index, handle -> Math.max(index, handle.savedStackDescriptor.firstUnusedLocalVarIndex)
|
||||
}
|
||||
|
||||
fun markRestoreStackMarkerEmitted(restoreStackMarker: AbstractInsnNode) {
|
||||
val saveStackMarker = context.saveStackMarkerForRestoreMarker[restoreStackMarker]
|
||||
markEmitted(saveStackMarker!!)
|
||||
}
|
||||
|
||||
fun allocateVariablesForBeforeInlineMarker(beforeInlineMarker: AbstractInsnNode, savedStackValues: List<BasicValue>): SavedStackDescriptor {
|
||||
return allocateNewHandle(1, beforeInlineMarker, savedStackValues)
|
||||
}
|
||||
|
||||
fun getBeforeInlineDescriptor(afterInlineMarker: AbstractInsnNode): SavedStackDescriptor {
|
||||
val beforeInlineMarker = context.openingInlineMethodMarker[afterInlineMarker]
|
||||
return allocatedHandles[beforeInlineMarker]!!.savedStackDescriptor
|
||||
}
|
||||
|
||||
fun markAfterInlineMarkerEmitted(afterInlineMarker: AbstractInsnNode) {
|
||||
val beforeInlineMarker = context.openingInlineMethodMarker[afterInlineMarker]
|
||||
markEmitted(beforeInlineMarker!!)
|
||||
}
|
||||
|
||||
private fun markEmitted(saveStackMarker: AbstractInsnNode) {
|
||||
val allocatedHandle = allocatedHandles[saveStackMarker]!!
|
||||
allocatedHandle.markRestoreNodeEmitted()
|
||||
if (allocatedHandle.isFullyEmitted()) {
|
||||
allocatedHandles.remove(saveStackMarker)
|
||||
}
|
||||
}
|
||||
|
||||
fun createReturnValueVariable(returnValue: BasicValue): Int {
|
||||
val returnValueIndex = getFirstUnusedLocalVariableIndex()
|
||||
updateMaxLocals(returnValueIndex + returnValue.getSize())
|
||||
return returnValueIndex
|
||||
}
|
||||
}
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.fixStack
|
||||
|
||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.parsePseudoInsnOrNull
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Value
|
||||
|
||||
public inline fun InsnList.forEachPseudoInsn(block: (PseudoInsn, AbstractInsnNode) -> Unit) {
|
||||
InsnSequence(this).forEach { insn ->
|
||||
parsePseudoInsnOrNull(insn)?.let { block(it, insn) }
|
||||
}
|
||||
}
|
||||
|
||||
public inline fun InsnList.forEachInlineMarker(block: (String, MethodInsnNode) -> Unit) {
|
||||
InsnSequence(this).forEach { insn ->
|
||||
if (InlineCodegenUtil.isInlineMarker(insn)) {
|
||||
val methodInsnNode = insn as MethodInsnNode
|
||||
block(methodInsnNode.name, methodInsnNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun <V : Value> Frame<V>.top(): V? {
|
||||
val stackSize = getStackSize()
|
||||
if (stackSize == 0)
|
||||
return null
|
||||
else
|
||||
return getStack(stackSize - 1)
|
||||
}
|
||||
|
||||
public fun MethodNode.updateMaxLocals(newMaxLocals: Int) {
|
||||
maxLocals = Math.max(maxLocals, newMaxLocals)
|
||||
}
|
||||
|
||||
class SavedStackDescriptor(
|
||||
val savedValues: List<BasicValue>,
|
||||
val firstLocalVarIndex: Int
|
||||
) {
|
||||
val savedValuesSize = savedValues.fold(0, { size, value -> size + value.getSize() })
|
||||
val firstUnusedLocalVarIndex = firstLocalVarIndex + savedValuesSize
|
||||
|
||||
public override fun toString(): String =
|
||||
"@$firstLocalVarIndex: [$savedValues]"
|
||||
|
||||
fun isNotEmpty(): Boolean = savedValues.isNotEmpty()
|
||||
}
|
||||
|
||||
|
||||
fun saveStack(methodNode: MethodNode, nodeToReplace: AbstractInsnNode, savedStackDescriptor: SavedStackDescriptor,
|
||||
restoreImmediately: Boolean) {
|
||||
with(methodNode.instructions) {
|
||||
generateStoreInstructions(methodNode, nodeToReplace, savedStackDescriptor)
|
||||
if (restoreImmediately) {
|
||||
generateLoadInstructions(methodNode, nodeToReplace, savedStackDescriptor)
|
||||
}
|
||||
remove(nodeToReplace)
|
||||
}
|
||||
}
|
||||
|
||||
fun restoreStack(methodNode: MethodNode, location: AbstractInsnNode, savedStackDescriptor: SavedStackDescriptor) {
|
||||
with(methodNode.instructions) {
|
||||
generateLoadInstructions(methodNode, location, savedStackDescriptor)
|
||||
remove(location)
|
||||
}
|
||||
}
|
||||
|
||||
fun restoreStackWithReturnValue(
|
||||
methodNode: MethodNode,
|
||||
nodeToReplace: AbstractInsnNode,
|
||||
savedStackDescriptor: SavedStackDescriptor,
|
||||
returnValue: BasicValue,
|
||||
returnValueLocalVarIndex: Int
|
||||
) {
|
||||
with(methodNode.instructions) {
|
||||
insertBefore(nodeToReplace, VarInsnNode(returnValue.getType().getOpcode(Opcodes.ISTORE), returnValueLocalVarIndex))
|
||||
generateLoadInstructions(methodNode, nodeToReplace, savedStackDescriptor)
|
||||
insertBefore(nodeToReplace, VarInsnNode(returnValue.getType().getOpcode(Opcodes.ILOAD), returnValueLocalVarIndex))
|
||||
remove(nodeToReplace)
|
||||
}
|
||||
}
|
||||
|
||||
fun generateLoadInstructions(methodNode: MethodNode, location: AbstractInsnNode, savedStackDescriptor: SavedStackDescriptor) {
|
||||
var localVarIndex = savedStackDescriptor.firstLocalVarIndex
|
||||
for (value in savedStackDescriptor.savedValues) {
|
||||
methodNode.instructions.insertBefore(location,
|
||||
VarInsnNode(value.getType().getOpcode(Opcodes.ILOAD), localVarIndex))
|
||||
localVarIndex += value.getSize()
|
||||
}
|
||||
}
|
||||
|
||||
fun generateStoreInstructions(methodNode: MethodNode, location: AbstractInsnNode, savedStackDescriptor: SavedStackDescriptor) {
|
||||
var localVarIndex = savedStackDescriptor.firstUnusedLocalVarIndex
|
||||
for (value in savedStackDescriptor.savedValues.reverse()) {
|
||||
localVarIndex -= value.getSize()
|
||||
methodNode.instructions.insertBefore(location,
|
||||
VarInsnNode(value.getType().getOpcode(Opcodes.ISTORE), localVarIndex))
|
||||
}
|
||||
}
|
||||
|
||||
fun getPopInstruction(top: BasicValue) =
|
||||
InsnNode(when (top.getSize()) {
|
||||
1 -> Opcodes.POP
|
||||
2 -> Opcodes.POP2
|
||||
else -> throw AssertionError("Unexpected value type size")
|
||||
})
|
||||
|
||||
fun removeAlwaysFalseIfeq(methodNode: MethodNode, node: AbstractInsnNode) {
|
||||
with (methodNode.instructions) {
|
||||
remove(node.getNext())
|
||||
remove(node)
|
||||
}
|
||||
}
|
||||
|
||||
fun replaceAlwaysTrueIfeqWithGoto(methodNode: MethodNode, node: AbstractInsnNode) {
|
||||
with (methodNode.instructions) {
|
||||
val next = node.getNext() as JumpInsnNode
|
||||
insertBefore(node, JumpInsnNode(Opcodes.GOTO, next.label))
|
||||
remove(node)
|
||||
remove(next)
|
||||
}
|
||||
}
|
||||
|
||||
fun replaceMarkerWithPops(methodNode: MethodNode, node: AbstractInsnNode, expectedStackSize: Int, frame: Frame<BasicValue>) {
|
||||
with (methodNode.instructions) {
|
||||
while (frame.getStackSize() > expectedStackSize) {
|
||||
val top = frame.pop()
|
||||
insertBefore(node, getPopInstruction(top))
|
||||
}
|
||||
remove(node)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,78 +24,46 @@ import org.jetbrains.org.objectweb.asm.tree.InsnList
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
|
||||
import kotlin.platform.platformStatic
|
||||
|
||||
public val PSEUDO_INSN_CALL_OWNER: String = "kotlin.jvm.\$PseudoInsn"
|
||||
public val PSEUDO_INSN_PARTS_SEPARATOR: String = ":"
|
||||
public val PSEUDO_INSN_CALL_OWNER: String = "kotlin/jvm/internal/\$PseudoInsn"
|
||||
|
||||
public enum class PseudoInsnOpcode(val signature: String = "()V") {
|
||||
public enum class PseudoInsn(val signature: String = "()V") {
|
||||
FIX_STACK_BEFORE_JUMP(),
|
||||
FAKE_ALWAYS_TRUE_IFEQ("()I"),
|
||||
FAKE_ALWAYS_FALSE_IFEQ("()I")
|
||||
FAKE_ALWAYS_FALSE_IFEQ("()I"),
|
||||
SAVE_STACK_BEFORE_TRY(),
|
||||
RESTORE_STACK_IN_TRY_CATCH()
|
||||
;
|
||||
|
||||
public fun insnOf(): PseudoInsn = PseudoInsn(this, emptyList())
|
||||
public fun insnOf(args: List<String>): PseudoInsn = PseudoInsn(this, args)
|
||||
|
||||
public fun parseOrNull(insn: AbstractInsnNode): PseudoInsn? {
|
||||
val pseudo = parseOrNull(insn)
|
||||
return if (pseudo?.opcode == this) pseudo else null
|
||||
}
|
||||
|
||||
public fun isa(insn: AbstractInsnNode): Boolean =
|
||||
if (isPseudoInsn(insn)) {
|
||||
val methodName = (insn as MethodInsnNode).name
|
||||
methodName == this.toString() || methodName.startsWith(this.toString() + PSEUDO_INSN_PARTS_SEPARATOR)
|
||||
}
|
||||
else false
|
||||
|
||||
public fun emit(iv: InstructionAdapter) {
|
||||
insnOf().emit(iv)
|
||||
iv.invokestatic(PSEUDO_INSN_CALL_OWNER, toString(), signature, false)
|
||||
}
|
||||
|
||||
public fun createInsnNode(): MethodInsnNode =
|
||||
MethodInsnNode(Opcodes.INVOKESTATIC, PSEUDO_INSN_CALL_OWNER, toString(), signature, false)
|
||||
|
||||
public fun isa(node: AbstractInsnNode): Boolean =
|
||||
this == parsePseudoInsnOrNull(node)
|
||||
}
|
||||
|
||||
public class PseudoInsn(public val opcode: PseudoInsnOpcode, public val args: List<String>) {
|
||||
public val encodedMethodName: String =
|
||||
if (args.isEmpty())
|
||||
opcode.toString()
|
||||
else
|
||||
opcode.toString() + PSEUDO_INSN_PARTS_SEPARATOR + args.join(PSEUDO_INSN_PARTS_SEPARATOR)
|
||||
public fun isPseudoInsn(insn: AbstractInsnNode): Boolean =
|
||||
insn is MethodInsnNode && insn.getOpcode() == Opcodes.INVOKESTATIC && insn.owner == PSEUDO_INSN_CALL_OWNER
|
||||
|
||||
public fun emit(iv: InstructionAdapter) {
|
||||
iv.invokestatic(PSEUDO_INSN_CALL_OWNER, encodedMethodName, opcode.signature, false)
|
||||
}
|
||||
}
|
||||
public fun parsePseudoInsnOrNull(insn: AbstractInsnNode): PseudoInsn? =
|
||||
if (isPseudoInsn(insn))
|
||||
PseudoInsn.valueOf((insn as MethodInsnNode).name)
|
||||
else null
|
||||
|
||||
public fun InstructionAdapter.fixStackAndJump(label: Label) {
|
||||
PseudoInsnOpcode.FIX_STACK_BEFORE_JUMP.emit(this)
|
||||
PseudoInsn.FIX_STACK_BEFORE_JUMP.emit(this)
|
||||
this.goTo(label)
|
||||
}
|
||||
|
||||
public fun InstructionAdapter.fakeAlwaysTrueIfeq(label: Label) {
|
||||
PseudoInsnOpcode.FAKE_ALWAYS_TRUE_IFEQ.emit(this)
|
||||
PseudoInsn.FAKE_ALWAYS_TRUE_IFEQ.emit(this)
|
||||
this.ifeq(label)
|
||||
}
|
||||
|
||||
public fun InstructionAdapter.fakeAlwaysFalseIfeq(label: Label) {
|
||||
PseudoInsnOpcode.FAKE_ALWAYS_FALSE_IFEQ.emit(this)
|
||||
PseudoInsn.FAKE_ALWAYS_FALSE_IFEQ.emit(this)
|
||||
this.ifeq(label)
|
||||
}
|
||||
|
||||
public fun parseOrNull(insn: AbstractInsnNode): PseudoInsn? =
|
||||
if (isPseudoInsn(insn))
|
||||
parseParts(getPseudoInsnParts(insn as MethodInsnNode))
|
||||
else null
|
||||
|
||||
private fun isPseudoInsn(insn: AbstractInsnNode) =
|
||||
insn is MethodInsnNode && insn.getOpcode() == Opcodes.INVOKESTATIC && insn.owner == PSEUDO_INSN_CALL_OWNER
|
||||
|
||||
private fun getPseudoInsnParts(insn: MethodInsnNode): List<String> =
|
||||
insn.name.splitBy(PSEUDO_INSN_PARTS_SEPARATOR)
|
||||
|
||||
private fun parseParts(parts: List<String>): PseudoInsn? {
|
||||
try {
|
||||
return PseudoInsnOpcode.valueOf(parts[0]).insnOf(parts.subList(1, parts.size()))
|
||||
}
|
||||
catch (e: IllegalArgumentException) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,10 @@ import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
|
||||
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils;
|
||||
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils;
|
||||
import org.jetbrains.kotlin.load.kotlin.nativeDeclarations.NativeDeclarationsPackage;
|
||||
import org.jetbrains.kotlin.name.*;
|
||||
import org.jetbrains.kotlin.name.ClassId;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe;
|
||||
import org.jetbrains.kotlin.name.SpecialNames;
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap;
|
||||
import org.jetbrains.kotlin.psi.JetExpression;
|
||||
import org.jetbrains.kotlin.psi.JetFile;
|
||||
@@ -51,7 +54,7 @@ import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||
import org.jetbrains.kotlin.resolve.constants.StringValue;
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
|
||||
@@ -681,13 +684,13 @@ public class JetTypeMapper {
|
||||
}
|
||||
|
||||
boolean isAccessor = property instanceof AccessorForPropertyDescriptor;
|
||||
Name propertyName = isAccessor
|
||||
? Name.identifier(((AccessorForPropertyDescriptor) property).getIndexedAccessorSuffix())
|
||||
: property.getName();
|
||||
String propertyName = isAccessor
|
||||
? ((AccessorForPropertyDescriptor) property).getIndexedAccessorSuffix()
|
||||
: property.getName().asString();
|
||||
|
||||
String accessorName = descriptor instanceof PropertyGetterDescriptor
|
||||
? PropertyCodegen.getterName(propertyName)
|
||||
: PropertyCodegen.setterName(propertyName);
|
||||
? JvmAbi.getterName(propertyName)
|
||||
: JvmAbi.setterName(propertyName);
|
||||
|
||||
return isAccessor ? "access$" + accessorName : accessorName;
|
||||
}
|
||||
@@ -718,10 +721,10 @@ public class JetTypeMapper {
|
||||
AnnotationDescriptor platformNameAnnotation = descriptor.getAnnotations().findAnnotation(new FqName("kotlin.platform.platformName"));
|
||||
if (platformNameAnnotation == null) return null;
|
||||
|
||||
Map<ValueParameterDescriptor, CompileTimeConstant<?>> arguments = platformNameAnnotation.getAllValueArguments();
|
||||
Map<ValueParameterDescriptor, ConstantValue<?>> arguments = platformNameAnnotation.getAllValueArguments();
|
||||
if (arguments.isEmpty()) return null;
|
||||
|
||||
CompileTimeConstant<?> name = arguments.values().iterator().next();
|
||||
ConstantValue<?> name = arguments.values().iterator().next();
|
||||
if (!(name instanceof StringValue)) return null;
|
||||
|
||||
return ((StringValue) name).getValue();
|
||||
|
||||
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.codegen.when;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.kotlin.psi.JetWhenExpression;
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||
import org.jetbrains.kotlin.resolve.constants.EnumValue;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
@@ -58,7 +58,7 @@ public class EnumSwitchCodegen extends SwitchCodegen {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processConstant(@NotNull CompileTimeConstant constant, @NotNull Label entryLabel) {
|
||||
protected void processConstant(@NotNull ConstantValue<?> constant, @NotNull Label entryLabel) {
|
||||
assert constant instanceof EnumValue : "guaranteed by usage contract";
|
||||
putTransitionOnce(mapping.getIndexByEntry((EnumValue) constant), entryLabel);
|
||||
}
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.codegen.when;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.kotlin.psi.JetWhenExpression;
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
|
||||
public class IntegralConstantsSwitchCodegen extends SwitchCodegen {
|
||||
@@ -32,7 +32,7 @@ public class IntegralConstantsSwitchCodegen extends SwitchCodegen {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processConstant(@NotNull CompileTimeConstant constant, @NotNull Label entryLabel) {
|
||||
protected void processConstant(@NotNull ConstantValue<?> constant, @NotNull Label entryLabel) {
|
||||
assert constant.getValue() != null : "constant value should not be null";
|
||||
int value = (constant.getValue() instanceof Number)
|
||||
? ((Number) constant.getValue()).intValue()
|
||||
|
||||
@@ -21,7 +21,7 @@ import com.intellij.openapi.util.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.kotlin.psi.JetWhenExpression;
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||
import org.jetbrains.kotlin.resolve.constants.StringValue;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
@@ -47,7 +47,7 @@ public class StringSwitchCodegen extends SwitchCodegen {
|
||||
|
||||
@Override
|
||||
protected void processConstant(
|
||||
@NotNull CompileTimeConstant constant, @NotNull Label entryLabel
|
||||
@NotNull ConstantValue<?> constant, @NotNull Label entryLabel
|
||||
) {
|
||||
assert constant instanceof StringValue : "guaranteed by usage contract";
|
||||
int hashCode = constant.hashCode();
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.codegen.FrameMap;
|
||||
import org.jetbrains.kotlin.psi.JetWhenEntry;
|
||||
import org.jetbrains.kotlin.psi.JetWhenExpression;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||
import org.jetbrains.kotlin.resolve.constants.NullValue;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
import org.jetbrains.kotlin.types.TypeUtils;
|
||||
@@ -96,7 +96,7 @@ abstract public class SwitchCodegen {
|
||||
for (JetWhenEntry entry : expression.getEntries()) {
|
||||
Label entryLabel = new Label();
|
||||
|
||||
for (CompileTimeConstant constant : SwitchCodegenUtil.getConstantsFromEntry(entry, bindingContext)) {
|
||||
for (ConstantValue<?> constant : SwitchCodegenUtil.getConstantsFromEntry(entry, bindingContext)) {
|
||||
if (constant instanceof NullValue) continue;
|
||||
processConstant(constant, entryLabel);
|
||||
}
|
||||
@@ -110,7 +110,7 @@ abstract public class SwitchCodegen {
|
||||
}
|
||||
|
||||
abstract protected void processConstant(
|
||||
@NotNull CompileTimeConstant constant,
|
||||
@NotNull ConstantValue<?> constant,
|
||||
@NotNull Label entryLabel
|
||||
);
|
||||
|
||||
@@ -154,7 +154,7 @@ abstract public class SwitchCodegen {
|
||||
private int findNullEntryIndex(@NotNull JetWhenExpression expression) {
|
||||
int entryIndex = 0;
|
||||
for (JetWhenEntry entry : expression.getEntries()) {
|
||||
for (CompileTimeConstant constant : SwitchCodegenUtil.getConstantsFromEntry(entry, bindingContext)) {
|
||||
for (ConstantValue<?> constant : SwitchCodegenUtil.getConstantsFromEntry(entry, bindingContext)) {
|
||||
if (constant instanceof NullValue) {
|
||||
return entryIndex;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueConstant;
|
||||
import org.jetbrains.kotlin.resolve.constants.NullValue;
|
||||
import org.jetbrains.kotlin.resolve.constants.StringValue;
|
||||
@@ -36,7 +36,7 @@ public class SwitchCodegenUtil {
|
||||
public static boolean checkAllItemsAreConstantsSatisfying(
|
||||
@NotNull JetWhenExpression expression,
|
||||
@NotNull BindingContext bindingContext,
|
||||
Function1<CompileTimeConstant, Boolean> predicate
|
||||
Function1<ConstantValue<?>, Boolean> predicate
|
||||
) {
|
||||
for (JetWhenEntry entry : expression.getEntries()) {
|
||||
for (JetWhenCondition condition : entry.getConditions()) {
|
||||
@@ -49,7 +49,7 @@ public class SwitchCodegenUtil {
|
||||
|
||||
if (patternExpression == null) return false;
|
||||
|
||||
CompileTimeConstant constant = ExpressionCodegen.getCompileTimeConstant(patternExpression, bindingContext);
|
||||
ConstantValue<?> constant = ExpressionCodegen.getCompileTimeConstant(patternExpression, bindingContext);
|
||||
if (constant == null || !predicate.invoke(constant)) {
|
||||
return false;
|
||||
}
|
||||
@@ -60,11 +60,11 @@ public class SwitchCodegenUtil {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Iterable<CompileTimeConstant> getAllConstants(
|
||||
public static Iterable<ConstantValue<?>> getAllConstants(
|
||||
@NotNull JetWhenExpression expression,
|
||||
@NotNull BindingContext bindingContext
|
||||
) {
|
||||
List<CompileTimeConstant> result = new ArrayList<CompileTimeConstant>();
|
||||
List<ConstantValue<?>> result = new ArrayList<ConstantValue<?>>();
|
||||
|
||||
for (JetWhenEntry entry : expression.getEntries()) {
|
||||
addConstantsFromEntry(result, entry, bindingContext);
|
||||
@@ -74,7 +74,7 @@ public class SwitchCodegenUtil {
|
||||
}
|
||||
|
||||
private static void addConstantsFromEntry(
|
||||
@NotNull List<CompileTimeConstant> result,
|
||||
@NotNull List<ConstantValue<?>> result,
|
||||
@NotNull JetWhenEntry entry,
|
||||
@NotNull BindingContext bindingContext
|
||||
) {
|
||||
@@ -89,11 +89,11 @@ public class SwitchCodegenUtil {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Iterable<CompileTimeConstant> getConstantsFromEntry(
|
||||
public static Iterable<ConstantValue<?>> getConstantsFromEntry(
|
||||
@NotNull JetWhenEntry entry,
|
||||
@NotNull BindingContext bindingContext
|
||||
) {
|
||||
List<CompileTimeConstant> result = new ArrayList<CompileTimeConstant>();
|
||||
List<ConstantValue<?>> result = new ArrayList<ConstantValue<?>>();
|
||||
addConstantsFromEntry(result, entry, bindingContext);
|
||||
return result;
|
||||
}
|
||||
@@ -132,7 +132,7 @@ public class SwitchCodegenUtil {
|
||||
@NotNull JetWhenExpression expression,
|
||||
@NotNull BindingContext bindingContext
|
||||
) {
|
||||
for (CompileTimeConstant constant : getAllConstants(expression, bindingContext)) {
|
||||
for (ConstantValue<?> constant : getAllConstants(expression, bindingContext)) {
|
||||
if (constant != null && !(constant instanceof NullValue)) return true;
|
||||
}
|
||||
|
||||
@@ -150,10 +150,10 @@ public class SwitchCodegenUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
return checkAllItemsAreConstantsSatisfying(expression, bindingContext, new Function1<CompileTimeConstant, Boolean>() {
|
||||
return checkAllItemsAreConstantsSatisfying(expression, bindingContext, new Function1<ConstantValue<?>, Boolean>() {
|
||||
@Override
|
||||
public Boolean invoke(
|
||||
@NotNull CompileTimeConstant constant
|
||||
@NotNull ConstantValue<?> constant
|
||||
) {
|
||||
return constant instanceof IntegerValueConstant;
|
||||
}
|
||||
@@ -170,10 +170,10 @@ public class SwitchCodegenUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
return checkAllItemsAreConstantsSatisfying(expression, bindingContext, new Function1<CompileTimeConstant, Boolean>() {
|
||||
return checkAllItemsAreConstantsSatisfying(expression, bindingContext, new Function1<ConstantValue<?>, Boolean>() {
|
||||
@Override
|
||||
public Boolean invoke(
|
||||
@NotNull CompileTimeConstant constant
|
||||
@NotNull ConstantValue<?> constant
|
||||
) {
|
||||
return constant instanceof StringValue || constant instanceof NullValue;
|
||||
}
|
||||
|
||||
+1
-1
@@ -113,7 +113,7 @@ public class BuiltInsSerializer(private val dependOnOldBuiltIns: Boolean) {
|
||||
// TODO: perform some kind of validation? At the moment not possible because DescriptorValidator is in compiler-tests
|
||||
// DescriptorValidator.validate(packageView)
|
||||
|
||||
val serializer = DescriptorSerializer.createTopLevel(BuiltInsSerializerExtension)
|
||||
val serializer = DescriptorSerializer.createTopLevel(BuiltInsSerializerExtension())
|
||||
|
||||
val classifierDescriptors = DescriptorSerializer.sort(packageView.memberScope.getDescriptors(DescriptorKindFilter.CLASSIFIERS))
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ public open class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
PathUtil.getKotlinPathsForCompiler()
|
||||
|
||||
messageSeverityCollector.report(CompilerMessageSeverity.LOGGING, "Using Kotlin home directory " + paths.getHomePath(), CompilerMessageLocation.NO_LOCATION)
|
||||
PerformanceCounter.setTimeCounterEnabled(arguments.reportPerf);
|
||||
|
||||
val configuration = CompilerConfiguration()
|
||||
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageSeverityCollector)
|
||||
@@ -93,7 +94,7 @@ public open class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
return INTERNAL_ERROR
|
||||
}
|
||||
catch (e: CliOptionProcessingException) {
|
||||
messageSeverityCollector.report(CompilerMessageSeverity.ERROR, e.getMessage(), CompilerMessageLocation.NO_LOCATION)
|
||||
messageSeverityCollector.report(CompilerMessageSeverity.ERROR, e.getMessage()!!, CompilerMessageLocation.NO_LOCATION)
|
||||
return INTERNAL_ERROR
|
||||
}
|
||||
catch (t: Throwable) {
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ import kotlin.properties.Delegates
|
||||
public class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager)
|
||||
: CoreJavaFileManager(myPsiManager), KotlinCliJavaFileManager {
|
||||
|
||||
private val perfCounter = PerformanceCounter("Find Java class")
|
||||
private val perfCounter = PerformanceCounter.create("Find Java class")
|
||||
private var index: JvmDependenciesIndex by Delegates.notNull()
|
||||
|
||||
public fun initIndex(packagesCache: JvmDependenciesIndex) {
|
||||
|
||||
+4
-4
@@ -314,7 +314,7 @@ public class KotlinToJVMBytecodeCompiler {
|
||||
MessageCollector collector = environment.getConfiguration().get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY);
|
||||
assert collector != null;
|
||||
|
||||
long analysisStart = PerformanceCounter.Companion.currentThreadCpuTime();
|
||||
long analysisStart = PerformanceCounter.Companion.currentTime();
|
||||
AnalyzerWithCompilerReport analyzerWithCompilerReport = new AnalyzerWithCompilerReport(collector);
|
||||
analyzerWithCompilerReport.analyzeAndReport(
|
||||
environment.getSourceFiles(), new Function0<AnalysisResult>() {
|
||||
@@ -334,7 +334,7 @@ public class KotlinToJVMBytecodeCompiler {
|
||||
}
|
||||
}
|
||||
);
|
||||
long analysisNanos = PerformanceCounter.Companion.currentThreadCpuTime() - analysisStart;
|
||||
long analysisNanos = PerformanceCounter.Companion.currentTime() - analysisStart;
|
||||
String message = "ANALYZE: " + environment.getSourceFiles().size() + " files (" +
|
||||
environment.getSourceLinesOfCode() + " lines) " +
|
||||
(targetDescription != null ? targetDescription : "") +
|
||||
@@ -395,11 +395,11 @@ public class KotlinToJVMBytecodeCompiler {
|
||||
);
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
||||
|
||||
long generationStart = PerformanceCounter.Companion.currentThreadCpuTime();
|
||||
long generationStart = PerformanceCounter.Companion.currentTime();
|
||||
|
||||
KotlinCodegenFacade.compileCorrectFiles(generationState, CompilationErrorHandler.THROW_EXCEPTION);
|
||||
|
||||
long generationNanos = PerformanceCounter.Companion.currentThreadCpuTime() - generationStart;
|
||||
long generationNanos = PerformanceCounter.Companion.currentTime() - generationStart;
|
||||
String desc = moduleId != null ? "module " + moduleId + " " : "";
|
||||
String message = "GENERATE: " + sourceFiles.size() + " files (" +
|
||||
environment.countLinesOfCode(sourceFiles) + " lines) " + desc + "in " + TimeUnit.NANOSECONDS.toMillis(generationNanos) + " ms";
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
open class DelegatePackageMemberDeclarationProvider(var delegate: PackageMemberDeclarationProvider) : PackageMemberDeclarationProvider {
|
||||
// Can't use Kotlin delegate feature because of inability to change delegate object in runtime (KT-5870)
|
||||
|
||||
override fun getAllDeclaredSubPackages() = delegate.getAllDeclaredSubPackages()
|
||||
override fun getAllDeclaredSubPackages(nameFilter: (Name) -> Boolean) = delegate.getAllDeclaredSubPackages(nameFilter)
|
||||
|
||||
override fun getPackageFiles() = delegate.getPackageFiles()
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ public fun createContainerForReplWithJava(
|
||||
moduleContext: ModuleContext, bindingTrace: BindingTrace, declarationProviderFactory: DeclarationProviderFactory,
|
||||
moduleContentScope: GlobalSearchScope, additionalFileScopeProvider: FileScopeProvider.AdditionalScopes
|
||||
): ContainerForReplWithJava = createContainer("ReplWithJava") {
|
||||
configureModule(moduleContext, KotlinJvmCheckerProvider, bindingTrace)
|
||||
configureModule(moduleContext, KotlinJvmCheckerProvider(moduleContext.module), bindingTrace)
|
||||
configureJavaTopDownAnalysis(moduleContentScope, moduleContext.project)
|
||||
|
||||
useInstance(additionalFileScopeProvider)
|
||||
|
||||
@@ -30,7 +30,6 @@ messages/**)
|
||||
-dontwarn org.xerial.snappy.SnappyBundleActivator
|
||||
-dontwarn com.intellij.util.CompressionUtil
|
||||
-dontwarn com.intellij.util.SnappyInitializer
|
||||
-dontwarn org.iq80.snappy.Snappy
|
||||
-dontwarn net.sf.cglib.**
|
||||
-dontwarn org.objectweb.asm.** # this is ASM3, the old version that we do not use
|
||||
|
||||
|
||||
@@ -17,9 +17,7 @@
|
||||
package org.jetbrains.kotlin.container
|
||||
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Modifier
|
||||
import java.lang.reflect.*
|
||||
import java.util.ArrayList
|
||||
import java.util.LinkedHashSet
|
||||
|
||||
@@ -44,17 +42,17 @@ fun Class<*>.getInfo(): ClassInfo {
|
||||
data class ClassInfo(
|
||||
val constructorInfo: ConstructorInfo?,
|
||||
val setterInfos: List<SetterInfo>,
|
||||
val registrations: List<Class<*>>
|
||||
val registrations: List<Type>
|
||||
)
|
||||
|
||||
data class ConstructorInfo(
|
||||
val constructor: Constructor<*>,
|
||||
val parameters: List<Class<*>>
|
||||
val parameters: List<Type>
|
||||
)
|
||||
|
||||
data class SetterInfo(
|
||||
val method: Method,
|
||||
val parameters: List<Class<*>>
|
||||
val parameters: List<Type>
|
||||
)
|
||||
|
||||
private fun traverseClass(c: Class<*>): ClassInfo {
|
||||
@@ -66,7 +64,7 @@ private fun getSetterInfos(c: Class<*>): List<SetterInfo> {
|
||||
for (method in c.getMethods()) {
|
||||
for (annotation in method.getDeclaredAnnotations()) {
|
||||
if (annotation.annotationType().getName().endsWith(".Inject")) {
|
||||
setterInfos.add(SetterInfo(method, method.getParameterTypes().toList()))
|
||||
setterInfos.add(SetterInfo(method, method.getGenericParameterTypes().toList()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,25 +81,37 @@ private fun getConstructorInfo(c: Class<*>): ConstructorInfo? {
|
||||
return null
|
||||
|
||||
val constructor = constructors.single()
|
||||
return ConstructorInfo(constructor, constructor.getParameterTypes().toList())
|
||||
return ConstructorInfo(constructor, constructor.getGenericParameterTypes().toList())
|
||||
}
|
||||
|
||||
|
||||
private fun collectInterfacesRecursive(cl: Class<*>, result: MutableSet<Class<*>>) {
|
||||
cl.getInterfaces().forEach {
|
||||
private fun collectInterfacesRecursive(type: Type, result: MutableSet<Type>) {
|
||||
// TODO: should apply generic substitution through hierarchy
|
||||
val klass : Class<*>? = when(type) {
|
||||
is Class<*> -> type
|
||||
is ParameterizedType -> type.getRawType() as? Class<*>
|
||||
else -> null
|
||||
}
|
||||
klass?.getGenericInterfaces()?.forEach {
|
||||
if (result.add(it)) {
|
||||
collectInterfacesRecursive(it, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRegistrations(klass: Class<*>): List<Class<*>> {
|
||||
val registrations = ArrayList<Class<*>>()
|
||||
private fun getRegistrations(klass: Class<*>): List<Type> {
|
||||
val registrations = ArrayList<Type>()
|
||||
|
||||
val superClasses = sequence(klass) { (it as Class<Any>).getSuperclass() }
|
||||
val superClasses = sequence<Type>(klass) {
|
||||
when (it) {
|
||||
is Class<*> -> it.getGenericSuperclass()
|
||||
is ParameterizedType -> (it.getRawType() as? Class<*>)?.getGenericSuperclass()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
registrations.addAll(superClasses)
|
||||
|
||||
val interfaces = LinkedHashSet<Class<*>>()
|
||||
val interfaces = LinkedHashSet<Type>()
|
||||
superClasses.forEach { collectInterfacesRecursive(it, interfaces) }
|
||||
registrations.addAll(interfaces)
|
||||
registrations.remove(javaClass<Any>())
|
||||
|
||||
@@ -16,13 +16,17 @@
|
||||
|
||||
package org.jetbrains.kotlin.container
|
||||
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.*
|
||||
|
||||
public class InstanceComponentDescriptor(val instance: Any) : ComponentDescriptor {
|
||||
|
||||
override fun getValue(): Any = instance
|
||||
override fun getRegistrations(): Iterable<Class<*>> = instance.javaClass.getInfo().registrations
|
||||
override fun getRegistrations(): Iterable<Type> = instance.javaClass.getInfo().registrations
|
||||
|
||||
override fun getDependencies(context: ValueResolveContext): Collection<Class<*>> = emptyList()
|
||||
|
||||
override fun toString(): String {
|
||||
return "Instance: ${instance.javaClass.getSimpleName()}"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,11 @@
|
||||
package org.jetbrains.kotlin.container
|
||||
|
||||
import java.io.Closeable
|
||||
import java.lang.reflect.Modifier
|
||||
import java.io.PrintStream
|
||||
import java.io.Writer
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.lang.reflect.Type
|
||||
import java.lang.reflect.WildcardType
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
class ContainerConsistencyException(message: String) : Exception(message)
|
||||
@@ -26,10 +30,9 @@ public interface ComponentContainer {
|
||||
fun createResolveContext(requestingDescriptor: ValueDescriptor): ValueResolveContext
|
||||
}
|
||||
|
||||
object DynamicComponentDescriptor : ComponentDescriptor {
|
||||
override fun getDependencies(context: ValueResolveContext): Collection<Class<*>> = throw UnsupportedOperationException()
|
||||
override fun getRegistrations(): Iterable<Class<*>> = throw UnsupportedOperationException()
|
||||
object DynamicComponentDescriptor : ValueDescriptor {
|
||||
override fun getValue(): Any = throw UnsupportedOperationException()
|
||||
override fun toString(): String = "Dynamic"
|
||||
}
|
||||
|
||||
public class StorageComponentContainer(id: String) : ComponentContainer, Closeable {
|
||||
@@ -47,22 +50,28 @@ public class StorageComponentContainer(id: String) : ComponentContainer, Closeab
|
||||
return this
|
||||
}
|
||||
|
||||
fun dump(printer: PrintStream) {
|
||||
componentStorage.dump(printer)
|
||||
}
|
||||
|
||||
override fun close() = componentStorage.dispose()
|
||||
|
||||
jvmOverloads public fun resolve(request: Class<*>, context: ValueResolveContext = unknownContext): ValueDescriptor? {
|
||||
val storageResolve = componentStorage.resolve(request, context)
|
||||
if (storageResolve != null)
|
||||
return storageResolve
|
||||
jvmOverloads public fun resolve(request: Type, context: ValueResolveContext = unknownContext): ValueDescriptor? {
|
||||
return componentStorage.resolve(request, context) ?: resolveIterable(request, context)
|
||||
}
|
||||
|
||||
val hasSinglePublicConstructor = request.getConstructors().singleOrNull()?.let { Modifier.isPublic(it.getModifiers()) } ?: false
|
||||
if (!hasSinglePublicConstructor)
|
||||
return null
|
||||
|
||||
val modifiers = request.getModifiers()
|
||||
if (Modifier.isInterface(modifiers) || Modifier.isAbstract(modifiers) || request.isPrimitive())
|
||||
return null
|
||||
|
||||
return SingletonTypeComponentDescriptor(this, request)
|
||||
private fun resolveIterable(request: Type, context: ValueResolveContext): ValueDescriptor? {
|
||||
if (request !is ParameterizedType) return null
|
||||
val rawType = request.getRawType()
|
||||
if (rawType != javaClass<Iterable<*>>()) return null
|
||||
val typeArguments = request.getActualTypeArguments()
|
||||
if (typeArguments.size() != 1) return null
|
||||
val iterableTypeArgument = typeArguments[0]
|
||||
if (!(iterableTypeArgument is WildcardType)) return null
|
||||
val upperBounds = iterableTypeArgument.getUpperBounds()
|
||||
if (upperBounds.size() != 1) return null
|
||||
val iterableType = upperBounds[0]
|
||||
return IterableDescriptor(componentStorage.resolveMultiple(iterableType, context))
|
||||
}
|
||||
|
||||
public fun resolveMultiple(request: Class<*>, context: ValueResolveContext = unknownContext): Iterable<ValueDescriptor> {
|
||||
|
||||
@@ -29,7 +29,7 @@ public fun topologicalSort<T>(items: Iterable<T>, dependencies: (T) -> Iterable<
|
||||
return
|
||||
|
||||
if (item in itemsInProgress)
|
||||
throw CycleInTopoSortException()
|
||||
return //throw CycleInTopoSortException()
|
||||
|
||||
itemsInProgress.add(item)
|
||||
|
||||
|
||||
@@ -16,14 +16,23 @@
|
||||
|
||||
package org.jetbrains.kotlin.container
|
||||
|
||||
import java.lang.reflect.*
|
||||
|
||||
public interface ValueDescriptor {
|
||||
public fun getValue(): Any
|
||||
}
|
||||
|
||||
internal interface ComponentDescriptor : ValueDescriptor {
|
||||
fun getRegistrations(): Iterable<Class<*>>
|
||||
fun getDependencies(context: ValueResolveContext): Collection<Class<*>>
|
||||
fun getRegistrations(): Iterable<Type>
|
||||
fun getDependencies(context: ValueResolveContext): Collection<Type>
|
||||
val shouldInjectProperties: Boolean
|
||||
get() = false
|
||||
}
|
||||
|
||||
public class IterableDescriptor(val descriptors: Iterable<ValueDescriptor>) : ValueDescriptor {
|
||||
override fun getValue(): Any {
|
||||
return descriptors.map { it.getValue() }
|
||||
}
|
||||
|
||||
override fun toString(): String = "Iterable: $descriptors"
|
||||
}
|
||||
@@ -18,10 +18,11 @@ package org.jetbrains.kotlin.container
|
||||
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import java.util.ArrayList
|
||||
import java.lang.reflect.*
|
||||
|
||||
internal class ComponentRegistry {
|
||||
fun buildRegistrationMap(descriptors: Collection<ComponentDescriptor>): MultiMap<Class<*>, ComponentDescriptor> {
|
||||
val registrationMap = MultiMap<Class<*>, ComponentDescriptor>()
|
||||
fun buildRegistrationMap(descriptors: Collection<ComponentDescriptor>): MultiMap<Type, ComponentDescriptor> {
|
||||
val registrationMap = MultiMap<Type, ComponentDescriptor>()
|
||||
for (descriptor in descriptors) {
|
||||
for (registration in descriptor.getRegistrations()) {
|
||||
registrationMap.putValue(registration, descriptor)
|
||||
@@ -30,13 +31,13 @@ internal class ComponentRegistry {
|
||||
return registrationMap
|
||||
}
|
||||
|
||||
private var registrationMap = MultiMap.createLinkedSet<Class<*>, ComponentDescriptor>()
|
||||
private var registrationMap = MultiMap.createLinkedSet<Type, ComponentDescriptor>()
|
||||
|
||||
public fun addAll(descriptors: Collection<ComponentDescriptor>) {
|
||||
registrationMap.putAllValues(buildRegistrationMap(descriptors))
|
||||
}
|
||||
|
||||
public fun tryGetEntry(request: Class<*>): Collection<ComponentDescriptor> {
|
||||
public fun tryGetEntry(request: Type): Collection<ComponentDescriptor> {
|
||||
return registrationMap.get(request)
|
||||
}
|
||||
}
|
||||
@@ -23,15 +23,15 @@ import java.lang.reflect.Type
|
||||
import java.util.ArrayList
|
||||
|
||||
public interface ValueResolver {
|
||||
fun resolve(request: Class<*>, context: ValueResolveContext): ValueDescriptor?
|
||||
fun resolve(request: Type, context: ValueResolveContext): ValueDescriptor?
|
||||
}
|
||||
|
||||
public interface ValueResolveContext {
|
||||
fun resolve(registration: Class<*>): ValueDescriptor?
|
||||
fun resolve(registration: Type): ValueDescriptor?
|
||||
}
|
||||
|
||||
internal class ComponentResolveContext(val container: StorageComponentContainer, val requestingDescriptor: ValueDescriptor) : ValueResolveContext {
|
||||
override fun resolve(registration: Class<*>): ValueDescriptor? = container.resolve(registration, this)
|
||||
override fun resolve(registration: Type): ValueDescriptor? = container.resolve(registration, this)
|
||||
|
||||
override fun toString(): String = "for $requestingDescriptor in $container"
|
||||
}
|
||||
@@ -54,10 +54,10 @@ fun Class<*>.bindToConstructor(context: ValueResolveContext): ConstructorBinding
|
||||
}
|
||||
|
||||
fun Method.bindToMethod(context: ValueResolveContext): MethodBinding {
|
||||
return MethodBinding(this, bindArguments(getParameterTypes().toList(), context))
|
||||
return MethodBinding(this, bindArguments(getGenericParameterTypes().toList(), context))
|
||||
}
|
||||
|
||||
private fun Member.bindArguments(parameters: List<Class<*>>, context: ValueResolveContext): List<ValueDescriptor> {
|
||||
private fun Member.bindArguments(parameters: List<Type>, context: ValueResolveContext): List<ValueDescriptor> {
|
||||
val bound = ArrayList<ValueDescriptor>(parameters.size())
|
||||
var unsatisfied: MutableList<Type>? = null
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.container
|
||||
import java.io.Closeable
|
||||
import java.util.ArrayList
|
||||
import kotlin.properties.Delegates
|
||||
import java.lang.reflect.*
|
||||
|
||||
enum class ComponentState {
|
||||
Null,
|
||||
@@ -116,7 +117,9 @@ public abstract class SingletonDescriptor(val container: ComponentContainer) : C
|
||||
}
|
||||
|
||||
public abstract class SingletonComponentDescriptor(container: ComponentContainer, val klass: Class<*>) : SingletonDescriptor(container) {
|
||||
public override fun getRegistrations(): Iterable<Class<*>> = klass.getInfo().registrations
|
||||
override fun toString(): String = "Singleton: ${klass.getSimpleName()}"
|
||||
|
||||
public override fun getRegistrations(): Iterable<Type> = klass.getInfo().registrations
|
||||
}
|
||||
|
||||
public class SingletonTypeComponentDescriptor(container: ComponentContainer, klass: Class<*>) : SingletonComponentDescriptor(container, klass) {
|
||||
@@ -139,7 +142,7 @@ public class SingletonTypeComponentDescriptor(container: ComponentContainer, kla
|
||||
return instance
|
||||
}
|
||||
|
||||
override fun getDependencies(context: ValueResolveContext): Collection<Class<*>> {
|
||||
override fun getDependencies(context: ValueResolveContext): Collection<Type> {
|
||||
val classInfo = klass.getInfo()
|
||||
return classInfo.constructorInfo?.parameters.orEmpty() + classInfo.setterInfos.flatMap { it.parameters }
|
||||
}
|
||||
|
||||
@@ -18,7 +18,10 @@ package org.jetbrains.kotlin.container
|
||||
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import java.io.Closeable
|
||||
import java.io.PrintStream
|
||||
import java.lang.reflect.Modifier
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.lang.reflect.Type
|
||||
import java.util.ArrayList
|
||||
import java.util.HashSet
|
||||
import java.util.LinkedHashSet
|
||||
@@ -30,13 +33,15 @@ public enum class ComponentStorageState {
|
||||
Disposed
|
||||
}
|
||||
|
||||
class InvalidCardinalityException(message: String, val descriptors: Collection<ComponentDescriptor>) : Exception(message)
|
||||
|
||||
public class ComponentStorage(val myId: String) : ValueResolver {
|
||||
var state = ComponentStorageState.Initial
|
||||
val registry = ComponentRegistry()
|
||||
val descriptors = LinkedHashSet<ComponentDescriptor>()
|
||||
val dependencies = MultiMap.createLinkedSet<ComponentDescriptor, Class<*>>()
|
||||
val dependencies = MultiMap.createLinkedSet<ComponentDescriptor, Type>()
|
||||
|
||||
override fun resolve(request: Class<*>, context: ValueResolveContext): ValueDescriptor? {
|
||||
override fun resolve(request: Type, context: ValueResolveContext): ValueDescriptor? {
|
||||
if (state == ComponentStorageState.Initial)
|
||||
throw ContainerConsistencyException("Container was not composed before resolving")
|
||||
|
||||
@@ -44,12 +49,14 @@ public class ComponentStorage(val myId: String) : ValueResolver {
|
||||
if (entry.isNotEmpty()) {
|
||||
registerDependency(request, context)
|
||||
|
||||
if (entry.size() > 1)
|
||||
throw InvalidCardinalityException("Request $request cannot be satisfied because there is more than one type registered", entry)
|
||||
return entry.singleOrNull()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun registerDependency(request: Class<*>, context: ValueResolveContext) {
|
||||
private fun registerDependency(request: Type, context: ValueResolveContext) {
|
||||
if (context is ComponentResolveContext) {
|
||||
val descriptor = context.requestingDescriptor
|
||||
if (descriptor is ComponentDescriptor) {
|
||||
@@ -58,7 +65,30 @@ public class ComponentStorage(val myId: String) : ValueResolver {
|
||||
}
|
||||
}
|
||||
|
||||
public fun resolveMultiple(request: Class<*>, context: ValueResolveContext): Iterable<ValueDescriptor> {
|
||||
public fun dump(printer: PrintStream): Unit = with (printer) {
|
||||
val heading = "Container: $myId"
|
||||
println(heading)
|
||||
println("=".repeat(heading.length()))
|
||||
println()
|
||||
getDescriptorsInDisposeOrder().forEach { descriptor ->
|
||||
println(descriptor)
|
||||
dependencies[descriptor].forEach {
|
||||
print(" -> ")
|
||||
val typeName = it.toString()
|
||||
print(typeName.substringBefore(" ")) // interface, class
|
||||
print(" ")
|
||||
print(typeName.substringAfterLast(".")) // name
|
||||
val resolve = registry.tryGetEntry(it)
|
||||
print(" as ")
|
||||
print(resolve)
|
||||
println()
|
||||
}
|
||||
println()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public fun resolveMultiple(request: Type, context: ValueResolveContext): Iterable<ValueDescriptor> {
|
||||
registerDependency(request, context)
|
||||
return registry.tryGetEntry(request)
|
||||
}
|
||||
@@ -89,7 +119,7 @@ public class ComponentStorage(val myId: String) : ValueResolver {
|
||||
|
||||
registry.addAll(descriptors)
|
||||
|
||||
val implicits = inspectDependenciesAndRegisterImplicits(context, descriptors)
|
||||
val implicits = inspectDependenciesAndRegisterAdhoc(context, descriptors)
|
||||
|
||||
injectProperties(context, descriptors + implicits)
|
||||
}
|
||||
@@ -97,35 +127,43 @@ public class ComponentStorage(val myId: String) : ValueResolver {
|
||||
private fun injectProperties(context: ComponentResolveContext, components: Collection<ComponentDescriptor>) {
|
||||
for (component in components) {
|
||||
if (component.shouldInjectProperties) {
|
||||
injectProperties(component.getValue(), context)
|
||||
injectProperties(component.getValue(), context.container.createResolveContext(component))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun inspectDependenciesAndRegisterImplicits(context: ComponentResolveContext, descriptors: Collection<ComponentDescriptor>): LinkedHashSet<ComponentDescriptor> {
|
||||
val implicits = LinkedHashSet<ComponentDescriptor>()
|
||||
val visitedTypes = HashSet<Class<*>>()
|
||||
private fun inspectDependenciesAndRegisterAdhoc(context: ComponentResolveContext, descriptors: Collection<ComponentDescriptor>): LinkedHashSet<ComponentDescriptor> {
|
||||
val adhoc = LinkedHashSet<ComponentDescriptor>()
|
||||
val visitedTypes = HashSet<Type>()
|
||||
for (descriptor in descriptors) {
|
||||
registerImplicits(context, descriptor, visitedTypes, implicits)
|
||||
collectAdhocComponents(context, descriptor, visitedTypes, adhoc)
|
||||
}
|
||||
registry.addAll(implicits)
|
||||
return implicits
|
||||
registry.addAll(adhoc)
|
||||
return adhoc
|
||||
}
|
||||
|
||||
private fun registerImplicits(
|
||||
context: ComponentResolveContext, descriptor: ComponentDescriptor,
|
||||
visitedTypes: HashSet<Class<*>>, implicitDescriptors: LinkedHashSet<ComponentDescriptor>
|
||||
private fun collectAdhocComponents(context: ComponentResolveContext, descriptor: ComponentDescriptor,
|
||||
visitedTypes: HashSet<Type>, adhocDescriptors: LinkedHashSet<ComponentDescriptor>
|
||||
) {
|
||||
val dependencies = descriptor.getDependencies(context)
|
||||
for (type in dependencies) {
|
||||
if (!visitedTypes.add(type)) continue
|
||||
if (!visitedTypes.add(type))
|
||||
continue
|
||||
|
||||
val entry = registry.tryGetEntry(type)
|
||||
if (entry.isEmpty()) {
|
||||
if (!Modifier.isAbstract(type.getModifiers()) && !type.isPrimitive()) {
|
||||
val implicitDescriptor = SingletonTypeComponentDescriptor(context.container, type)
|
||||
implicitDescriptors.add(implicitDescriptor)
|
||||
registerImplicits(context, implicitDescriptor, visitedTypes, implicitDescriptors)
|
||||
val rawType: Class<*>? = when (type) {
|
||||
is Class<*> -> type
|
||||
is ParameterizedType -> type.getRawType() as? Class<*>
|
||||
else -> null
|
||||
}
|
||||
if (rawType == null)
|
||||
continue
|
||||
|
||||
if (!Modifier.isAbstract(rawType.getModifiers()) && !rawType.isPrimitive()) {
|
||||
val implicitDescriptor = SingletonTypeComponentDescriptor(context.container, rawType)
|
||||
adhocDescriptors.add(implicitDescriptor)
|
||||
collectAdhocComponents(context, implicitDescriptor, visitedTypes, adhocDescriptors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+71
-43
@@ -17,53 +17,11 @@
|
||||
package org.jetbrains.kotlin.container.tests
|
||||
|
||||
import org.jetbrains.kotlin.container.*
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import java.io.Closeable
|
||||
import javax.inject.Inject
|
||||
import kotlin.test.*
|
||||
|
||||
interface TestComponentInterface {
|
||||
public val disposed: Boolean
|
||||
fun foo()
|
||||
}
|
||||
|
||||
interface TestClientComponentInterface
|
||||
|
||||
class TestComponent : TestComponentInterface, Closeable {
|
||||
public override var disposed: Boolean = false
|
||||
override fun close() {
|
||||
disposed = true
|
||||
}
|
||||
|
||||
override fun foo() {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
|
||||
class ManualTestComponent(val name: String) : TestComponentInterface, Closeable {
|
||||
public override var disposed: Boolean = false
|
||||
override fun close() {
|
||||
disposed = true
|
||||
}
|
||||
|
||||
override fun foo() {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
|
||||
class TestClientComponent(val dep: TestComponentInterface) : TestClientComponentInterface, Closeable {
|
||||
override fun close() {
|
||||
if (dep.disposed)
|
||||
throw Exception("Dependency shouldn't be disposed before dependee")
|
||||
disposed = true
|
||||
}
|
||||
|
||||
var disposed: Boolean = false
|
||||
}
|
||||
|
||||
class TestClientComponent2() : TestClientComponentInterface {
|
||||
}
|
||||
|
||||
class ComponentContainerTest {
|
||||
Test fun should_throw_when_not_composed() {
|
||||
val container = StorageComponentContainer("test")
|
||||
@@ -155,6 +113,76 @@ class ComponentContainerTest {
|
||||
}
|
||||
}
|
||||
|
||||
Test fun should_resolve_adhoc_types_to_same_instances() {
|
||||
createContainer("test") {
|
||||
useImpl<TestAdhocComponent1>()
|
||||
useImpl<TestAdhocComponent2>()
|
||||
}.use {
|
||||
val descriptor1 = it.resolve<TestAdhocComponent1>()
|
||||
assertNotNull(descriptor1)
|
||||
val descriptor2 = it.resolve<TestAdhocComponent2>()
|
||||
assertNotNull(descriptor2)
|
||||
val component1 = descriptor1!!.getValue() as TestAdhocComponent1
|
||||
val component2 = descriptor2!!.getValue() as TestAdhocComponent2
|
||||
assertTrue(component1.service === component2.service)
|
||||
}
|
||||
}
|
||||
|
||||
Test fun should_resolve_iterable() {
|
||||
createContainer("test") {
|
||||
useImpl<TestComponent>()
|
||||
useImpl<TestClientComponent>()
|
||||
useImpl<TestClientComponent2>()
|
||||
useImpl<TestIterableComponent>()
|
||||
}.use {
|
||||
val descriptor = it.resolve<TestIterableComponent>()
|
||||
assertNotNull(descriptor)
|
||||
val iterableComponent = descriptor!!.getValue() as TestIterableComponent
|
||||
assertEquals(2, iterableComponent.components.count())
|
||||
assertTrue(iterableComponent.components.any { it is TestClientComponent })
|
||||
assertTrue(iterableComponent.components.any { it is TestClientComponent2 })
|
||||
}
|
||||
}
|
||||
|
||||
Test fun should_distinguish_generic() {
|
||||
createContainer("test") {
|
||||
useImpl<TestGenericClient>()
|
||||
useImpl<TestStringComponent>()
|
||||
useImpl<TestIntComponent>()
|
||||
}.use {
|
||||
val descriptor = it.resolve<TestGenericClient>()
|
||||
assertNotNull(descriptor)
|
||||
val genericClient = descriptor!!.getValue() as TestGenericClient
|
||||
assertTrue(genericClient.component1 is TestStringComponent)
|
||||
assertTrue(genericClient.component2 is TestIntComponent)
|
||||
}
|
||||
}
|
||||
|
||||
Ignore("Need generic type substitution")
|
||||
Test fun should_resolve_generic_adhoc() {
|
||||
createContainer("test") {
|
||||
useImpl<TestImplicitGenericClient>()
|
||||
}.use {
|
||||
val descriptor = it.resolve<TestImplicitGenericClient>()
|
||||
assertNotNull(descriptor)
|
||||
val genericClient = descriptor!!.getValue() as TestImplicitGenericClient
|
||||
assertTrue(genericClient.component is TestImplicitGeneric)
|
||||
}
|
||||
}
|
||||
|
||||
Test fun should_fail_with_invalid_cardinality() {
|
||||
createContainer("test") {
|
||||
useImpl<TestComponent>()
|
||||
useInstance(TestComponent())
|
||||
}.use {
|
||||
assertTrue {
|
||||
fails {
|
||||
it.resolve<TestComponent>()
|
||||
} is InvalidCardinalityException
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class WithSetters {
|
||||
var isSetterCalled = false
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.container.tests
|
||||
|
||||
import java.io.*
|
||||
|
||||
interface TestComponentInterface {
|
||||
public val disposed: Boolean
|
||||
fun foo()
|
||||
}
|
||||
|
||||
interface TestClientComponentInterface {
|
||||
}
|
||||
|
||||
class TestComponent : TestComponentInterface, Closeable {
|
||||
public override var disposed: Boolean = false
|
||||
override fun close() {
|
||||
disposed = true
|
||||
}
|
||||
|
||||
override fun foo() {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
|
||||
class ManualTestComponent(val name: String) : TestComponentInterface, Closeable {
|
||||
public override var disposed: Boolean = false
|
||||
override fun close() {
|
||||
disposed = true
|
||||
}
|
||||
|
||||
override fun foo() {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
|
||||
class TestClientComponent(val dep: TestComponentInterface) : TestClientComponentInterface, Closeable {
|
||||
override fun close() {
|
||||
if (dep.disposed)
|
||||
throw Exception("Dependency shouldn't be disposed before dependee")
|
||||
disposed = true
|
||||
}
|
||||
|
||||
var disposed: Boolean = false
|
||||
}
|
||||
|
||||
class TestClientComponent2() : TestClientComponentInterface {
|
||||
}
|
||||
|
||||
class TestAdhocComponentService
|
||||
class TestAdhocComponent1(val service: TestAdhocComponentService) {
|
||||
|
||||
}
|
||||
|
||||
class TestAdhocComponent2(val service: TestAdhocComponentService) {
|
||||
|
||||
}
|
||||
|
||||
class TestIterableComponent(val components: Iterable<TestClientComponentInterface>)
|
||||
|
||||
interface TestGenericComponent<T>
|
||||
|
||||
class TestGenericClient(val component1 : TestGenericComponent<String>, val component2: TestGenericComponent<Int>)
|
||||
class TestStringComponent : TestGenericComponent<String>
|
||||
class TestIntComponent : TestGenericComponent<Int>
|
||||
|
||||
class TestImplicitGeneric<T>()
|
||||
class TestImplicitGenericClient(val component: TestImplicitGeneric<String>)
|
||||
@@ -13,5 +13,6 @@
|
||||
<orderEntry type="module" module-name="deserialization" />
|
||||
<orderEntry type="module" module-name="descriptor.loader.java" exported="" />
|
||||
<orderEntry type="module" module-name="util" />
|
||||
<orderEntry type="module" module-name="util.runtime" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.resolve.jvm.JavaLazyAnalyzerPostConstruct
|
||||
import org.jetbrains.kotlin.resolve.lazy.FileScopeProviderImpl
|
||||
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
|
||||
import org.jetbrains.kotlin.synthetic.AdditionalScopesWithJavaSyntheticExtensions
|
||||
|
||||
public fun StorageComponentContainer.configureJavaTopDownAnalysis(moduleContentScope: GlobalSearchScope, project: Project) {
|
||||
useInstance(moduleContentScope)
|
||||
@@ -65,13 +66,14 @@ public fun StorageComponentContainer.configureJavaTopDownAnalysis(moduleContentS
|
||||
useImpl<JavaSourceElementFactoryImpl>()
|
||||
useImpl<JavaLazyAnalyzerPostConstruct>()
|
||||
useImpl<JavaFlexibleTypeCapabilitiesProvider>()
|
||||
useImpl<AdditionalScopesWithJavaSyntheticExtensions>()
|
||||
}
|
||||
|
||||
public fun createContainerForLazyResolveWithJava(
|
||||
moduleContext: ModuleContext, bindingTrace: BindingTrace, declarationProviderFactory: DeclarationProviderFactory,
|
||||
moduleContentScope: GlobalSearchScope, moduleClassResolver: ModuleClassResolver
|
||||
): Pair<ResolveSession, JavaDescriptorResolver> = createContainer("LazyResolveWithJava") {
|
||||
configureModule(moduleContext, KotlinJvmCheckerProvider, bindingTrace)
|
||||
configureModule(moduleContext, KotlinJvmCheckerProvider(moduleContext.module), bindingTrace)
|
||||
configureJavaTopDownAnalysis(moduleContentScope, moduleContext.project)
|
||||
|
||||
useInstance(moduleClassResolver)
|
||||
@@ -92,8 +94,9 @@ public fun createContainerForTopDownAnalyzerForJvm(
|
||||
declarationProviderFactory: DeclarationProviderFactory,
|
||||
moduleContentScope: GlobalSearchScope
|
||||
): ContainerForTopDownAnalyzerForJvm = createContainer("TopDownAnalyzerForJvm") {
|
||||
configureModule(moduleContext, KotlinJvmCheckerProvider, bindingTrace)
|
||||
configureModule(moduleContext, KotlinJvmCheckerProvider(moduleContext.module), bindingTrace)
|
||||
configureJavaTopDownAnalysis(moduleContentScope, moduleContext.project)
|
||||
|
||||
useInstance(declarationProviderFactory)
|
||||
useInstance(BodyResolveCache.ThrowException)
|
||||
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.jvm.bindingContextSlices.RUNTIME_ASSERTION_INFO
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker
|
||||
import org.jetbrains.kotlin.types.upperIfFlexible
|
||||
import kotlin.platform.platformStatic
|
||||
|
||||
public class RuntimeAssertionInfo(public val needNotNullAssertion: Boolean, public val message: String) {
|
||||
public interface DataFlowExtras {
|
||||
class OnlyMessage(message: String) : DataFlowExtras {
|
||||
override val canBeNull: Boolean get() = true
|
||||
override val possibleTypes: Set<JetType> get() = setOf()
|
||||
override val presentableText: String = message
|
||||
}
|
||||
|
||||
val canBeNull: Boolean
|
||||
val possibleTypes: Set<JetType>
|
||||
val presentableText: String
|
||||
}
|
||||
|
||||
companion object {
|
||||
platformStatic public fun create(
|
||||
expectedType: JetType,
|
||||
expressionType: JetType,
|
||||
dataFlowExtras: DataFlowExtras
|
||||
): RuntimeAssertionInfo? {
|
||||
fun assertNotNull(): Boolean {
|
||||
if (expectedType.isError() || expressionType.isError()) return false
|
||||
|
||||
// T : Any, T! = T..T?
|
||||
// Let T$ will be copy of T! with enhanced nullability.
|
||||
// Cases when nullability assertion needed: T! -> T, T$ -> T
|
||||
|
||||
// Expected type either T?, T! or T$
|
||||
if (TypeUtils.isNullableType(expectedType) || expectedType.hasEnhancedNullability()) return false
|
||||
|
||||
// Expression type is not nullable and not enhanced (neither T?, T! or T$)
|
||||
val isExpressionTypeNullable = TypeUtils.isNullableType(expressionType)
|
||||
if (!isExpressionTypeNullable && !expressionType.hasEnhancedNullability()) return false
|
||||
|
||||
// Smart-cast T! or T?
|
||||
if (!dataFlowExtras.canBeNull && isExpressionTypeNullable) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return if (assertNotNull())
|
||||
RuntimeAssertionInfo(needNotNullAssertion = true, message = dataFlowExtras.presentableText)
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
private fun JetType.hasEnhancedNullability()
|
||||
= getAnnotations().findAnnotation(JvmAnnotationNames.ENHANCED_NULLABILITY_ANNOTATION) != null
|
||||
}
|
||||
}
|
||||
|
||||
public object RuntimeAssertionsTypeChecker : AdditionalTypeChecker {
|
||||
override fun checkType(expression: JetExpression, expressionType: JetType, c: ResolutionContext<*>) {
|
||||
if (TypeUtils.noExpectedType(c.expectedType)) return
|
||||
|
||||
val assertionInfo = RuntimeAssertionInfo.create(
|
||||
c.expectedType,
|
||||
expressionType,
|
||||
object : RuntimeAssertionInfo.DataFlowExtras {
|
||||
override val canBeNull: Boolean
|
||||
get() = c.dataFlowInfo.getNullability(dataFlowValue).canBeNull()
|
||||
override val possibleTypes: Set<JetType>
|
||||
get() = c.dataFlowInfo.getPossibleTypes(dataFlowValue)
|
||||
override val presentableText: String
|
||||
get() = StringUtil.trimMiddle(expression.getText(), 50)
|
||||
|
||||
private val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, expressionType, c)
|
||||
}
|
||||
)
|
||||
|
||||
if (assertionInfo != null) {
|
||||
c.trace.record(RUNTIME_ASSERTION_INFO, expression, assertionInfo)
|
||||
}
|
||||
}
|
||||
|
||||
override fun checkReceiver(
|
||||
receiverParameter: ReceiverParameterDescriptor,
|
||||
receiverArgument: ReceiverValue,
|
||||
safeAccess: Boolean,
|
||||
c: CallResolutionContext<*>
|
||||
) { }
|
||||
}
|
||||
+8
-9
@@ -14,14 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlin.reflect
|
||||
package org.jetbrains.kotlin.jvm.bindingContextSlices
|
||||
|
||||
/**
|
||||
* Represents a variable declared in a package.
|
||||
*/
|
||||
public interface KTopLevelVariable<out R> : KVariable<R>, KTopLevelProperty<R>
|
||||
import org.jetbrains.kotlin.jvm.RuntimeAssertionInfo
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.util.slicedMap.BasicWritableSlice
|
||||
import org.jetbrains.kotlin.util.slicedMap.RewritePolicy
|
||||
import org.jetbrains.kotlin.util.slicedMap.WritableSlice
|
||||
import org.jetbrains.kotlin.utils.DO_NOTHING
|
||||
|
||||
/**
|
||||
* Represents a package variable declared as a `var`.
|
||||
*/
|
||||
public interface KMutableTopLevelVariable<R> : KTopLevelVariable<R>, KMutableVariable<R>, KMutableTopLevelProperty<R>
|
||||
public val RUNTIME_ASSERTION_INFO: WritableSlice<JetExpression, RuntimeAssertionInfo> = BasicWritableSlice(RewritePolicy.DO_NOTHING)
|
||||
+1
-8
@@ -22,23 +22,16 @@ import org.jetbrains.kotlin.load.java.structure.impl.*
|
||||
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
|
||||
import org.jetbrains.kotlin.resolve.lazy.ResolveSessionUtils
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import javax.inject.Inject
|
||||
import kotlin.properties.Delegates
|
||||
import org.jetbrains.kotlin.name.tail
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.*
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils
|
||||
|
||||
public class LazyResolveBasedCache : JavaResolverCache {
|
||||
private var resolveSession by Delegates.notNull<ResolveSession>()
|
||||
public class LazyResolveBasedCache(private val resolveSession: ResolveSession) : JavaResolverCache {
|
||||
|
||||
private val trace: BindingTrace get() = resolveSession.getTrace()
|
||||
|
||||
Inject
|
||||
public fun setSession(resolveSession: ResolveSession) {
|
||||
this.resolveSession = resolveSession
|
||||
}
|
||||
|
||||
override fun getClassResolvedFromSource(fqName: FqName): ClassDescriptor? {
|
||||
return trace.get(FQNAME_TO_CLASS_DESCRIPTOR, fqName.toUnsafe()) ?: findInPackageFragments(fqName)
|
||||
}
|
||||
|
||||
+15
-8
@@ -24,8 +24,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaAnnotationOwner;
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaAnnotationImpl;
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaAnnotationOwnerImpl;
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaElementCollectionFromPsiArrayUtil;
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaModifierListOwnerImpl;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -35,18 +35,25 @@ public class PsiBasedExternalAnnotationResolver implements ExternalAnnotationRes
|
||||
@Nullable
|
||||
@Override
|
||||
public JavaAnnotation findExternalAnnotation(@NotNull JavaAnnotationOwner owner, @NotNull FqName fqName) {
|
||||
PsiAnnotation psiAnnotation = findExternalAnnotation(((JavaAnnotationOwnerImpl) owner).getPsi(), fqName);
|
||||
return psiAnnotation == null ? null : new JavaAnnotationImpl(psiAnnotation);
|
||||
if (owner instanceof JavaModifierListOwnerImpl) {
|
||||
JavaModifierListOwnerImpl modifierListOwner = (JavaModifierListOwnerImpl) owner;
|
||||
PsiAnnotation psiAnnotation = findExternalAnnotation(modifierListOwner.getPsi(), fqName);
|
||||
return psiAnnotation == null ? null : new JavaAnnotationImpl(psiAnnotation);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<JavaAnnotation> findExternalAnnotations(@NotNull JavaAnnotationOwner owner) {
|
||||
PsiModifierListOwner psiOwner = ((JavaAnnotationOwnerImpl) owner).getPsi();
|
||||
PsiAnnotation[] annotations = ExternalAnnotationsManager.getInstance(psiOwner.getProject()).findExternalAnnotations(psiOwner);
|
||||
return annotations == null
|
||||
? Collections.<JavaAnnotation>emptyList()
|
||||
: JavaElementCollectionFromPsiArrayUtil.annotations(annotations);
|
||||
if (owner instanceof JavaModifierListOwnerImpl) {
|
||||
PsiModifierListOwner psiOwner = ((JavaModifierListOwnerImpl) owner).getPsi();
|
||||
PsiAnnotation[] annotations = ExternalAnnotationsManager.getInstance(psiOwner.getProject()).findExternalAnnotations(psiOwner);
|
||||
return annotations == null
|
||||
? Collections.<JavaAnnotation>emptyList()
|
||||
: JavaElementCollectionFromPsiArrayUtil.annotations(annotations);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
+4
-13
@@ -26,9 +26,7 @@ import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter
|
||||
import org.jetbrains.kotlin.util.slicedMap.Slices
|
||||
import org.jetbrains.kotlin.util.slicedMap.WritableSlice
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
public class TraceBasedErrorReporter : ErrorReporter {
|
||||
public class TraceBasedErrorReporter(private val trace: BindingTrace) : ErrorReporter {
|
||||
|
||||
companion object {
|
||||
private val LOG = Logger.getInstance(javaClass<TraceBasedErrorReporter>())
|
||||
@@ -43,24 +41,17 @@ public class TraceBasedErrorReporter : ErrorReporter {
|
||||
public val classId: ClassId
|
||||
)
|
||||
|
||||
private var trace: BindingTrace? = null
|
||||
|
||||
Inject
|
||||
public fun setTrace(trace: BindingTrace) {
|
||||
this.trace = trace
|
||||
}
|
||||
|
||||
override fun reportIncompatibleAbiVersion(classId: ClassId, filePath: String, actualVersion: Int) {
|
||||
trace!!.record(ABI_VERSION_ERRORS, filePath, AbiVersionErrorData(actualVersion, classId))
|
||||
trace.record(ABI_VERSION_ERRORS, filePath, AbiVersionErrorData(actualVersion, classId))
|
||||
}
|
||||
|
||||
override fun reportIncompleteHierarchy(descriptor: ClassDescriptor, unresolvedSuperClasses: List<String>) {
|
||||
// TODO: MutableList is a workaround for KT-5792 Covariant types in Kotlin translated to wildcard types in Java
|
||||
trace!!.record(INCOMPLETE_HIERARCHY, descriptor, unresolvedSuperClasses as MutableList)
|
||||
trace.record(INCOMPLETE_HIERARCHY, descriptor, unresolvedSuperClasses as MutableList)
|
||||
}
|
||||
|
||||
override fun reportCannotInferVisibility(descriptor: CallableMemberDescriptor) {
|
||||
OverrideResolver.createCannotInferVisibilityReporter(trace!!).invoke(descriptor)
|
||||
OverrideResolver.createCannotInferVisibilityReporter(trace).invoke(descriptor)
|
||||
}
|
||||
|
||||
override fun reportLoadingError(message: String, exception: Exception?) {
|
||||
|
||||
+11
-17
@@ -35,28 +35,22 @@ import org.jetbrains.kotlin.resolve.jvm.kotlinSignature.AlternativeMethodSignatu
|
||||
import org.jetbrains.kotlin.resolve.jvm.kotlinSignature.SignaturesPropagationData;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class TraceBasedExternalSignatureResolver implements ExternalSignatureResolver {
|
||||
private BindingTrace trace;
|
||||
private ExternalAnnotationResolver externalAnnotationResolver;
|
||||
private Project project;
|
||||
@NotNull private final BindingTrace trace;
|
||||
@NotNull private final ExternalAnnotationResolver externalAnnotationResolver;
|
||||
@NotNull private final Project project;
|
||||
|
||||
@Inject
|
||||
public void setTrace(BindingTrace trace) {
|
||||
this.trace = trace;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setExternalAnnotationResolver(ExternalAnnotationResolver externalAnnotationResolver) {
|
||||
public TraceBasedExternalSignatureResolver(
|
||||
@NotNull ExternalAnnotationResolver externalAnnotationResolver,
|
||||
@NotNull Project project,
|
||||
@NotNull BindingTrace trace
|
||||
) {
|
||||
this.externalAnnotationResolver = externalAnnotationResolver;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setProject(Project project) {
|
||||
this.project = project;
|
||||
this.trace = trace;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,6 +126,6 @@ public class TraceBasedExternalSignatureResolver implements ExternalSignatureRes
|
||||
|
||||
@Override
|
||||
public void reportSignatureErrors(@NotNull CallableMemberDescriptor descriptor, @NotNull List<String> signatureErrors) {
|
||||
trace.record(JavaBindingContext.LOAD_FROM_JAVA_SIGNATURE_ERRORS, descriptor, signatureErrors);
|
||||
trace.record(JavaBindingContext.LOAD_FROM_JAVA_SIGNATURE_ERRORS, descriptor.getOriginal(), signatureErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
-2
@@ -17,6 +17,10 @@
|
||||
package org.jetbrains.kotlin.load.java.sam;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.SamAdapterDescriptor;
|
||||
|
||||
@@ -24,8 +28,17 @@ import org.jetbrains.kotlin.load.java.descriptors.SamAdapterDescriptor;
|
||||
private final JavaMethodDescriptor declaration;
|
||||
|
||||
public SamAdapterFunctionDescriptor(@NotNull JavaMethodDescriptor declaration) {
|
||||
super(declaration.getContainingDeclaration(), null, declaration.getAnnotations(),
|
||||
declaration.getName(), Kind.SYNTHESIZED, declaration.getSource());
|
||||
this(declaration.getContainingDeclaration(), null, Kind.SYNTHESIZED, declaration);
|
||||
}
|
||||
|
||||
private SamAdapterFunctionDescriptor(
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
@Nullable SimpleFunctionDescriptor original,
|
||||
@NotNull Kind kind,
|
||||
@NotNull JavaMethodDescriptor declaration
|
||||
) {
|
||||
super(containingDeclaration, original, declaration.getAnnotations(),
|
||||
declaration.getName(), kind, declaration.getSource());
|
||||
this.declaration = declaration;
|
||||
setHasStableParameterNames(declaration.hasStableParameterNames());
|
||||
setHasSynthesizedParameterNames(declaration.hasSynthesizedParameterNames());
|
||||
@@ -36,4 +49,14 @@ import org.jetbrains.kotlin.load.java.descriptors.SamAdapterDescriptor;
|
||||
public JavaMethodDescriptor getOriginForSam() {
|
||||
return declaration;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected JavaMethodDescriptor createSubstitutedCopy(
|
||||
@NotNull DeclarationDescriptor newOwner,
|
||||
@Nullable FunctionDescriptor original,
|
||||
@NotNull Kind kind
|
||||
) {
|
||||
return new SamAdapterFunctionDescriptor(newOwner, (SimpleFunctionDescriptor) original, kind, declaration);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-6
@@ -30,7 +30,7 @@ import java.util.List;
|
||||
public class SamAdapterOverridabilityCondition implements ExternalOverridabilityCondition {
|
||||
@Override
|
||||
public boolean isOverridable(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
|
||||
if (subDescriptor instanceof PropertyDescriptor) {
|
||||
if (!(subDescriptor instanceof SimpleFunctionDescriptor)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -50,19 +50,27 @@ public class SamAdapterOverridabilityCondition implements ExternalOverridability
|
||||
|
||||
for (ValueParameterDescriptor param1 : parameters1) {
|
||||
ValueParameterDescriptor param2 = parameters2.get(param1.getIndex());
|
||||
if (!equalClasses(param2.getType(), param1.getType())) {
|
||||
if (differentClasses(param2.getType(), param1.getType())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean equalClasses(@NotNull JetType type1, @NotNull JetType type2) {
|
||||
private static boolean differentClasses(@NotNull JetType type1, @NotNull JetType type2) {
|
||||
DeclarationDescriptor declarationDescriptor1 = type1.getConstructor().getDeclarationDescriptor();
|
||||
if (declarationDescriptor1 == null) return false; // No class, classes are not equal
|
||||
if (declarationDescriptor1 == null) return true; // No class, classes are not equal
|
||||
DeclarationDescriptor declarationDescriptor2 = type2.getConstructor().getDeclarationDescriptor();
|
||||
if (declarationDescriptor2 == null) return false; // Class of type1 is not null
|
||||
return declarationDescriptor1.getOriginal().equals(declarationDescriptor2.getOriginal());
|
||||
if (declarationDescriptor2 == null) return true; // Class of type1 is not null
|
||||
|
||||
if (declarationDescriptor1 instanceof TypeParameterDescriptor && declarationDescriptor2 instanceof TypeParameterDescriptor) {
|
||||
// if type of value parameter is some generic parameter then their equality was checked by OverridingUtil before calling ExternalOverridabilityCondition
|
||||
// Note that it's true unless we generate sam adapter for type parameter with SAM interface as upper bound:
|
||||
// <K extends Runnable >void foo(K runnable) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
return !declarationDescriptor1.getOriginal().equals(declarationDescriptor2.getOriginal());
|
||||
}
|
||||
|
||||
// if function is or overrides declaration, returns null; otherwise, return original of sam adapter with substituted type parameters
|
||||
|
||||
+4
-4
@@ -16,11 +16,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.load.java.structure.impl;
|
||||
|
||||
import com.intellij.psi.PsiModifierListOwner;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import com.intellij.psi.PsiAnnotationOwner;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaAnnotationOwner;
|
||||
|
||||
public interface JavaAnnotationOwnerImpl extends JavaAnnotationOwner {
|
||||
@NotNull
|
||||
PsiModifierListOwner getPsi();
|
||||
@Nullable
|
||||
PsiAnnotationOwner getAnnotationOwnerPsi();
|
||||
}
|
||||
|
||||
-12
@@ -146,18 +146,6 @@ public class JavaClassImpl extends JavaClassifierImpl<PsiClass> implements JavaC
|
||||
return JavaElementUtil.getVisibility(this);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<JavaAnnotation> getAnnotations() {
|
||||
return JavaElementUtil.getAnnotations(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JavaAnnotation findAnnotation(@NotNull FqName fqName) {
|
||||
return JavaElementUtil.findAnnotation(this, fqName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JavaClassifierType getDefaultType() {
|
||||
|
||||
+25
-1
@@ -16,16 +16,28 @@
|
||||
|
||||
package org.jetbrains.kotlin.load.java.structure.impl;
|
||||
|
||||
import com.intellij.psi.PsiAnnotationOwner;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiTypeParameter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClassifier;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
|
||||
public abstract class JavaClassifierImpl<Psi extends PsiClass> extends JavaElementImpl<Psi> implements JavaClassifier {
|
||||
import java.util.Collection;
|
||||
|
||||
public abstract class JavaClassifierImpl<Psi extends PsiClass> extends JavaElementImpl<Psi> implements JavaClassifier, JavaAnnotationOwnerImpl {
|
||||
protected JavaClassifierImpl(@NotNull Psi psiClass) {
|
||||
super(psiClass);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiAnnotationOwner getAnnotationOwnerPsi() {
|
||||
return getPsi().getModifierList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
/* package */ static JavaClassifier create(@NotNull PsiClass psiClass) {
|
||||
if (psiClass instanceof PsiTypeParameter) {
|
||||
@@ -35,4 +47,16 @@ public abstract class JavaClassifierImpl<Psi extends PsiClass> extends JavaEleme
|
||||
return new JavaClassImpl(psiClass);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<JavaAnnotation> getAnnotations() {
|
||||
return JavaElementUtil.getAnnotations(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JavaAnnotation findAnnotation(@NotNull FqName fqName) {
|
||||
return JavaElementUtil.findAnnotation(this, fqName);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-10
@@ -16,10 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.load.java.structure.impl;
|
||||
|
||||
import com.intellij.psi.PsiAnnotation;
|
||||
import com.intellij.psi.PsiModifier;
|
||||
import com.intellij.psi.PsiModifierList;
|
||||
import com.intellij.psi.PsiModifierListOwner;
|
||||
import com.intellij.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities;
|
||||
@@ -66,18 +63,18 @@ import static org.jetbrains.kotlin.load.java.structure.impl.JavaElementCollectio
|
||||
|
||||
@NotNull
|
||||
public static Collection<JavaAnnotation> getAnnotations(@NotNull JavaAnnotationOwnerImpl owner) {
|
||||
PsiModifierList modifierList = owner.getPsi().getModifierList();
|
||||
if (modifierList != null) {
|
||||
return annotations(modifierList.getAnnotations());
|
||||
PsiAnnotationOwner annotationOwnerPsi = owner.getAnnotationOwnerPsi();
|
||||
if (annotationOwnerPsi != null) {
|
||||
return annotations(annotationOwnerPsi.getAnnotations());
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static JavaAnnotation findAnnotation(@NotNull JavaAnnotationOwnerImpl owner, @NotNull FqName fqName) {
|
||||
PsiModifierList modifierList = owner.getPsi().getModifierList();
|
||||
if (modifierList != null) {
|
||||
PsiAnnotation psiAnnotation = modifierList.findAnnotation(fqName.asString());
|
||||
PsiAnnotationOwner annotationOwnerPsi = owner.getAnnotationOwnerPsi();
|
||||
if (annotationOwnerPsi != null) {
|
||||
PsiAnnotation psiAnnotation = annotationOwnerPsi.findAnnotation(fqName.asString());
|
||||
return psiAnnotation == null ? null : new JavaAnnotationImpl(psiAnnotation);
|
||||
}
|
||||
return null;
|
||||
|
||||
+7
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.load.java.structure.impl;
|
||||
|
||||
import com.intellij.psi.PsiAnnotationOwner;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMember;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -35,6 +36,12 @@ public abstract class JavaMemberImpl<Psi extends PsiMember> extends JavaElementI
|
||||
super(psiMember);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiAnnotationOwner getAnnotationOwnerPsi() {
|
||||
return getPsi().getModifierList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Name getName() {
|
||||
|
||||
+3
-2
@@ -64,9 +64,10 @@ public class JavaMethodImpl extends JavaMemberImpl<PsiMethod> implements JavaMet
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
@NotNull
|
||||
public JavaType getReturnType() {
|
||||
PsiType psiType = getPsi().getReturnType();
|
||||
return psiType == null ? null : JavaTypeImpl.create(psiType);
|
||||
assert psiType != null : "Method is not a constructor and has no return type: " + getName();
|
||||
return JavaTypeImpl.create(psiType);
|
||||
}
|
||||
}
|
||||
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.load.java.structure.impl;
|
||||
|
||||
import com.intellij.psi.PsiExpression;
|
||||
import com.intellij.psi.impl.JavaConstantExpressionEvaluator;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaField;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaPropertyInitializerEvaluator;
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantsPackage;
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
|
||||
|
||||
public class JavaPropertyInitializerEvaluatorImpl implements JavaPropertyInitializerEvaluator {
|
||||
@Nullable
|
||||
@Override
|
||||
public CompileTimeConstant<?> getInitializerConstant(@NotNull JavaField field, @NotNull PropertyDescriptor descriptor) {
|
||||
PsiExpression initializer = ((JavaFieldImpl) field).getInitializer();
|
||||
Object evaluatedExpression = JavaConstantExpressionEvaluator.computeConstantExpression(initializer, false);
|
||||
if (evaluatedExpression != null) {
|
||||
return ConstantsPackage.createCompileTimeConstant(
|
||||
evaluatedExpression,
|
||||
ConstantExpressionEvaluator.isPropertyCompileTimeConstant(descriptor),
|
||||
false,
|
||||
true,
|
||||
descriptor.getType());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNotNullCompileTimeConstant(@NotNull JavaField field) {
|
||||
// PsiUtil.isCompileTimeConstant returns false for null-initialized fields,
|
||||
// see com.intellij.psi.util.IsConstantExpressionVisitor.visitLiteralExpression()
|
||||
return PsiUtil.isCompileTimeConstant(((JavaFieldImpl) field).getPsi());
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.load.java.structure.impl
|
||||
|
||||
import com.intellij.psi.impl.JavaConstantExpressionEvaluator
|
||||
import com.intellij.psi.util.PsiUtil
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaField
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaPropertyInitializerEvaluator
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValueFactory
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
|
||||
public class JavaPropertyInitializerEvaluatorImpl : JavaPropertyInitializerEvaluator {
|
||||
override fun getInitializerConstant(field: JavaField, descriptor: PropertyDescriptor): ConstantValue<*>? {
|
||||
val initializer = (field as JavaFieldImpl).getInitializer()
|
||||
val evaluated = JavaConstantExpressionEvaluator.computeConstantExpression(initializer, false) ?: return null
|
||||
val factory = ConstantValueFactory(descriptor.builtIns)
|
||||
when (evaluated) {
|
||||
//Note: evaluated expression may be of class that does not match field type in some cases
|
||||
// tested for Int, left other checks just in case
|
||||
is Byte, is Short, is Int, is Long -> {
|
||||
return factory.createIntegerConstantValue((evaluated as Number).toLong(), descriptor.getType())
|
||||
}
|
||||
else -> {
|
||||
return factory.createConstantValue(evaluated)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun isNotNullCompileTimeConstant(field: JavaField): Boolean {
|
||||
// PsiUtil.isCompileTimeConstant returns false for null-initialized fields,
|
||||
// see com.intellij.psi.util.IsConstantExpressionVisitor.visitLiteralExpression()
|
||||
return PsiUtil.isCompileTimeConstant((field as JavaFieldImpl).getPsi())
|
||||
}
|
||||
}
|
||||
+24
-1
@@ -19,10 +19,14 @@ package org.jetbrains.kotlin.load.java.structure.impl;
|
||||
import com.intellij.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaArrayType;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaType;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
|
||||
public abstract class JavaTypeImpl<Psi extends PsiType> implements JavaType {
|
||||
import java.util.Collection;
|
||||
|
||||
public abstract class JavaTypeImpl<Psi extends PsiType> implements JavaType, JavaAnnotationOwnerImpl {
|
||||
private final Psi psiType;
|
||||
|
||||
public JavaTypeImpl(@NotNull Psi psiType) {
|
||||
@@ -34,6 +38,12 @@ public abstract class JavaTypeImpl<Psi extends PsiType> implements JavaType {
|
||||
return psiType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiAnnotationOwner getAnnotationOwnerPsi() {
|
||||
return getPsi();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JavaTypeImpl<?> create(@NotNull PsiType psiType) {
|
||||
return psiType.accept(new PsiTypeVisitor<JavaTypeImpl<?>>() {
|
||||
@@ -75,6 +85,19 @@ public abstract class JavaTypeImpl<Psi extends PsiType> implements JavaType {
|
||||
return new JavaArrayTypeImpl(getPsi().createArrayType());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<JavaAnnotation> getAnnotations() {
|
||||
return JavaElementUtil.getAnnotations(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JavaAnnotation findAnnotation(@NotNull FqName fqName) {
|
||||
return JavaElementUtil.findAnnotation(this, fqName);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getPsi().hashCode();
|
||||
|
||||
+32
-1
@@ -16,10 +16,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.load.java.structure.impl;
|
||||
|
||||
import com.intellij.psi.PsiAnnotationOwner;
|
||||
import com.intellij.psi.PsiParameter;
|
||||
import com.intellij.psi.impl.compiled.ClsParameterImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities;
|
||||
import org.jetbrains.kotlin.descriptors.Visibility;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaType;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaValueParameter;
|
||||
@@ -28,11 +31,39 @@ import org.jetbrains.kotlin.name.Name;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class JavaValueParameterImpl extends JavaElementImpl<PsiParameter> implements JavaValueParameter, JavaAnnotationOwnerImpl {
|
||||
public class JavaValueParameterImpl extends JavaElementImpl<PsiParameter>
|
||||
implements JavaValueParameter, JavaAnnotationOwnerImpl, JavaModifierListOwnerImpl {
|
||||
public JavaValueParameterImpl(@NotNull PsiParameter psiParameter) {
|
||||
super(psiParameter);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiAnnotationOwner getAnnotationOwnerPsi() {
|
||||
return getPsi().getModifierList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAbstract() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStatic() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinal() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Visibility getVisibility() {
|
||||
return Visibilities.LOCAL;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<JavaAnnotation> getAnnotations() {
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ public class JavaAnnotationCallChecker : CallChecker {
|
||||
if (it.getArgumentExpression() != null) {
|
||||
context.trace.report(
|
||||
diagnostic.on(
|
||||
it.getArgumentExpression()
|
||||
it.getArgumentExpression()!!
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
+64
-14
@@ -20,16 +20,15 @@ import org.jetbrains.kotlin.cfg.WhenChecker
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.jvm.RuntimeAssertionsTypeChecker
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.isMarkedNotNull
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.isMarkedNullable
|
||||
import org.jetbrains.kotlin.load.kotlin.nativeDeclarations.NativeFunChecker
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.AdditionalCheckerProvider
|
||||
import org.jetbrains.kotlin.resolve.DeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.annotations.findPublicFieldAnnotation
|
||||
import org.jetbrains.kotlin.resolve.annotations.hasInlineAnnotation
|
||||
import org.jetbrains.kotlin.resolve.annotations.hasIntrinsicAnnotation
|
||||
import org.jetbrains.kotlin.resolve.annotations.hasPlatformStaticAnnotation
|
||||
@@ -41,6 +40,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.Nullability
|
||||
import org.jetbrains.kotlin.resolve.jvm.calls.checkers.NeedSyntheticChecker
|
||||
import org.jetbrains.kotlin.resolve.jvm.calls.checkers.ReflectionAPICallChecker
|
||||
import org.jetbrains.kotlin.resolve.jvm.calls.checkers.TraitDefaultMethodCallChecker
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.NullabilityInformationSource
|
||||
@@ -52,23 +52,29 @@ import org.jetbrains.kotlin.types.expressions.SenselessComparisonChecker
|
||||
import org.jetbrains.kotlin.types.flexibility
|
||||
import org.jetbrains.kotlin.types.isFlexible
|
||||
|
||||
public object KotlinJvmCheckerProvider : AdditionalCheckerProvider(
|
||||
public class KotlinJvmCheckerProvider(private val module: ModuleDescriptor) : AdditionalCheckerProvider(
|
||||
additionalDeclarationCheckers = listOf(PlatformStaticAnnotationChecker(),
|
||||
LocalFunInlineChecker(),
|
||||
ReifiedTypeParameterAnnotationChecker(),
|
||||
NativeFunChecker(),
|
||||
OverloadsAnnotationChecker()),
|
||||
OverloadsAnnotationChecker(),
|
||||
PublicFieldAnnotationChecker()),
|
||||
|
||||
additionalCallCheckers = listOf(NeedSyntheticChecker(), JavaAnnotationCallChecker(),
|
||||
JavaAnnotationMethodCallChecker(), TraitDefaultMethodCallChecker()),
|
||||
JavaAnnotationMethodCallChecker(), TraitDefaultMethodCallChecker(),
|
||||
ReflectionAPICallChecker(module)),
|
||||
|
||||
additionalTypeCheckers = listOf(JavaNullabilityWarningsChecker()),
|
||||
additionalTypeCheckers = listOf(JavaNullabilityWarningsChecker(), RuntimeAssertionsTypeChecker),
|
||||
additionalSymbolUsageValidators = listOf()
|
||||
)
|
||||
|
||||
public class LocalFunInlineChecker : DeclarationChecker {
|
||||
|
||||
override fun check(declaration: JetDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink) {
|
||||
override fun check(
|
||||
declaration: JetDeclaration,
|
||||
descriptor: DeclarationDescriptor,
|
||||
diagnosticHolder: DiagnosticSink,
|
||||
bindingContext: BindingContext) {
|
||||
if (descriptor.hasInlineAnnotation() &&
|
||||
declaration is JetNamedFunction &&
|
||||
descriptor is FunctionDescriptor &&
|
||||
@@ -80,7 +86,12 @@ public class LocalFunInlineChecker : DeclarationChecker {
|
||||
|
||||
public class PlatformStaticAnnotationChecker : DeclarationChecker {
|
||||
|
||||
override fun check(declaration: JetDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink) {
|
||||
override fun check(
|
||||
declaration: JetDeclaration,
|
||||
descriptor: DeclarationDescriptor,
|
||||
diagnosticHolder: DiagnosticSink,
|
||||
bindingContext: BindingContext
|
||||
) {
|
||||
if (descriptor.hasPlatformStaticAnnotation()) {
|
||||
if (declaration is JetNamedFunction || declaration is JetProperty || declaration is JetPropertyAccessor) {
|
||||
checkDeclaration(declaration, descriptor, diagnosticHolder)
|
||||
@@ -119,7 +130,12 @@ public class PlatformStaticAnnotationChecker : DeclarationChecker {
|
||||
}
|
||||
|
||||
public class OverloadsAnnotationChecker: DeclarationChecker {
|
||||
override fun check(declaration: JetDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink) {
|
||||
override fun check(
|
||||
declaration: JetDeclaration,
|
||||
descriptor: DeclarationDescriptor,
|
||||
diagnosticHolder: DiagnosticSink,
|
||||
bindingContext: BindingContext
|
||||
) {
|
||||
if (descriptor.getAnnotations().findAnnotation(FqName("kotlin.jvm.jvmOverloads")) != null) {
|
||||
checkDeclaration(declaration, descriptor, diagnosticHolder)
|
||||
}
|
||||
@@ -142,9 +158,37 @@ public class OverloadsAnnotationChecker: DeclarationChecker {
|
||||
}
|
||||
}
|
||||
|
||||
public class PublicFieldAnnotationChecker: DeclarationChecker {
|
||||
override fun check(
|
||||
declaration: JetDeclaration,
|
||||
descriptor: DeclarationDescriptor,
|
||||
diagnosticHolder: DiagnosticSink,
|
||||
bindingContext: BindingContext
|
||||
) {
|
||||
val annotation = descriptor.findPublicFieldAnnotation() ?: return
|
||||
|
||||
fun report() {
|
||||
val annotationEntry = bindingContext.get(BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT, annotation) ?: return
|
||||
diagnosticHolder.report(ErrorsJvm.INAPPLICABLE_PUBLIC_FIELD.on(annotationEntry))
|
||||
}
|
||||
|
||||
if (descriptor !is PropertyDescriptor) {
|
||||
report()
|
||||
}
|
||||
else if (!bindingContext.get<PropertyDescriptor, Boolean>(BindingContext.BACKING_FIELD_REQUIRED, descriptor)!!) {
|
||||
report()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ReifiedTypeParameterAnnotationChecker : DeclarationChecker {
|
||||
|
||||
override fun check(declaration: JetDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink) {
|
||||
override fun check(
|
||||
declaration: JetDeclaration,
|
||||
descriptor: DeclarationDescriptor,
|
||||
diagnosticHolder: DiagnosticSink,
|
||||
bindingContext: BindingContext
|
||||
) {
|
||||
if (descriptor.hasIntrinsicAnnotation()) return
|
||||
|
||||
if (descriptor is CallableDescriptor && !descriptor.hasInlineAnnotation()) {
|
||||
@@ -176,12 +220,18 @@ private fun checkTypeParameterDescriptorsAreNotReified(
|
||||
public class JavaNullabilityWarningsChecker : AdditionalTypeChecker {
|
||||
private fun JetType.mayBeNull(): NullabilityInformationSource? {
|
||||
if (!isError() && !isFlexible() && TypeUtils.isNullableType(this)) return NullabilityInformationSource.KOTLIN
|
||||
|
||||
if (isFlexible() && TypeUtils.isNullableType(flexibility().lowerBound)) return NullabilityInformationSource.KOTLIN
|
||||
|
||||
if (getAnnotations().isMarkedNullable()) return NullabilityInformationSource.JAVA
|
||||
return null
|
||||
}
|
||||
|
||||
private fun JetType.mustNotBeNull(): NullabilityInformationSource? {
|
||||
if (!isError() && !isFlexible() && !TypeUtils.isNullableType(this)) return NullabilityInformationSource.KOTLIN
|
||||
|
||||
if (isFlexible() && !TypeUtils.isNullableType(flexibility().upperBound)) return NullabilityInformationSource.KOTLIN
|
||||
|
||||
if (!isMarkedNullable() && getAnnotations().isMarkedNotNull()) return NullabilityInformationSource.JAVA
|
||||
return null
|
||||
}
|
||||
@@ -254,7 +304,7 @@ public class JavaNullabilityWarningsChecker : AdditionalTypeChecker {
|
||||
val baseExpression = expression.getLeft()
|
||||
val baseExpressionType = baseExpression?.let{ c.trace.getType(it) } ?: return
|
||||
doIfNotNull(
|
||||
DataFlowValueFactory.createDataFlowValue(baseExpression, baseExpressionType, c),
|
||||
DataFlowValueFactory.createDataFlowValue(baseExpression!!, baseExpressionType, c),
|
||||
c
|
||||
) {
|
||||
c.trace.report(Errors.USELESS_ELVIS.on(expression, baseExpressionType))
|
||||
@@ -317,7 +367,7 @@ public class JavaNullabilityWarningsChecker : AdditionalTypeChecker {
|
||||
}
|
||||
else {
|
||||
doIfNotNull(dataFlowValue, c) {
|
||||
c.trace.report(Errors.UNNECESSARY_SAFE_CALL.on(c.call.getCallOperationNode().getPsi(), receiverArgument.getType()))
|
||||
c.trace.report(Errors.UNNECESSARY_SAFE_CALL.on(c.call.getCallOperationNode()!!.getPsi(), receiverArgument.getType()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ public class VirtualFileKotlinClass private constructor(
|
||||
|
||||
companion object Factory {
|
||||
private val LOG = Logger.getInstance(javaClass<VirtualFileKotlinClass>())
|
||||
private val perfCounter = PerformanceCounter("Binary class from Kotlin file")
|
||||
private val perfCounter = PerformanceCounter.create("Binary class from Kotlin file")
|
||||
|
||||
deprecated("Use KotlinBinaryClassCache")
|
||||
fun create(file: VirtualFile): VirtualFileKotlinClass? {
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||
import org.jetbrains.kotlin.psi.JetDeclarationWithBody
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.annotations.hasInlineAnnotation
|
||||
import org.jetbrains.kotlin.resolve.diagnostics.SuppressDiagnosticsByAnnotations
|
||||
import org.jetbrains.kotlin.resolve.diagnostics.FUNCTION_NO_BODY_ERRORS
|
||||
@@ -41,7 +42,12 @@ public fun DeclarationDescriptor.hasNativeAnnotation(): Boolean {
|
||||
public class SuppressNoBodyErrorsForNativeDeclarations : SuppressDiagnosticsByAnnotations(FUNCTION_NO_BODY_ERRORS, NATIVE_ANNOTATION_CLASS_NAME)
|
||||
|
||||
public class NativeFunChecker : DeclarationChecker {
|
||||
override fun check(declaration: JetDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink) {
|
||||
override fun check(
|
||||
declaration: JetDeclaration,
|
||||
descriptor: DeclarationDescriptor,
|
||||
diagnosticHolder: DiagnosticSink,
|
||||
bindingContext: BindingContext
|
||||
) {
|
||||
if (!descriptor.hasNativeAnnotation()) return
|
||||
|
||||
if (DescriptorUtils.isTrait(descriptor.getContainingDeclaration())) {
|
||||
|
||||
@@ -36,23 +36,22 @@ public class AsmTypes {
|
||||
|
||||
public static final Type LAMBDA = Type.getObjectType("kotlin/jvm/internal/Lambda");
|
||||
public static final Type FUNCTION_REFERENCE = Type.getObjectType("kotlin/jvm/internal/FunctionReference");
|
||||
public static final Type PROPERTY_REFERENCE0 = Type.getObjectType("kotlin/jvm/internal/PropertyReference0");
|
||||
public static final Type PROPERTY_REFERENCE1 = Type.getObjectType("kotlin/jvm/internal/PropertyReference1");
|
||||
public static final Type MUTABLE_PROPERTY_REFERENCE0 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference0");
|
||||
public static final Type MUTABLE_PROPERTY_REFERENCE1 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference1");
|
||||
|
||||
public static final Type K_CLASS_TYPE = reflect("KClass");
|
||||
public static final Type K_CLASS_ARRAY_TYPE = Type.getObjectType("[" + K_CLASS_TYPE.getDescriptor());
|
||||
public static final Type K_PACKAGE_TYPE = reflect("KPackage");
|
||||
public static final Type K_DECLARATION_CONTAINER_TYPE = reflect("KDeclarationContainer");
|
||||
|
||||
public static final Type K_FUNCTION = reflect("KFunction");
|
||||
public static final Type K_TOP_LEVEL_FUNCTION = reflect("KTopLevelFunction");
|
||||
public static final Type K_MEMBER_FUNCTION = reflect("KMemberFunction");
|
||||
public static final Type K_TOP_LEVEL_EXTENSION_FUNCTION = reflect("KTopLevelExtensionFunction");
|
||||
public static final Type K_LOCAL_FUNCTION = reflect("KLocalFunction");
|
||||
|
||||
public static final Type K_MEMBER_PROPERTY_TYPE = reflect("KMemberProperty");
|
||||
public static final Type K_MUTABLE_MEMBER_PROPERTY_TYPE = reflect("KMutableMemberProperty");
|
||||
public static final Type K_TOP_LEVEL_VARIABLE_TYPE = reflect("KTopLevelVariable");
|
||||
public static final Type K_MUTABLE_TOP_LEVEL_VARIABLE_TYPE = reflect("KMutableTopLevelVariable");
|
||||
public static final Type K_TOP_LEVEL_EXTENSION_PROPERTY_TYPE = reflect("KTopLevelExtensionProperty");
|
||||
public static final Type K_MUTABLE_TOP_LEVEL_EXTENSION_PROPERTY_TYPE = reflect("KMutableTopLevelExtensionProperty");
|
||||
public static final Type K_PROPERTY0_TYPE = reflect("KProperty0");
|
||||
public static final Type K_PROPERTY1_TYPE = reflect("KProperty1");
|
||||
public static final Type K_MUTABLE_PROPERTY0_TYPE = reflect("KMutableProperty0");
|
||||
public static final Type K_MUTABLE_PROPERTY1_TYPE = reflect("KMutableProperty1");
|
||||
|
||||
public static final String REFLECTION = "kotlin/jvm/internal/Reflection";
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user