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