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 import org.jetbrains.jet.lang.resolve.java.JvmClassName;
029
030 import java.util.List;
031
032 import static org.jetbrains.asm4.Opcodes.INVOKESPECIAL;
033 import static org.jetbrains.asm4.Opcodes.INVOKESTATIC;
034
035 public class CallableMethod implements Callable {
036 @NotNull
037 private final JvmClassName owner;
038 @Nullable
039 private final JvmClassName defaultImplOwner;
040 @Nullable
041 private final JvmClassName defaultImplParam;
042 private final JvmMethodSignature signature;
043 private final int invokeOpcode;
044 @Nullable
045 private final JvmClassName thisClass;
046 @Nullable
047 private final Type receiverParameterType;
048 @Nullable
049 private final Type generateCalleeType;
050
051 public CallableMethod(
052 @NotNull JvmClassName owner, @Nullable JvmClassName defaultImplOwner, @Nullable JvmClassName defaultImplParam,
053 JvmMethodSignature signature, int invokeOpcode,
054 @Nullable JvmClassName thisClass, @Nullable Type receiverParameterType, @Nullable Type generateCalleeType
055 ) {
056 this.owner = owner;
057 this.defaultImplOwner = defaultImplOwner;
058 this.defaultImplParam = defaultImplParam;
059 this.signature = signature;
060 this.invokeOpcode = invokeOpcode;
061 this.thisClass = thisClass;
062 this.receiverParameterType = receiverParameterType;
063 this.generateCalleeType = generateCalleeType;
064 }
065
066 @NotNull
067 public JvmClassName getOwner() {
068 return owner;
069 }
070
071 @Nullable
072 public JvmClassName getDefaultImplParam() {
073 return defaultImplParam;
074 }
075
076 public JvmMethodSignature getSignature() {
077 return signature;
078 }
079
080 public int getInvokeOpcode() {
081 return invokeOpcode;
082 }
083
084 public List<Type> getValueParameterTypes() {
085 return signature.getValueParameterTypes();
086 }
087
088 @Nullable
089 public JvmClassName getThisType() {
090 return thisClass;
091 }
092
093 @Nullable
094 public Type getReceiverClass() {
095 return receiverParameterType;
096 }
097
098 private void invoke(InstructionAdapter v) {
099 v.visitMethodInsn(getInvokeOpcode(), owner.getInternalName(), getSignature().getAsmMethod().getName(),
100 getSignature().getAsmMethod().getDescriptor());
101 }
102
103 public void invokeWithNotNullAssertion(
104 @NotNull InstructionAdapter v,
105 @NotNull GenerationState state,
106 @NotNull ResolvedCall resolvedCall
107 ) {
108 invokeWithoutAssertions(v);
109 AsmUtil.genNotNullAssertionForMethod(v, state, resolvedCall);
110 }
111
112 public void invokeWithoutAssertions(@NotNull InstructionAdapter v) {
113 invoke(v);
114 }
115
116 @Nullable
117 public Type getGenerateCalleeType() {
118 return generateCalleeType;
119 }
120
121 private void invokeDefault(InstructionAdapter v, int mask) {
122 if (defaultImplOwner == null || defaultImplParam == null) {
123 throw new IllegalStateException();
124 }
125
126 v.iconst(mask);
127 String desc = getSignature().getAsmMethod().getDescriptor().replace(")", "I)");
128 if ("<init>".equals(getSignature().getAsmMethod().getName())) {
129 v.visitMethodInsn(INVOKESPECIAL, defaultImplOwner.getInternalName(), "<init>", desc);
130 }
131 else {
132 if (getInvokeOpcode() != INVOKESTATIC) {
133 desc = desc.replace("(", "(" + defaultImplParam.getDescriptor());
134 }
135 v.visitMethodInsn(INVOKESTATIC, defaultImplOwner.getInternalName(),
136 getSignature().getAsmMethod().getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, desc);
137 }
138 }
139
140 public void invokeDefaultWithNotNullAssertion(
141 @NotNull InstructionAdapter v,
142 @NotNull GenerationState state,
143 @NotNull ResolvedCall resolvedCall,
144 int mask
145 ) {
146 invokeDefault(v, mask);
147 AsmUtil.genNotNullAssertionForMethod(v, state, resolvedCall);
148 }
149
150 public boolean isNeedsThis() {
151 return thisClass != null && generateCalleeType == null;
152 }
153
154 public Type getReturnType() {
155 return signature.getAsmMethod().getReturnType();
156 }
157
158 @Override
159 public String toString() {
160 StringBuilder sb = new StringBuilder();
161 sb.append(Printer.OPCODES[invokeOpcode]);
162 sb.append(" ");
163 sb.append(owner);
164 sb.append(".");
165 sb.append(signature);
166 return sb.toString();
167 }
168 }