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