NamespaceCodegen.java 8.7 KB
Newer Older
M
Maxim Shafirov 已提交
1 2
package org.jetbrains.jet.codegen;

3
import com.intellij.psi.PsiFile;
A
Alex Tkachman 已提交
4
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
A
Andrey Breslav 已提交
5
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
6
import org.jetbrains.jet.lang.psi.*;
7
import org.jetbrains.jet.lang.resolve.BindingContext;
A
Alex Tkachman 已提交
8
import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor;
A
Alex Tkachman 已提交
9
import org.jetbrains.jet.lang.types.JetType;
A
Alex Tkachman 已提交
10 11
import org.jetbrains.jet.lang.types.TypeProjection;
import org.jetbrains.jet.lang.types.TypeUtils;
12 13 14
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
15
import org.objectweb.asm.commons.InstructionAdapter;
M
Maxim Shafirov 已提交
16

17 18 19
import java.util.Collections;
import java.util.List;
import java.util.Map;
A
Alex Tkachman 已提交
20 21

import static org.objectweb.asm.Opcodes.*;
A
Alex Tkachman 已提交
22

M
Maxim Shafirov 已提交
23 24 25 26
/**
 * @author max
 */
public class NamespaceCodegen {
27
    private final ClassBuilder v;
28
    private final GenerationState state;
M
Maxim Shafirov 已提交
29

30
    public NamespaceCodegen(ClassBuilder v, String fqName, GenerationState state, PsiFile sourceFile) {
31
        this.v = v;
32
        this.state = state;
33

34 35 36 37 38 39 40
        v.defineClass(V1_6,
                      ACC_PUBLIC,
                      getJVMClassName(fqName),
                      null,
                      //"jet/lang/Namespace",
                      "java/lang/Object",
                      new String[0]
41
        );
42 43
        // TODO figure something out for a namespace that spans multiple files
        v.visitSource(sourceFile.getName(), null);
44 45 46
    }

    public void generate(JetNamespace namespace) {
47
        final ClassContext context = ClassContext.STATIC.intoNamespace(state.getBindingContext().get(BindingContext.NAMESPACE, namespace));
M
Maxim Shafirov 已提交
48 49 50

        final FunctionCodegen functionCodegen = new FunctionCodegen(context, v, state);
        final PropertyCodegen propertyCodegen = new PropertyCodegen(context, v, functionCodegen, state);
51
        final ClassCodegen classCodegen = state.forClass();
M
Maxim Shafirov 已提交
52

53
        GenerationState.prepareAnonymousClasses(namespace, state.getTypeMapper());
54

M
Maxim Shafirov 已提交
55 56
        for (JetDeclaration declaration : namespace.getDeclarations()) {
            if (declaration instanceof JetProperty) {
M
Maxim Shafirov 已提交
57
                propertyCodegen.gen((JetProperty) declaration);
M
Maxim Shafirov 已提交
58
            }
59
            else if (declaration instanceof JetNamedFunction) {
D
Dmitry Jemerov 已提交
60
                try {
M
Maxim Shafirov 已提交
61
                    functionCodegen.gen((JetNamedFunction) declaration);
D
Dmitry Jemerov 已提交
62 63 64
                } catch (Exception e) {
                    throw new RuntimeException("Failed to generate function " + declaration.getName(), e);
                }
M
Maxim Shafirov 已提交
65
            }
66
            else if (declaration instanceof JetClassOrObject) {
M
Maxim Shafirov 已提交
67
                classCodegen.generate(context, (JetClassOrObject) declaration);
68
            }
69 70
            else if (declaration instanceof JetNamespace) {
                JetNamespace childNamespace = (JetNamespace) declaration;
71
                state.forNamespace(childNamespace).generate(childNamespace);
72
            }
M
Maxim Shafirov 已提交
73
        }
A
Alex Tkachman 已提交
74

75 76
        if (hasNonConstantPropertyInitializers(namespace)) {
            generateStaticInitializers(namespace);
A
Alex Tkachman 已提交
77
        }
A
Alex Tkachman 已提交
78 79

        generateTypeInfoFields(namespace, context);
80
    }
M
Maxim Shafirov 已提交
81

82
    private void generateStaticInitializers(JetNamespace namespace) {
83 84
        MethodVisitor mv = v.newMethod(namespace, ACC_PUBLIC | ACC_STATIC,
                                       "<clinit>", "()V", null, null);
85 86 87
        mv.visitCode();

        FrameMap frameMap = new FrameMap();
88
        ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, ClassContext.STATIC, state);
89 90 91 92 93

        for (JetDeclaration declaration : namespace.getDeclarations()) {
            if (declaration instanceof JetProperty) {
                final JetExpression initializer = ((JetProperty) declaration).getInitializer();
                if (initializer != null && !(initializer instanceof JetConstantExpression)) {
94
                    final PropertyDescriptor descriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, declaration);
95
                    codegen.genToJVMStack(initializer);
96
                    codegen.intermediateValueForProperty(descriptor, true, false).store(new InstructionAdapter(mv));
97 98 99
                }
            }
        }
A
Alex Tkachman 已提交
100 101

        mv.visitInsn(RETURN);
102 103 104 105
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

A
Alex Tkachman 已提交
106 107 108 109 110
    private void generateTypeInfoFields(JetNamespace namespace, ClassContext context) {
        if(context.typeInfoConstants != null) {
            String jvmClassName = getJVMClassName(namespace.getName());
            for(Map.Entry<JetType,Integer> e : (context.typeInfoConstants != null ? context.typeInfoConstants : Collections.<JetType,Integer>emptyMap()).entrySet()) {
                String fieldName = "$typeInfoCache$" + e.getValue();
111
                v.newField(null, ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC, fieldName, "Ljet/typeinfo/TypeInfo;", null, null);
A
Alex Tkachman 已提交
112

113
                MethodVisitor mmv = v.newMethod(null, ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, "$getCachedTypeInfo$" + e.getValue(), "()Ljet/typeinfo/TypeInfo;", null, null);
114
                InstructionAdapter v = new InstructionAdapter(mmv);
A
Alex Tkachman 已提交
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
                v.visitFieldInsn(GETSTATIC, jvmClassName, fieldName, "Ljet/typeinfo/TypeInfo;");
                v.visitInsn(DUP);
                Label end = new Label();
                v.visitJumpInsn(IFNONNULL, end);

                v.pop();
                generateTypeInfo(context, v, e.getKey(), state.getTypeMapper(), e.getKey());
                v.dup();

                v.visitFieldInsn(PUTSTATIC, jvmClassName, fieldName, "Ljet/typeinfo/TypeInfo;");
                v.visitLabel(end);
                v.visitInsn(ARETURN);
                v.visitMaxs(0, 0);
                v.visitEnd();
            }
        }
    }

133
    private static void generateTypeInfo(ClassContext context, InstructionAdapter v, JetType jetType, JetTypeMapper typeMapper, JetType root) {
A
Alex Tkachman 已提交
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
        String knownTypeInfo = typeMapper.isKnownTypeInfo(jetType);
        if(knownTypeInfo != null) {
            v.getstatic("jet/typeinfo/TypeInfo", knownTypeInfo, "Ljet/typeinfo/TypeInfo;");
            return;
        }

        DeclarationDescriptor declarationDescriptor = jetType.getConstructor().getDeclarationDescriptor();
        if(!jetType.equals(root) && jetType.getArguments().size() == 0 && !(declarationDescriptor instanceof JavaClassDescriptor)) {
            // TODO: we need some better checks here
            v.getstatic(typeMapper.mapType(jetType, OwnerKind.IMPLEMENTATION).getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
            return;
        }

        boolean hasUnsubstituted = TypeUtils.hasUnsubstitutedTypeParameters(jetType);
        if(!jetType.equals(root) && !hasUnsubstituted) {
            int typeInfoConstantIndex = context.getTypeInfoConstantIndex(jetType);
            v.invokestatic(context.getNamespaceClassName(), "$getCachedTypeInfo$" + typeInfoConstantIndex, "()Ljet/typeinfo/TypeInfo;");
            return;
        }

154
        final Type jvmType = typeMapper.mapType(jetType);
A
Alex Tkachman 已提交
155 156 157 158

        v.aconst(jvmType);
        v.iconst(jetType.isNullable() ? 1 : 0);
        List<TypeProjection> arguments = jetType.getArguments();
A
Alex Tkachman 已提交
159
        if (arguments.size() > 0 && !(jvmType.getSort() == Type.ARRAY && jvmType.getElementType().getSort() != Type.OBJECT)) {
A
Alex Tkachman 已提交
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
            v.iconst(arguments.size());
            v.newarray(JetTypeMapper.TYPE_TYPEINFOPROJECTION);

            for (int i = 0, argumentsSize = arguments.size(); i < argumentsSize; i++) {
                TypeProjection argument = arguments.get(i);
                v.dup();
                v.iconst(i);
                generateTypeInfo(context, v, argument.getType(), typeMapper, root);
                ExpressionCodegen.genTypeInfoToProjection(v, argument.getProjectionKind());
                v.astore(JetTypeMapper.TYPE_OBJECT);
            }
            v.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfoProjection;)Ljet/typeinfo/TypeInfo;");
        }
        else {
            v.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z)Ljet/typeinfo/TypeInfo;");
        }
    }

178
    private static boolean hasNonConstantPropertyInitializers(JetNamespace namespace) {
179 180 181 182 183 184 185 186 187 188 189 190
        for (JetDeclaration declaration : namespace.getDeclarations()) {
            if (declaration instanceof JetProperty) {
                final JetExpression initializer = ((JetProperty) declaration).getInitializer();
                if (initializer != null && !(initializer instanceof JetConstantExpression)) {
                    return true;
                }

            }
        }
        return false;
    }

191
    public void done() {
192
        v.done();
M
Maxim Shafirov 已提交
193
    }
D
Dmitry Jemerov 已提交
194

195
    public static String getJVMClassName(String fqName) {
196 197 198
        if (fqName.length() == 0) {
            return "namespace";
        }
199 200
        return fqName.replace('.', '/') + "/namespace";
    }
M
Maxim Shafirov 已提交
201
}