NamespaceCodegen.java 9.4 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
Alex Tkachman 已提交
5
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
A
Andrey Breslav 已提交
6
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
7
import org.jetbrains.jet.lang.psi.*;
8
import org.jetbrains.jet.lang.resolve.BindingContext;
A
Alex Tkachman 已提交
9
import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor;
10
import org.jetbrains.jet.lang.types.JetStandardClasses;
A
Alex Tkachman 已提交
11
import org.jetbrains.jet.lang.types.JetType;
A
Alex Tkachman 已提交
12 13
import org.jetbrains.jet.lang.types.TypeProjection;
import org.jetbrains.jet.lang.types.TypeUtils;
14 15 16
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
17
import org.objectweb.asm.commons.InstructionAdapter;
M
Maxim Shafirov 已提交
18

19
import java.util.List;
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
        v.defineClass(sourceFile, V1_6,
A
Alex Tkachman 已提交
35
                      ACC_PUBLIC/*|ACC_SUPER*/,
36 37 38 39 40
                      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) {
A
Alex Tkachman 已提交
47 48
        NamespaceDescriptor descriptor = state.getBindingContext().get(BindingContext.NAMESPACE, namespace);
        final CodegenContext context = CodegenContext.STATIC.intoNamespace(descriptor);
M
Maxim Shafirov 已提交
49 50 51

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

M
Maxim Shafirov 已提交
54 55 56
        if (v.generateCode()) {
            GenerationState.prepareAnonymousClasses(namespace, state.getTypeMapper());
        }
57

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

78 79
        if (hasNonConstantPropertyInitializers(namespace)) {
            generateStaticInitializers(namespace);
A
Alex Tkachman 已提交
80
        }
A
Alex Tkachman 已提交
81 82

        generateTypeInfoFields(namespace, context);
83
    }
M
Maxim Shafirov 已提交
84

85
    private void generateStaticInitializers(JetNamespace namespace) {
86 87
        MethodVisitor mv = v.newMethod(namespace, ACC_PUBLIC | ACC_STATIC,
                                       "<clinit>", "()V", null, null);
88 89 90 91 92 93 94 95 96 97 98
        if (v.generateCode()) {
            mv.visitCode();

            FrameMap frameMap = new FrameMap();
            ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, CodegenContext.STATIC, state);

            for (JetDeclaration declaration : namespace.getDeclarations()) {
                if (declaration instanceof JetProperty) {
                    final JetExpression initializer = ((JetProperty) declaration).getInitializer();
                    if (initializer != null && !(initializer instanceof JetConstantExpression)) {
                        final PropertyDescriptor descriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, declaration);
99 100 101 102
                        assert descriptor != null;
                        if(descriptor.getReceiverParameter().exists()) {
                            continue;
                        }
103 104 105
                        codegen.genToJVMStack(initializer);
                        codegen.intermediateValueForProperty(descriptor, true, null).store(new InstructionAdapter(mv));
                    }
106 107
                }
            }
A
Alex Tkachman 已提交
108

109 110 111 112
            mv.visitInsn(RETURN);
            mv.visitMaxs(0, 0);
            mv.visitEnd();
        }
113 114
    }

115
    private void generateTypeInfoFields(JetNamespace namespace, CodegenContext context) {
A
Alex Tkachman 已提交
116 117
        if(context.typeInfoConstants != null) {
            String jvmClassName = getJVMClassName(namespace.getName());
118 119 120
            for(int index = 0; index != context.typeInfoConstantsCount; index++) {
                JetType type = context.reverseTypeInfoConstants.get(index);
                String fieldName = "$typeInfoCache$" + index;
121
                v.newField(null, ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC, fieldName, "Ljet/typeinfo/TypeInfo;", null, null);
A
Alex Tkachman 已提交
122

123
                MethodVisitor mmv = v.newMethod(null, ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, "$getCachedTypeInfo$" + index, "()Ljet/typeinfo/TypeInfo;", null, null);
124
                InstructionAdapter v = new InstructionAdapter(mmv);
A
Alex Tkachman 已提交
125 126 127 128 129 130
                v.visitFieldInsn(GETSTATIC, jvmClassName, fieldName, "Ljet/typeinfo/TypeInfo;");
                v.visitInsn(DUP);
                Label end = new Label();
                v.visitJumpInsn(IFNONNULL, end);

                v.pop();
131
                generateTypeInfo(context, v, type, state.getTypeMapper(), type);
A
Alex Tkachman 已提交
132 133 134 135 136 137 138 139 140 141 142
                v.dup();

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

143
    private static void generateTypeInfo(CodegenContext context, InstructionAdapter v, JetType jetType, JetTypeMapper typeMapper, JetType root) {
A
Alex Tkachman 已提交
144 145 146 147 148 149 150
        String knownTypeInfo = typeMapper.isKnownTypeInfo(jetType);
        if(knownTypeInfo != null) {
            v.getstatic("jet/typeinfo/TypeInfo", knownTypeInfo, "Ljet/typeinfo/TypeInfo;");
            return;
        }

        DeclarationDescriptor declarationDescriptor = jetType.getConstructor().getDeclarationDescriptor();
151
        if(!jetType.equals(root) && jetType.getArguments().size() == 0 && !(declarationDescriptor instanceof JavaClassDescriptor) && !JetStandardClasses.getAny().equals(declarationDescriptor)) {
A
Alex Tkachman 已提交
152 153 154 155 156 157 158 159 160 161 162 163
            // 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;
        }

164
        final Type jvmType = typeMapper.mapType(jetType);
A
Alex Tkachman 已提交
165 166 167 168

        v.aconst(jvmType);
        v.iconst(jetType.isNullable() ? 1 : 0);
        List<TypeProjection> arguments = jetType.getArguments();
169
        if (arguments.size() > 0 && !(jvmType.getSort() == Type.ARRAY && JetTypeMapper.correctElementType(jvmType).getSort() != Type.OBJECT)) {
A
Alex Tkachman 已提交
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
            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;");
        }
    }

188
    private static boolean hasNonConstantPropertyInitializers(JetNamespace namespace) {
189 190 191 192 193 194 195 196 197 198 199 200
        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;
    }

201
    public void done() {
202
        v.done();
M
Maxim Shafirov 已提交
203
    }
D
Dmitry Jemerov 已提交
204

205
    public static String getJVMClassName(String fqName) {
206 207 208
        if (fqName.length() == 0) {
            return "namespace";
        }
A
Alex Tkachman 已提交
209 210 211 212 213 214

        String name = fqName.replace('.', '/') + "/namespace";
        if(name.startsWith("<java_root>")) {
            name = name.substring("<java_root>".length() + 1, name.length() - ".namespace".length());
        }
        return name;
215
    }
M
Maxim Shafirov 已提交
216
}