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