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