NamespaceCodegen.java 9.6 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;
S
Stepan Koltsov 已提交
9
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
10
import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
11
import org.jetbrains.jet.lang.types.JetStandardClasses;
A
Alex Tkachman 已提交
12
import org.jetbrains.jet.lang.types.JetType;
A
Alex Tkachman 已提交
13 14
import org.jetbrains.jet.lang.types.TypeProjection;
import org.jetbrains.jet.lang.types.TypeUtils;
15 16 17
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
18
import org.objectweb.asm.commons.InstructionAdapter;
M
Maxim Shafirov 已提交
19

20
import java.util.List;
A
Alex Tkachman 已提交
21 22

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

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

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

35
        v.defineClass(sourceFile, V1_6,
A
Alex Tkachman 已提交
36
                      ACC_PUBLIC/*|ACC_SUPER*/,
37
                      getJVMClassName(fqName, true),
38 39 40 41
                      null,
                      //"jet/lang/Namespace",
                      "java/lang/Object",
                      new String[0]
42
        );
43
        // TODO figure something out for a namespace that spans multiple files
44
        v.visitSource(state.transformFileName(sourceFile.getName()), null);
45 46
    }

A
Andrey Breslav 已提交
47 48
    public void generate(JetFile file) {
        NamespaceDescriptor descriptor = state.getBindingContext().get(BindingContext.NAMESPACE, file);
A
Alex Tkachman 已提交
49
        final CodegenContext context = CodegenContext.STATIC.intoNamespace(descriptor);
M
Maxim Shafirov 已提交
50 51 52

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

M
Maxim Shafirov 已提交
55
        if (v.generateCode()) {
A
Andrey Breslav 已提交
56
            GenerationState.prepareAnonymousClasses(file, state.getTypeMapper());
M
Maxim Shafirov 已提交
57
        }
58

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

A
Andrey Breslav 已提交
82 83
        if (hasNonConstantPropertyInitializers(file)) {
            generateStaticInitializers(file);
A
Alex Tkachman 已提交
84
        }
A
Alex Tkachman 已提交
85

A
Andrey Breslav 已提交
86
        generateTypeInfoFields(file, context);
87
    }
M
Maxim Shafirov 已提交
88

A
Andrey Breslav 已提交
89
    private void generateStaticInitializers(JetFile namespace) {
90 91
        MethodVisitor mv = v.newMethod(namespace, ACC_PUBLIC | ACC_STATIC,
                                       "<clinit>", "()V", null, null);
92 93 94 95 96 97 98 99 100 101 102
        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);
103 104 105 106
                        assert descriptor != null;
                        if(descriptor.getReceiverParameter().exists()) {
                            continue;
                        }
107 108 109
                        codegen.genToJVMStack(initializer);
                        codegen.intermediateValueForProperty(descriptor, true, null).store(new InstructionAdapter(mv));
                    }
110 111
                }
            }
A
Alex Tkachman 已提交
112

113
            mv.visitInsn(RETURN);
A
Alex Tkachman 已提交
114
            FunctionCodegen.endVisit(mv, "static initializer for namespace", namespace);
115 116
            mv.visitEnd();
        }
117 118
    }

A
Andrey Breslav 已提交
119
    private void generateTypeInfoFields(JetFile file, CodegenContext context) {
A
Alex Tkachman 已提交
120
        if(context.typeInfoConstants != null) {
121
            String jvmClassName = getJVMClassName(JetPsiUtil.getFQName(file), true);
122 123 124
            for(int index = 0; index != context.typeInfoConstantsCount; index++) {
                JetType type = context.reverseTypeInfoConstants.get(index);
                String fieldName = "$typeInfoCache$" + index;
125
                v.newField(null, ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC, fieldName, "Ljet/TypeInfo;", null, null);
A
Alex Tkachman 已提交
126

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

                v.pop();
135
                generateTypeInfo(context, v, type, state.getTypeMapper(), type);
A
Alex Tkachman 已提交
136 137
                v.dup();

138
                v.visitFieldInsn(PUTSTATIC, jvmClassName, fieldName, "Ljet/TypeInfo;");
A
Alex Tkachman 已提交
139 140
                v.visitLabel(end);
                v.visitInsn(ARETURN);
A
Andrey Breslav 已提交
141
                FunctionCodegen.endVisit(v, "type info method", file);
A
Alex Tkachman 已提交
142 143 144 145
            }
        }
    }

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

        DeclarationDescriptor declarationDescriptor = jetType.getConstructor().getDeclarationDescriptor();
154
        if(!jetType.equals(root) && jetType.getArguments().size() == 0 && !JetStandardClasses.getAny().equals(declarationDescriptor)) {
A
Alex Tkachman 已提交
155
            // TODO: we need some better checks here
S
Stepan Koltsov 已提交
156
            v.getstatic(typeMapper.mapType(jetType, OwnerKind.IMPLEMENTATION).getInternalName(), JvmAbi.TYPE_INFO_FIELD, "Ljet/TypeInfo;");
A
Alex Tkachman 已提交
157 158 159 160 161 162
            return;
        }

        boolean hasUnsubstituted = TypeUtils.hasUnsubstitutedTypeParameters(jetType);
        if(!jetType.equals(root) && !hasUnsubstituted) {
            int typeInfoConstantIndex = context.getTypeInfoConstantIndex(jetType);
163
            v.invokestatic(context.getNamespaceClassName(), "$getCachedTypeInfo$" + typeInfoConstantIndex, "()Ljet/TypeInfo;");
A
Alex Tkachman 已提交
164 165 166
            return;
        }

167
        final Type jvmType = typeMapper.mapType(jetType);
A
Alex Tkachman 已提交
168 169 170 171

        v.aconst(jvmType);
        v.iconst(jetType.isNullable() ? 1 : 0);
        List<TypeProjection> arguments = jetType.getArguments();
172
        if (arguments.size() > 0 && !(jvmType.getSort() == Type.ARRAY && JetTypeMapper.correctElementType(jvmType).getSort() != Type.OBJECT)) {
A
Alex Tkachman 已提交
173 174 175 176 177 178 179 180 181 182 183
            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);
            }
184
            v.invokestatic("jet/TypeInfo", JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD, "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfoProjection;)Ljet/TypeInfo;");
A
Alex Tkachman 已提交
185 186
        }
        else {
187
            v.invokestatic("jet/TypeInfo", JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD, "(Ljava/lang/Class;Z)Ljet/TypeInfo;");
A
Alex Tkachman 已提交
188 189 190
        }
    }

A
Andrey Breslav 已提交
191
    private static boolean hasNonConstantPropertyInitializers(JetFile namespace) {
192 193 194 195 196 197 198 199 200 201 202 203
        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;
    }

204
    public void done() {
205
        v.done();
M
Maxim Shafirov 已提交
206
    }
D
Dmitry Jemerov 已提交
207

208 209 210 211
    /**
     * @param namespace true for "namespace" suffix 
     */
    public static String getJVMClassName(String fqName, boolean namespace) {
212
        if (fqName.length() == 0) {
S
Stepan Koltsov 已提交
213
            return JvmAbi.PACKAGE_CLASS;
214
        }
A
Alex Tkachman 已提交
215

216
        String name = fqName.replace('.', '/');
A
Alex Tkachman 已提交
217
        if(name.startsWith("<java_root>")) {
218 219 220 221
            name = name.substring("<java_root>".length() + 1, name.length());
        }
        if (namespace) {
            name += "/" + JvmAbi.PACKAGE_CLASS;
A
Alex Tkachman 已提交
222 223
        }
        return name;
224
    }
M
Maxim Shafirov 已提交
225
}