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.List;
039 import java.util.Map;
040
041 import static org.jetbrains.asm4.Opcodes.*;
042 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
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 FqName builtInsPackageFqName = KotlinBuiltIns.getInstance().getBuiltInsPackageFqName();
126 intrinsicsMap.registerIntrinsic(builtInsPackageFqName, Name.identifier("name"), 0, new EnumName());
127 intrinsicsMap.registerIntrinsic(builtInsPackageFqName, Name.identifier("ordinal"), 0, new EnumOrdinal());
128
129 intrinsicsMap.registerIntrinsic(builtInsPackageFqName, Name.identifier("toString"), 0, TO_STRING);
130 intrinsicsMap.registerIntrinsic(builtInsPackageFqName, Name.identifier("equals"), 1, EQUALS);
131 intrinsicsMap.registerIntrinsic(builtInsPackageFqName, Name.identifier("identityEquals"), 1, IDENTITY_EQUALS);
132 intrinsicsMap.registerIntrinsic(builtInsPackageFqName, Name.identifier("plus"), 1, STRING_PLUS);
133 intrinsicsMap.registerIntrinsic(builtInsPackageFqName, Name.identifier("arrayOfNulls"), 1, new NewArray());
134 intrinsicsMap.registerIntrinsic(builtInsPackageFqName, Name.identifier("synchronized"), 2, new StupidSync());
135 intrinsicsMap.registerIntrinsic(builtInsPackageFqName, Name.identifier("iterator"), 0, new IteratorIterator());
136
137
138 declareIntrinsicFunction(Name.identifier("ByteIterator"), Name.identifier("next"), 0, ITERATOR_NEXT);
139 declareIntrinsicFunction(Name.identifier("ShortIterator"), Name.identifier("next"), 0, ITERATOR_NEXT);
140 declareIntrinsicFunction(Name.identifier("IntIterator"), Name.identifier("next"), 0, ITERATOR_NEXT);
141 declareIntrinsicFunction(Name.identifier("LongIterator"), Name.identifier("next"), 0, ITERATOR_NEXT);
142 declareIntrinsicFunction(Name.identifier("CharIterator"), Name.identifier("next"), 0, ITERATOR_NEXT);
143 declareIntrinsicFunction(Name.identifier("BooleanIterator"), Name.identifier("next"), 0, ITERATOR_NEXT);
144 declareIntrinsicFunction(Name.identifier("FloatIterator"), Name.identifier("next"), 0, ITERATOR_NEXT);
145 declareIntrinsicFunction(Name.identifier("DoubleIterator"), Name.identifier("next"), 0, ITERATOR_NEXT);
146
147 for (PrimitiveType type : PrimitiveType.values()) {
148 declareIntrinsicFunction(type.getTypeName(), Name.identifier("compareTo"), 1, new CompareTo());
149 }
150 // declareIntrinsicFunction("Any", "equals", 1, new Equals());
151 //
152 declareIntrinsicProperty(Name.identifier("CharSequence"), Name.identifier("length"), new StringLength());
153 declareIntrinsicProperty(Name.identifier("String"), Name.identifier("length"), new StringLength());
154
155 registerStaticField(getFQName(KotlinBuiltIns.getInstance().getUnit()).toSafe(), Name.identifier("VALUE"));
156
157 for (PrimitiveType type : PrimitiveType.NUMBER_TYPES) {
158 FqName rangeClassFqName = RangeCodegenUtil.getRangeClassFqName(type);
159 FqName progressionClassFqName = RangeCodegenUtil.getProgressionClassFqName(type);
160
161 registerStaticField(rangeClassFqName, Name.identifier("EMPTY"));
162
163 registerRangeOrProgressionProperty(rangeClassFqName, Name.identifier("start"));
164 registerRangeOrProgressionProperty(rangeClassFqName, Name.identifier("end"));
165
166 registerRangeOrProgressionProperty(progressionClassFqName, Name.identifier("start"));
167 registerRangeOrProgressionProperty(progressionClassFqName, Name.identifier("end"));
168 registerRangeOrProgressionProperty(progressionClassFqName, Name.identifier("increment"));
169 }
170
171 declareArrayMethods();
172 }
173
174 private void registerStaticField(@NotNull FqName classFqName, @NotNull Name propertyName) {
175 FqNameUnsafe classObjectFqName = classFqName.toUnsafe().child(SpecialNames.getClassObjectName(classFqName.shortName()));
176 intrinsicsMap.registerIntrinsic(classObjectFqName, propertyName, -1, new StaticField(classFqName, propertyName));
177 }
178
179 private void registerRangeOrProgressionProperty(@NotNull FqName ownerClass, @NotNull Name propertyName) {
180 intrinsicsMap.registerIntrinsic(ownerClass, propertyName, -1, new PropertyOfProgressionOrRange(ownerClass, propertyName));
181 }
182
183 private void declareArrayMethods() {
184
185 for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) {
186 declareArrayMethodsForPrimitive(jvmPrimitiveType);
187 }
188
189 declareIntrinsicProperty(Name.identifier("Array"), Name.identifier("size"), ARRAY_SIZE);
190 declareIntrinsicProperty(Name.identifier("Array"), Name.identifier("indices"), ARRAY_INDICES);
191 declareIntrinsicFunction(Name.identifier("Array"), Name.identifier("set"), 2, ARRAY_SET);
192 declareIntrinsicFunction(Name.identifier("Array"), Name.identifier("get"), 1, ARRAY_GET);
193 declareIterator(Name.identifier("Array"));
194 }
195
196 private void declareArrayMethodsForPrimitive(JvmPrimitiveType jvmPrimitiveType) {
197 PrimitiveType primitiveType = jvmPrimitiveType.getPrimitiveType();
198 declareIntrinsicProperty(primitiveType.getArrayTypeName(), Name.identifier("size"), ARRAY_SIZE);
199 declareIntrinsicProperty(primitiveType.getArrayTypeName(), Name.identifier("indices"), ARRAY_INDICES);
200 declareIntrinsicFunction(primitiveType.getArrayTypeName(), Name.identifier("set"), 2, ARRAY_SET);
201 declareIntrinsicFunction(primitiveType.getArrayTypeName(), Name.identifier("get"), 1, ARRAY_GET);
202 declareIterator(primitiveType.getArrayTypeName());
203 }
204
205 private void declareIterator(@NotNull Name arrayClassName) {
206 declareIntrinsicFunction(arrayClassName, Name.identifier("iterator"), 0, ARRAY_ITERATOR);
207 }
208
209 private void declareBinaryOp(Name methodName, int opcode) {
210 BinaryOp op = new BinaryOp(opcode);
211 for (PrimitiveType type : PrimitiveType.values()) {
212 declareIntrinsicFunction(type.getTypeName(), methodName, 1, op);
213 }
214 }
215
216 private void declareIntrinsicProperty(Name className, Name methodName, IntrinsicMethod implementation) {
217 intrinsicsMap.registerIntrinsic(KotlinBuiltIns.getInstance().getBuiltInsPackageFqName().child(className), methodName, -1, implementation);
218 }
219
220 private void declareIntrinsicFunction(Name className, Name functionName, int arity, IntrinsicMethod implementation) {
221 intrinsicsMap.registerIntrinsic(KotlinBuiltIns.getInstance().getBuiltInsPackageFqName().child(className), functionName, arity, implementation);
222 }
223
224 @Nullable
225 public IntrinsicMethod getIntrinsic(@NotNull CallableMemberDescriptor descriptor) {
226 IntrinsicMethod intrinsicMethod = intrinsicsMap.getIntrinsic(descriptor);
227 if (intrinsicMethod != null) {
228 return intrinsicMethod;
229 }
230
231 if (descriptor instanceof SimpleFunctionDescriptor) {
232 SimpleFunctionDescriptor functionDescriptor = (SimpleFunctionDescriptor) descriptor;
233
234 if (isEnumClassObject(functionDescriptor.getContainingDeclaration())) {
235 if (isEnumValuesMethod(functionDescriptor)) {
236 return ENUM_VALUES;
237 }
238
239 if (isEnumValueOfMethod(functionDescriptor)) {
240 return ENUM_VALUE_OF;
241 }
242 }
243 }
244
245 List<AnnotationDescriptor> annotations = descriptor.getAnnotations();
246 if (annotations != null) {
247 for (AnnotationDescriptor annotation : annotations) {
248 ClassifierDescriptor classifierDescriptor = annotation.getType().getConstructor().getDeclarationDescriptor();
249 assert classifierDescriptor != null;
250 if ("Intrinsic".equals(classifierDescriptor.getName().asString())) {
251 String value = (String) annotation.getAllValueArguments().values().iterator().next().getValue();
252 intrinsicMethod = namedMethods.get(value);
253 if (intrinsicMethod != null) {
254 break;
255 }
256 }
257 }
258 }
259 return intrinsicMethod;
260 }
261 }