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.getInternalName() + "." + signature; 155 } 156 }