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 }