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 017package org.jetbrains.jet.codegen.intrinsics; 018 019import com.google.common.collect.ImmutableList; 020import org.jetbrains.annotations.NotNull; 021import org.jetbrains.annotations.Nullable; 022import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor; 023import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; 024import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor; 025import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; 026import org.jetbrains.jet.lang.resolve.java.JvmPrimitiveType; 027import org.jetbrains.jet.lang.resolve.name.FqName; 028import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; 029import org.jetbrains.jet.lang.resolve.name.Name; 030import org.jetbrains.jet.lang.types.expressions.OperatorConventions; 031import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 032import org.jetbrains.jet.lang.types.lang.PrimitiveType; 033 034import javax.annotation.PostConstruct; 035import java.util.HashMap; 036import java.util.List; 037import java.util.Map; 038 039import static org.jetbrains.asm4.Opcodes.*; 040import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*; 041 042public class IntrinsicMethods { 043 private static final IntrinsicMethod UNARY_MINUS = new UnaryMinus(); 044 private static final IntrinsicMethod UNARY_PLUS = new UnaryPlus(); 045 private static final IntrinsicMethod NUMBER_CAST = new NumberCast(); 046 private static final IntrinsicMethod INV = new Inv(); 047 private static final IntrinsicMethod RANGE_TO = new RangeTo(); 048 private static final IntrinsicMethod INC = new Increment(1); 049 private static final IntrinsicMethod DEC = new Increment(-1); 050 private static final IntrinsicMethod HASH_CODE = new HashCode(); 051 052 private static final IntrinsicMethod ARRAY_SIZE = new ArraySize(); 053 private static final IntrinsicMethod ARRAY_INDICES = new ArrayIndices(); 054 private static final Equals EQUALS = new Equals(); 055 private static final IdentityEquals IDENTITY_EQUALS = new IdentityEquals(); 056 private static final IteratorNext ITERATOR_NEXT = new IteratorNext(); 057 private static final ArraySet ARRAY_SET = new ArraySet(); 058 private static final ArrayGet ARRAY_GET = new ArrayGet(); 059 private static final StringPlus STRING_PLUS = new StringPlus(); 060 public static final String KOTLIN_JAVA_CLASS_FUNCTION = "kotlin.javaClass.function"; 061 public static final String KOTLIN_ARRAYS_ARRAY = "kotlin.arrays.array"; 062 private static final String KOTLIN_JAVA_CLASS_PROPERTY = "kotlin.javaClass.property"; 063 private static final String KOTLIN_TO_STRING = "kotlin.toString"; 064 private static final String KOTLIN_HASH_CODE = "kotlin.hashCode"; 065 private static final EnumValues ENUM_VALUES = new EnumValues(); 066 private static final EnumValueOf ENUM_VALUE_OF = new EnumValueOf(); 067 private static final ToString TO_STRING = new ToString(); 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 074 @PostConstruct 075 public void init() { 076 namedMethods.put(KOTLIN_JAVA_CLASS_FUNCTION, new JavaClassFunction()); 077 namedMethods.put(KOTLIN_JAVA_CLASS_PROPERTY, new JavaClassProperty()); 078 namedMethods.put(KOTLIN_ARRAYS_ARRAY, new JavaClassArray()); 079 namedMethods.put(KOTLIN_HASH_CODE, HASH_CODE); 080 namedMethods.put(KOTLIN_TO_STRING, TO_STRING); 081 082 ImmutableList<Name> primitiveCastMethods = OperatorConventions.NUMBER_CONVERSIONS.asList(); 083 for (Name method : primitiveCastMethods) { 084 declareIntrinsicFunction(Name.identifier("Number"), method, 0, NUMBER_CAST); 085 for (PrimitiveType type : PrimitiveType.NUMBER_TYPES) { 086 declareIntrinsicFunction(type.getTypeName(), method, 0, NUMBER_CAST); 087 } 088 } 089 090 for (PrimitiveType type : PrimitiveType.NUMBER_TYPES) { 091 Name typeName = type.getTypeName(); 092 declareIntrinsicFunction(typeName, Name.identifier("plus"), 0, UNARY_PLUS); 093 declareIntrinsicFunction(typeName, Name.identifier("minus"), 0, UNARY_MINUS); 094 declareIntrinsicFunction(typeName, Name.identifier("inv"), 0, INV); 095 declareIntrinsicFunction(typeName, Name.identifier("rangeTo"), 1, RANGE_TO); 096 declareIntrinsicFunction(typeName, Name.identifier("inc"), 0, INC); 097 declareIntrinsicFunction(typeName, Name.identifier("dec"), 0, DEC); 098 declareIntrinsicFunction(typeName, Name.identifier("hashCode"), 0, HASH_CODE); 099 declareIntrinsicFunction(typeName, Name.identifier("equals"), 1, EQUALS); 100 } 101 102 declareBinaryOp(Name.identifier("plus"), IADD); 103 declareBinaryOp(Name.identifier("minus"), ISUB); 104 declareBinaryOp(Name.identifier("times"), IMUL); 105 declareBinaryOp(Name.identifier("div"), IDIV); 106 declareBinaryOp(Name.identifier("mod"), IREM); 107 declareBinaryOp(Name.identifier("shl"), ISHL); 108 declareBinaryOp(Name.identifier("shr"), ISHR); 109 declareBinaryOp(Name.identifier("ushr"), IUSHR); 110 declareBinaryOp(Name.identifier("and"), IAND); 111 declareBinaryOp(Name.identifier("or"), IOR); 112 declareBinaryOp(Name.identifier("xor"), IXOR); 113 114 declareIntrinsicFunction(Name.identifier("Boolean"), Name.identifier("not"), 0, new Not()); 115 116 declareIntrinsicFunction(Name.identifier("String"), Name.identifier("plus"), 1, new Concat()); 117 declareIntrinsicFunction(Name.identifier("CharSequence"), Name.identifier("get"), 1, new StringGetChar()); 118 declareIntrinsicFunction(Name.identifier("String"), Name.identifier("get"), 1, new StringGetChar()); 119 120 FqName builtInsPackageFqName = KotlinBuiltIns.getInstance().getBuiltInsPackageFqName(); 121 intrinsicsMap.registerIntrinsic(builtInsPackageFqName, Name.identifier("name"), 0, new EnumName()); 122 intrinsicsMap.registerIntrinsic(builtInsPackageFqName, Name.identifier("ordinal"), 0, new EnumOrdinal()); 123 124 intrinsicsMap.registerIntrinsic(builtInsPackageFqName, Name.identifier("toString"), 0, TO_STRING); 125 intrinsicsMap.registerIntrinsic(builtInsPackageFqName, Name.identifier("equals"), 1, EQUALS); 126 intrinsicsMap.registerIntrinsic(builtInsPackageFqName, Name.identifier("identityEquals"), 1, IDENTITY_EQUALS); 127 intrinsicsMap.registerIntrinsic(builtInsPackageFqName, Name.identifier("plus"), 1, STRING_PLUS); 128 intrinsicsMap.registerIntrinsic(builtInsPackageFqName, Name.identifier("arrayOfNulls"), 1, new NewArray()); 129 intrinsicsMap.registerIntrinsic(builtInsPackageFqName, Name.identifier("synchronized"), 2, new StupidSync()); 130 intrinsicsMap.registerIntrinsic(builtInsPackageFqName, Name.identifier("iterator"), 0, new IteratorIterator()); 131 132 133 declareIntrinsicFunction(Name.identifier("ByteIterator"), Name.identifier("next"), 0, ITERATOR_NEXT); 134 declareIntrinsicFunction(Name.identifier("ShortIterator"), Name.identifier("next"), 0, ITERATOR_NEXT); 135 declareIntrinsicFunction(Name.identifier("IntIterator"), Name.identifier("next"), 0, ITERATOR_NEXT); 136 declareIntrinsicFunction(Name.identifier("LongIterator"), Name.identifier("next"), 0, ITERATOR_NEXT); 137 declareIntrinsicFunction(Name.identifier("CharIterator"), Name.identifier("next"), 0, ITERATOR_NEXT); 138 declareIntrinsicFunction(Name.identifier("BooleanIterator"), Name.identifier("next"), 0, ITERATOR_NEXT); 139 declareIntrinsicFunction(Name.identifier("FloatIterator"), Name.identifier("next"), 0, ITERATOR_NEXT); 140 declareIntrinsicFunction(Name.identifier("DoubleIterator"), Name.identifier("next"), 0, ITERATOR_NEXT); 141 142 for (PrimitiveType type : PrimitiveType.values()) { 143 declareIntrinsicFunction(type.getTypeName(), Name.identifier("compareTo"), 1, new CompareTo()); 144 } 145 // declareIntrinsicFunction("Any", "equals", 1, new Equals()); 146 // 147 declareIntrinsicProperty(Name.identifier("CharSequence"), Name.identifier("length"), new StringLength()); 148 declareIntrinsicProperty(Name.identifier("String"), Name.identifier("length"), new StringLength()); 149 150 registerStaticField(getFQName(KotlinBuiltIns.getInstance().getUnit()).toSafe(), Name.identifier("VALUE")); 151 152 for (PrimitiveType type : PrimitiveType.NUMBER_TYPES) { 153 registerStaticField(type.getRangeClassName(), Name.identifier("EMPTY")); 154 } 155 156 for (PrimitiveType type : PrimitiveType.NUMBER_TYPES) { 157 registerRangeOrProgressionProperty(type.getRangeClassName(), Name.identifier("start")); 158 registerRangeOrProgressionProperty(type.getRangeClassName(), Name.identifier("end")); 159 160 registerRangeOrProgressionProperty(type.getProgressionClassName(), Name.identifier("start")); 161 registerRangeOrProgressionProperty(type.getProgressionClassName(), Name.identifier("end")); 162 registerRangeOrProgressionProperty(type.getProgressionClassName(), Name.identifier("increment")); 163 } 164 165 declareArrayMethods(); 166 } 167 168 private void registerStaticField(@NotNull FqName classFqName, @NotNull Name propertyName) { 169 FqNameUnsafe classObjectFqName = classFqName.toUnsafe().child(getClassObjectName(classFqName.shortName())); 170 intrinsicsMap.registerIntrinsic(classObjectFqName, propertyName, -1, new StaticField(classFqName, propertyName)); 171 } 172 173 private void registerRangeOrProgressionProperty(@NotNull FqName ownerClass, @NotNull Name propertyName) { 174 intrinsicsMap.registerIntrinsic(ownerClass, propertyName, -1, new PropertyOfProgressionOrRange(ownerClass, propertyName)); 175 } 176 177 private void declareArrayMethods() { 178 179 for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) { 180 declareArrayMethodsForPrimitive(jvmPrimitiveType); 181 } 182 183 declareIntrinsicProperty(Name.identifier("Array"), Name.identifier("size"), ARRAY_SIZE); 184 declareIntrinsicProperty(Name.identifier("Array"), Name.identifier("indices"), ARRAY_INDICES); 185 declareIntrinsicFunction(Name.identifier("Array"), Name.identifier("set"), 2, ARRAY_SET); 186 declareIntrinsicFunction(Name.identifier("Array"), Name.identifier("get"), 1, ARRAY_GET); 187 declareIterator(Name.identifier("Array")); 188 } 189 190 private void declareArrayMethodsForPrimitive(JvmPrimitiveType jvmPrimitiveType) { 191 PrimitiveType primitiveType = jvmPrimitiveType.getPrimitiveType(); 192 declareIntrinsicProperty(primitiveType.getArrayTypeName(), Name.identifier("size"), ARRAY_SIZE); 193 declareIntrinsicProperty(primitiveType.getArrayTypeName(), Name.identifier("indices"), ARRAY_INDICES); 194 declareIntrinsicFunction(primitiveType.getArrayTypeName(), Name.identifier("set"), 2, ARRAY_SET); 195 declareIntrinsicFunction(primitiveType.getArrayTypeName(), Name.identifier("get"), 1, ARRAY_GET); 196 declareIterator(primitiveType.getArrayTypeName()); 197 } 198 199 private void declareIterator(@NotNull Name arrayClassName) { 200 declareIntrinsicFunction(arrayClassName, Name.identifier("iterator"), 0, ARRAY_ITERATOR); 201 } 202 203 private void declareBinaryOp(Name methodName, int opcode) { 204 BinaryOp op = new BinaryOp(opcode); 205 for (PrimitiveType type : PrimitiveType.values()) { 206 declareIntrinsicFunction(type.getTypeName(), methodName, 1, op); 207 } 208 } 209 210 private void declareIntrinsicProperty(Name className, Name methodName, IntrinsicMethod implementation) { 211 intrinsicsMap.registerIntrinsic(KotlinBuiltIns.getInstance().getBuiltInsPackageFqName().child(className), methodName, -1, implementation); 212 } 213 214 private void declareIntrinsicFunction(Name className, Name functionName, int arity, IntrinsicMethod implementation) { 215 intrinsicsMap.registerIntrinsic(KotlinBuiltIns.getInstance().getBuiltInsPackageFqName().child(className), functionName, arity, implementation); 216 } 217 218 @Nullable 219 public IntrinsicMethod getIntrinsic(@NotNull CallableMemberDescriptor descriptor) { 220 IntrinsicMethod intrinsicMethod = intrinsicsMap.getIntrinsic(descriptor); 221 if (intrinsicMethod != null) { 222 return intrinsicMethod; 223 } 224 225 if (descriptor instanceof SimpleFunctionDescriptor) { 226 SimpleFunctionDescriptor functionDescriptor = (SimpleFunctionDescriptor) descriptor; 227 228 if (isEnumClassObject(functionDescriptor.getContainingDeclaration())) { 229 if (isEnumValuesMethod(functionDescriptor)) { 230 return ENUM_VALUES; 231 } 232 233 if (isEnumValueOfMethod(functionDescriptor)) { 234 return ENUM_VALUE_OF; 235 } 236 } 237 } 238 239 List<AnnotationDescriptor> annotations = descriptor.getAnnotations(); 240 if (annotations != null) { 241 for (AnnotationDescriptor annotation : annotations) { 242 ClassifierDescriptor classifierDescriptor = annotation.getType().getConstructor().getDeclarationDescriptor(); 243 assert classifierDescriptor != null; 244 if ("Intrinsic".equals(classifierDescriptor.getName().asString())) { 245 String value = (String) annotation.getAllValueArguments().values().iterator().next().getValue(); 246 intrinsicMethod = namedMethods.get(value); 247 if (intrinsicMethod != null) { 248 break; 249 } 250 } 251 } 252 } 253 return intrinsicMethod; 254 } 255}