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