ClassBodyCodegen.java 5.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Copyright 2010-2012 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.
 */

17 18
package org.jetbrains.jet.codegen;

19
import com.intellij.psi.PsiElement;
20 21 22
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.psi.*;
23
import org.jetbrains.jet.lang.resolve.BindingContext;
24
import org.objectweb.asm.MethodVisitor;
25
import org.objectweb.asm.Opcodes;
26
import org.objectweb.asm.commons.InstructionAdapter;
27

28
import java.util.ArrayList;
29 30 31
import java.util.Collections;
import java.util.List;

32 33 34 35 36
/**
 * @author max
 * @author yole
 */
public abstract class ClassBodyCodegen {
37 38
    protected final GenerationState state;

39
    protected final JetClassOrObject myClass;
40 41
    protected final OwnerKind kind;
    protected final ClassDescriptor descriptor;
42
    protected final ClassBuilder v;
43
    protected final CodegenContext context;
44

45 46
    protected final List<CodeChunk> staticInitializerChunks = new ArrayList<CodeChunk>();

47
    public ClassBodyCodegen(JetClassOrObject aClass, CodegenContext context, ClassBuilder v, GenerationState state) {
48
        this.state = state;
49
        descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
50
        myClass = aClass;
M
Maxim Shafirov 已提交
51 52
        this.context = context;
        this.kind = context.getContextKind();
53 54 55
        this.v = v;
    }

56
    public final void generate() {
57 58 59 60
        generateDeclaration();

        generateClassBody();

61
        generateSyntheticParts();
A
Alex Tkachman 已提交
62

63
        generateStaticInitializer();
64 65 66 67
    }

    protected abstract void generateDeclaration();

68
    protected void generateSyntheticParts() {
69 70 71
    }

    private void generateClassBody() {
M
Maxim Shafirov 已提交
72 73
        final FunctionCodegen functionCodegen = new FunctionCodegen(context, v, state);
        final PropertyCodegen propertyCodegen = new PropertyCodegen(context, v, functionCodegen, state);
74 75

        for (JetDeclaration declaration : myClass.getDeclarations()) {
76
            generateDeclaration(propertyCodegen, declaration, functionCodegen);
77 78
        }

79
        generatePrimaryConstructorProperties(propertyCodegen, myClass);
80 81
    }

82 83
    protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) {
        if (declaration instanceof JetProperty) {
M
Maxim Shafirov 已提交
84
            propertyCodegen.gen((JetProperty) declaration);
85
        }
86
        else if (declaration instanceof JetNamedFunction) {
87
            try {
A
Alex Tkachman 已提交
88
                genNamedFunction((JetNamedFunction) declaration, functionCodegen);
89 90 91
            }
            catch(CompilationException e) {
                throw e;
92
            } catch (RuntimeException e) {
M
Maxim Shafirov 已提交
93
                throw new RuntimeException("Error generating method " + myClass.getName() + "." + declaration.getName() + " in " + context, e);
94 95 96 97
            }
        }
    }

A
Alex Tkachman 已提交
98 99 100 101
    protected void genNamedFunction(JetNamedFunction declaration, FunctionCodegen functionCodegen) {
        functionCodegen.gen(declaration);
    }

102
    private void generatePrimaryConstructorProperties(PropertyCodegen propertyCodegen, PsiElement origin) {
M
Maxim Shafirov 已提交
103
        OwnerKind kind = context.getContextKind();
104
        for (JetParameter p : getPrimaryConstructorParameters()) {
105
            if (p.getValOrVarNode() != null) {
106
                PropertyDescriptor propertyDescriptor = state.getBindingContext().get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, p);
107
                if (propertyDescriptor != null) {
108
                    propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, p);
109
                    if (propertyDescriptor.isVar()) {
110
                        propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, origin);
111 112
                    }

113
                    //noinspection ConstantConditions
A
Alex Tkachman 已提交
114
                    if (!(kind instanceof OwnerKind.DelegateKind) && state.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) {
115 116 117 118
                        int modifiers = JetTypeMapper.getAccessModifiers(propertyDescriptor, 0);
                        if (!propertyDescriptor.isVar()) {
                            modifiers |= Opcodes.ACC_FINAL;
                        }
S
Stepan Koltsov 已提交
119
                        if(state.getInjector().getJetStandardLibrary().isVolatile(propertyDescriptor)) {
120 121
                            modifiers |= Opcodes.ACC_VOLATILE;
                        }
S
Stepan Koltsov 已提交
122
                        v.newField(p, modifiers, p.getName(), state.getInjector().getJetTypeMapper().mapType(propertyDescriptor.getType()).getDescriptor(), null, null);
123 124 125 126 127 128
                    }
                }
            }
        }
    }

129 130 131 132 133 134
    protected List<JetParameter> getPrimaryConstructorParameters() {
        if (myClass instanceof JetClass) {
            return ((JetClass) myClass).getPrimaryConstructorParameters();
        }
        return Collections.emptyList();
    }
135 136 137

    private void generateStaticInitializer() {
        if (staticInitializerChunks.size() > 0) {
138
            final MethodVisitor mv = v.newMethod(null, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,"<clinit>", "()V", null, null);
S
Stepan Koltsov 已提交
139
            if (v.generateCode() == ClassBuilder.Mode.FULL) {
140
                mv.visitCode();
141

142
                InstructionAdapter v = new InstructionAdapter(mv);
143

144 145 146
                for (CodeChunk chunk : staticInitializerChunks) {
                    chunk.generate(v);
                }
147

148
                mv.visitInsn(Opcodes.RETURN);
A
Alex Tkachman 已提交
149
                FunctionCodegen.endVisit(v, "static initializer", myClass);
150
            }
151 152
        }
    }
153
}