001 /* 002 * Copyright 2010-2015 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.kotlin.codegen; 018 019 import org.jetbrains.annotations.NotNull; 020 import org.jetbrains.annotations.Nullable; 021 import org.jetbrains.kotlin.codegen.state.GenerationState; 022 import org.jetbrains.kotlin.codegen.state.JetTypeMapper; 023 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; 024 import org.jetbrains.kotlin.load.java.JvmAbi; 025 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind; 026 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature; 027 import org.jetbrains.kotlin.resolve.jvm.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 }