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.intrinsics; 018 019 import com.google.common.collect.ImmutableList; 020 import org.jetbrains.annotations.NotNull; 021 import org.jetbrains.annotations.Nullable; 022 import org.jetbrains.jet.codegen.JvmCodegenUtil; 023 import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor; 024 import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; 025 import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor; 026 import org.jetbrains.jet.lang.resolve.CompileTimeConstantUtils; 027 import org.jetbrains.jet.lang.resolve.DescriptorUtils; 028 import org.jetbrains.jet.lang.resolve.java.JvmPrimitiveType; 029 import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; 030 import org.jetbrains.jet.lang.resolve.name.Name; 031 import org.jetbrains.jet.lang.types.expressions.OperatorConventions; 032 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 033 import org.jetbrains.jet.lang.types.lang.PrimitiveType; 034 035 import java.util.HashMap; 036 import java.util.Map; 037 038 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject; 039 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumClass; 040 import static org.jetbrains.jet.lang.types.lang.KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME; 041 import static org.jetbrains.org.objectweb.asm.Opcodes.*; 042 043 public class IntrinsicMethods { 044 private static final IntrinsicMethod UNARY_MINUS = new UnaryMinus(); 045 private static final IntrinsicMethod UNARY_PLUS = new UnaryPlus(); 046 private static final IntrinsicMethod NUMBER_CAST = new NumberCast(); 047 private static final IntrinsicMethod INV = new Inv(); 048 private static final IntrinsicMethod RANGE_TO = new RangeTo(); 049 private static final IntrinsicMethod INC = new Increment(1); 050 private static final IntrinsicMethod DEC = new Increment(-1); 051 private static final IntrinsicMethod HASH_CODE = new HashCode(); 052 053 private static final IntrinsicMethod ARRAY_SIZE = new ArraySize(); 054 private static final IntrinsicMethod ARRAY_INDICES = new ArrayIndices(); 055 private static final Equals EQUALS = new Equals(); 056 private static final IdentityEquals IDENTITY_EQUALS = new IdentityEquals(); 057 private static final IteratorNext ITERATOR_NEXT = new IteratorNext(); 058 private static final ArraySet ARRAY_SET = new ArraySet(); 059 private static final ArrayGet ARRAY_GET = new ArrayGet(); 060 private static final StringPlus STRING_PLUS = new StringPlus(); 061 private static final EnumValues ENUM_VALUES = new EnumValues(); 062 private static final EnumValueOf ENUM_VALUE_OF = new EnumValueOf(); 063 private static final ToString TO_STRING = new ToString(); 064 private static final Clone CLONE = new Clone(); 065 066 private static final FqNameUnsafe KOTLIN_ANY_FQ_NAME = DescriptorUtils.getFqName(KotlinBuiltIns.getInstance().getAny()); 067 private static final FqNameUnsafe KOTLIN_STRING_FQ_NAME = DescriptorUtils.getFqName(KotlinBuiltIns.getInstance().getString()); 068 069 private final Map<String, IntrinsicMethod> namedMethods = new HashMap<String, IntrinsicMethod>(); 070 private static final IntrinsicMethod ARRAY_ITERATOR = new ArrayIterator(); 071 private final IntrinsicsMap intrinsicsMap = new IntrinsicsMap(); 072 073 public IntrinsicMethods() { 074 namedMethods.put("kotlin.javaClass.function", new JavaClassFunction()); 075 namedMethods.put("kotlin.javaClass.property", new JavaClassProperty()); 076 namedMethods.put("kotlin.arrays.array", new JavaClassArray()); 077 namedMethods.put("kotlin.collections.copyToArray", new CopyToArray()); 078 namedMethods.put("kotlin.jvm.internal.unsafe.monitorEnter", MonitorInstruction.MONITOR_ENTER); 079 namedMethods.put("kotlin.jvm.internal.unsafe.monitorExit", MonitorInstruction.MONITOR_EXIT); 080 081 ImmutableList<Name> primitiveCastMethods = OperatorConventions.NUMBER_CONVERSIONS.asList(); 082 for (Name method : primitiveCastMethods) { 083 String methodName = method.asString(); 084 declareIntrinsicFunction("Number", methodName, 0, NUMBER_CAST); 085 for (PrimitiveType type : PrimitiveType.NUMBER_TYPES) { 086 declareIntrinsicFunction(type.getTypeName().asString(), methodName, 0, NUMBER_CAST); 087 } 088 } 089 090 for (PrimitiveType type : PrimitiveType.NUMBER_TYPES) { 091 String typeName = type.getTypeName().asString(); 092 declareIntrinsicFunction(typeName, "plus", 0, UNARY_PLUS); 093 declareIntrinsicFunction(typeName, "minus", 0, UNARY_MINUS); 094 declareIntrinsicFunction(typeName, "inv", 0, INV); 095 declareIntrinsicFunction(typeName, "rangeTo", 1, RANGE_TO); 096 declareIntrinsicFunction(typeName, "inc", 0, INC); 097 declareIntrinsicFunction(typeName, "dec", 0, DEC); 098 } 099 100 for (PrimitiveType type : PrimitiveType.values()) { 101 String typeName = type.getTypeName().asString(); 102 declareIntrinsicFunction(typeName, "equals", 1, EQUALS); 103 declareIntrinsicFunction(typeName, "hashCode", 0, HASH_CODE); 104 declareIntrinsicFunction(typeName, "toString", 0, TO_STRING); 105 } 106 107 declareBinaryOp("plus", IADD); 108 declareBinaryOp("minus", ISUB); 109 declareBinaryOp("times", IMUL); 110 declareBinaryOp("div", IDIV); 111 declareBinaryOp("mod", IREM); 112 declareBinaryOp("shl", ISHL); 113 declareBinaryOp("shr", ISHR); 114 declareBinaryOp("ushr", IUSHR); 115 declareBinaryOp("and", IAND); 116 declareBinaryOp("or", IOR); 117 declareBinaryOp("xor", IXOR); 118 119 declareIntrinsicFunction("Boolean", "not", 0, new Not()); 120 121 declareIntrinsicFunction("String", "plus", 1, new Concat()); 122 declareIntrinsicFunction("CharSequence", "get", 1, new StringGetChar()); 123 declareIntrinsicFunction("String", "get", 1, new StringGetChar()); 124 125 declareIntrinsicFunction("Cloneable", "clone", 0, CLONE); 126 127 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KOTLIN_ANY_FQ_NAME, "toString", 0, TO_STRING); 128 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KOTLIN_ANY_FQ_NAME, "equals", 1, EQUALS); 129 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KOTLIN_ANY_FQ_NAME, "identityEquals", 1, IDENTITY_EQUALS); 130 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KOTLIN_STRING_FQ_NAME, "plus", 1, STRING_PLUS); 131 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, null, "arrayOfNulls", 1, new NewArray()); 132 133 for (PrimitiveType type : PrimitiveType.values()) { 134 String typeName = type.getTypeName().asString(); 135 declareIntrinsicFunction(typeName, "compareTo", 1, new CompareTo()); 136 declareIntrinsicFunction(typeName + "Iterator", "next", 0, ITERATOR_NEXT); 137 } 138 139 declareIntrinsicProperty("CharSequence", "length", new StringLength()); 140 declareIntrinsicProperty("String", "length", new StringLength()); 141 142 declareArrayMethods(); 143 } 144 145 private void declareArrayMethods() { 146 for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) { 147 declareArrayMethodsForPrimitive(jvmPrimitiveType); 148 } 149 150 declareIntrinsicProperty("Array", "size", ARRAY_SIZE); 151 declareIntrinsicProperty("Array", "indices", ARRAY_INDICES); 152 declareIntrinsicFunction("Array", "set", 2, ARRAY_SET); 153 declareIntrinsicFunction("Array", "get", 1, ARRAY_GET); 154 declareIntrinsicFunction("Array", "clone", 0, CLONE); 155 declareIterator("Array"); 156 } 157 158 private void declareArrayMethodsForPrimitive(@NotNull JvmPrimitiveType jvmPrimitiveType) { 159 String arrayTypeName = jvmPrimitiveType.getPrimitiveType().getArrayTypeName().asString(); 160 declareIntrinsicProperty(arrayTypeName, "size", ARRAY_SIZE); 161 declareIntrinsicProperty(arrayTypeName, "indices", ARRAY_INDICES); 162 declareIntrinsicFunction(arrayTypeName, "set", 2, ARRAY_SET); 163 declareIntrinsicFunction(arrayTypeName, "get", 1, ARRAY_GET); 164 declareIntrinsicFunction(arrayTypeName, "clone", 0, CLONE); 165 declareIterator(arrayTypeName); 166 } 167 168 private void declareIterator(@NotNull String arrayClassName) { 169 declareIntrinsicFunction(arrayClassName, "iterator", 0, ARRAY_ITERATOR); 170 } 171 172 private void declareBinaryOp(@NotNull String methodName, int opcode) { 173 BinaryOp op = new BinaryOp(opcode); 174 for (PrimitiveType type : PrimitiveType.values()) { 175 declareIntrinsicFunction(type.getTypeName().asString(), methodName, 1, op); 176 } 177 } 178 179 private void declareIntrinsicProperty(@NotNull String className, @NotNull String methodName, @NotNull IntrinsicMethod implementation) { 180 declareIntrinsicFunction(className, methodName, -1, implementation); 181 } 182 183 private void declareIntrinsicFunction( 184 @NotNull String className, 185 @NotNull String methodName, 186 int arity, 187 @NotNull IntrinsicMethod implementation 188 ) { 189 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME.child(Name.identifier(className)), 190 null, methodName, arity, implementation); 191 } 192 193 @Nullable 194 public IntrinsicMethod getIntrinsic(@NotNull CallableMemberDescriptor descriptor) { 195 IntrinsicMethod intrinsicMethod = intrinsicsMap.getIntrinsic(descriptor); 196 if (intrinsicMethod != null) { 197 return intrinsicMethod; 198 } 199 200 if (descriptor instanceof SimpleFunctionDescriptor) { 201 SimpleFunctionDescriptor functionDescriptor = (SimpleFunctionDescriptor) descriptor; 202 203 DeclarationDescriptor container = descriptor.getContainingDeclaration(); 204 //noinspection ConstantConditions 205 if (isClassObject(container) && isEnumClass(container.getContainingDeclaration())) { 206 if (JvmCodegenUtil.isEnumValuesMethod(functionDescriptor)) { 207 return ENUM_VALUES; 208 } 209 210 if (JvmCodegenUtil.isEnumValueOfMethod(functionDescriptor)) { 211 return ENUM_VALUE_OF; 212 } 213 } 214 } 215 216 String value = CompileTimeConstantUtils.getIntrinsicAnnotationArgument(descriptor); 217 if (value == null) return null; 218 219 return namedMethods.get(value); 220 } 221 }