001    /*
002     * Copyright 2010-2013 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.jet.codegen;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.asm4.Type;
022    import org.jetbrains.asm4.commons.InstructionAdapter;
023    import org.jetbrains.asm4.util.Printer;
024    import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
025    import org.jetbrains.jet.codegen.state.GenerationState;
026    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
027    import org.jetbrains.jet.lang.resolve.java.JvmAbi;
028    
029    import java.util.List;
030    
031    import static org.jetbrains.asm4.Opcodes.INVOKESPECIAL;
032    import static org.jetbrains.asm4.Opcodes.INVOKESTATIC;
033    
034    public class CallableMethod implements Callable {
035        @NotNull
036        private final Type owner;
037        @Nullable
038        private final Type defaultImplOwner;
039        @Nullable
040        private final Type defaultImplParam;
041        private final JvmMethodSignature signature;
042        private final int invokeOpcode;
043        @Nullable
044        private final Type thisClass;
045        @Nullable
046        private final Type receiverParameterType;
047        @Nullable
048        private final Type generateCalleeType;
049    
050        public CallableMethod(
051                @NotNull Type owner, @Nullable Type defaultImplOwner, @Nullable Type defaultImplParam,
052                JvmMethodSignature signature, int invokeOpcode,
053                @Nullable Type thisClass, @Nullable Type receiverParameterType, @Nullable Type generateCalleeType
054        ) {
055            this.owner = owner;
056            this.defaultImplOwner = defaultImplOwner;
057            this.defaultImplParam = defaultImplParam;
058            this.signature = signature;
059            this.invokeOpcode = invokeOpcode;
060            this.thisClass = thisClass;
061            this.receiverParameterType = receiverParameterType;
062            this.generateCalleeType = generateCalleeType;
063        }
064    
065        @NotNull
066        public Type getOwner() {
067            return owner;
068        }
069    
070        public JvmMethodSignature getSignature() {
071            return signature;
072        }
073    
074        public int getInvokeOpcode() {
075            return invokeOpcode;
076        }
077    
078        public List<Type> getValueParameterTypes() {
079            return signature.getValueParameterTypes();
080        }
081    
082        @Nullable
083        public Type getThisType() {
084            return thisClass;
085        }
086    
087        @Nullable
088        public Type getReceiverClass() {
089            return receiverParameterType;
090        }
091    
092        private void invoke(InstructionAdapter v) {
093            v.visitMethodInsn(getInvokeOpcode(), owner.getInternalName(), getSignature().getAsmMethod().getName(),
094                              getSignature().getAsmMethod().getDescriptor());
095        }
096    
097        public void invokeWithNotNullAssertion(
098                @NotNull InstructionAdapter v,
099                @NotNull GenerationState state,
100                @NotNull ResolvedCall resolvedCall
101        ) {
102            invokeWithoutAssertions(v);
103            AsmUtil.genNotNullAssertionForMethod(v, state, resolvedCall);
104        }
105    
106        public void invokeWithoutAssertions(@NotNull InstructionAdapter v) {
107            invoke(v);
108        }
109    
110        @Nullable
111        public Type getGenerateCalleeType() {
112            return generateCalleeType;
113        }
114    
115        private void invokeDefault(InstructionAdapter v, int mask) {
116            if (defaultImplOwner == null || defaultImplParam == null) {
117                throw new IllegalStateException();
118            }
119    
120            v.iconst(mask);
121            String desc = getSignature().getAsmMethod().getDescriptor().replace(")", "I)");
122            if ("<init>".equals(getSignature().getAsmMethod().getName())) {
123                v.visitMethodInsn(INVOKESPECIAL, defaultImplOwner.getInternalName(), "<init>", desc);
124            }
125            else {
126                if (getInvokeOpcode() != INVOKESTATIC) {
127                    desc = desc.replace("(", "(" + defaultImplParam.getDescriptor());
128                }
129                v.visitMethodInsn(INVOKESTATIC, defaultImplOwner.getInternalName(),
130                                  getSignature().getAsmMethod().getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, desc);
131            }
132        }
133    
134        public void invokeDefaultWithNotNullAssertion(
135                @NotNull InstructionAdapter v,
136                @NotNull GenerationState state,
137                @NotNull ResolvedCall resolvedCall,
138                int mask
139        ) {
140            invokeDefault(v, mask);
141            AsmUtil.genNotNullAssertionForMethod(v, state, resolvedCall);
142        }
143    
144        public boolean isNeedsThis() {
145            return thisClass != null && generateCalleeType == null;
146        }
147    
148        public Type getReturnType() {
149            return signature.getAsmMethod().getReturnType();
150        }
151    
152        @Override
153        public String toString() {
154            return Printer.OPCODES[invokeOpcode] + " " + owner + "." + signature;
155        }
156    }