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 }