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