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 }