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