001 /*
002 * Copyright 2010-2015 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.kotlin.codegen.intrinsics;
018
019 import com.google.common.collect.ImmutableList;
020 import kotlin.StringsKt;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
024 import org.jetbrains.kotlin.builtins.PrimitiveType;
025 import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
026 import org.jetbrains.kotlin.name.Name;
027 import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils;
028 import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType;
029 import org.jetbrains.kotlin.types.expressions.OperatorConventions;
030 import org.jetbrains.kotlin.util.capitalizeDecapitalize.CapitalizeDecapitalizeKt;
031
032 import java.util.HashMap;
033 import java.util.Map;
034
035 import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME;
036 import static org.jetbrains.org.objectweb.asm.Opcodes.*;
037
038 public class IntrinsicMethods {
039 public static final String INTRINSICS_CLASS_NAME = "kotlin/jvm/internal/Intrinsics";
040
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 Equals EQUALS = new Equals();
052 private static final IdentityEquals IDENTITY_EQUALS = new IdentityEquals();
053 private static final IteratorNext ITERATOR_NEXT = new IteratorNext();
054 private static final ArraySet ARRAY_SET = new ArraySet();
055 private static final ArrayGet ARRAY_GET = new ArrayGet();
056 private static final StringPlus STRING_PLUS = new StringPlus();
057 private static final ToString TO_STRING = new ToString();
058 private static final Clone CLONE = new Clone();
059
060 private final Map<String, IntrinsicMethod> namedMethods = new HashMap<String, IntrinsicMethod>();
061 private static final IntrinsicMethod ARRAY_ITERATOR = new ArrayIterator();
062 private final IntrinsicsMap intrinsicsMap = new IntrinsicsMap();
063
064 public IntrinsicMethods() {
065 namedMethods.put("kotlin.javaClass.function", new JavaClassFunction());
066 namedMethods.put("kotlin.javaClass.property", new JavaClassProperty());
067 namedMethods.put("kotlin.KClass.java.property", new KClassJavaProperty());
068 namedMethods.put("kotlin.jvm.internal.unsafe.monitorEnter", MonitorInstruction.MONITOR_ENTER);
069 namedMethods.put("kotlin.jvm.internal.unsafe.monitorExit", MonitorInstruction.MONITOR_EXIT);
070 namedMethods.put("kotlin.jvm.isArrayOf", new IsArrayOf());
071
072 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, null, "arrayOf", 1, new JavaClassArray());
073
074 ImmutableList<Name> primitiveCastMethods = OperatorConventions.NUMBER_CONVERSIONS.asList();
075 for (Name method : primitiveCastMethods) {
076 String methodName = method.asString();
077 declareIntrinsicFunction("Number", methodName, 0, NUMBER_CAST);
078 for (PrimitiveType type : PrimitiveType.NUMBER_TYPES) {
079 declareIntrinsicFunction(type.getTypeName().asString(), methodName, 0, NUMBER_CAST);
080 }
081 }
082
083 for (PrimitiveType type : PrimitiveType.NUMBER_TYPES) {
084 String typeName = type.getTypeName().asString();
085 declareIntrinsicFunction(typeName, "plus", 0, UNARY_PLUS);
086 declareIntrinsicFunction(typeName, "unaryPlus", 0, UNARY_PLUS);
087 declareIntrinsicFunction(typeName, "minus", 0, UNARY_MINUS);
088 declareIntrinsicFunction(typeName, "unaryMinus", 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 intrinsicsMap.registerIntrinsic(
102 BUILT_INS_PACKAGE_FQ_NAME, null, StringsKt.decapitalize(type.getArrayTypeName().asString()) + "Of", 1, new JavaClassArray()
103 );
104 }
105
106 declareBinaryOp("plus", IADD);
107 declareBinaryOp("minus", ISUB);
108 declareBinaryOp("times", IMUL);
109 declareBinaryOp("div", IDIV);
110 declareBinaryOp("mod", IREM);
111 declareBinaryOp("shl", ISHL);
112 declareBinaryOp("shr", ISHR);
113 declareBinaryOp("ushr", IUSHR);
114 declareBinaryOp("and", IAND);
115 declareBinaryOp("or", IOR);
116 declareBinaryOp("xor", IXOR);
117
118 declareIntrinsicFunction("Boolean", "not", 0, new Not());
119
120 declareIntrinsicFunction("String", "plus", 1, new Concat());
121 declareIntrinsicFunction("String", "get", 1, new StringGetChar());
122
123 declareIntrinsicFunction("Cloneable", "clone", 0, CLONE);
124
125 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KotlinBuiltIns.FQ_NAMES.any, "toString", 0, TO_STRING);
126 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KotlinBuiltIns.FQ_NAMES.any, "identityEquals", 1, IDENTITY_EQUALS);
127 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KotlinBuiltIns.FQ_NAMES.string, "plus", 1, STRING_PLUS);
128 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, null, "arrayOfNulls", 1, new NewArray());
129
130 for (PrimitiveType type : PrimitiveType.values()) {
131 String typeName = type.getTypeName().asString();
132 declareIntrinsicFunction(typeName, "compareTo", 1, new CompareTo());
133 declareIntrinsicFunction(typeName + "Iterator", "next", 0, ITERATOR_NEXT);
134 }
135
136 declareArrayMethods();
137 }
138
139 private void declareArrayMethods() {
140 for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) {
141 declareArrayMethodsForPrimitive(jvmPrimitiveType);
142 }
143
144 declareIntrinsicFunction("Array", "size", -1, ARRAY_SIZE);
145 declareIntrinsicFunction("Array", "set", 2, ARRAY_SET);
146 declareIntrinsicFunction("Array", "get", 1, ARRAY_GET);
147 declareIntrinsicFunction("Array", "clone", 0, CLONE);
148 declareIterator("Array");
149 }
150
151 private void declareArrayMethodsForPrimitive(@NotNull JvmPrimitiveType jvmPrimitiveType) {
152 String arrayTypeName = jvmPrimitiveType.getPrimitiveType().getArrayTypeName().asString();
153 declareIntrinsicFunction(arrayTypeName, "size", -1, ARRAY_SIZE);
154 declareIntrinsicFunction(arrayTypeName, "set", 2, ARRAY_SET);
155 declareIntrinsicFunction(arrayTypeName, "get", 1, ARRAY_GET);
156 declareIntrinsicFunction(arrayTypeName, "clone", 0, CLONE);
157 declareIterator(arrayTypeName);
158 }
159
160 private void declareIterator(@NotNull String arrayClassName) {
161 declareIntrinsicFunction(arrayClassName, "iterator", 0, ARRAY_ITERATOR);
162 }
163
164 private void declareBinaryOp(@NotNull String methodName, int opcode) {
165 BinaryOp op = new BinaryOp(opcode);
166 for (PrimitiveType type : PrimitiveType.values()) {
167 declareIntrinsicFunction(type.getTypeName().asString(), methodName, 1, op);
168 }
169 }
170
171 private void declareIntrinsicFunction(
172 @NotNull String className,
173 @NotNull String methodName,
174 int arity,
175 @NotNull IntrinsicMethod implementation
176 ) {
177 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME.child(Name.identifier(className)),
178 null, methodName, arity, implementation);
179 }
180
181 @Nullable
182 public IntrinsicMethod getIntrinsic(@NotNull CallableMemberDescriptor descriptor) {
183 IntrinsicMethod intrinsicMethod = intrinsicsMap.getIntrinsic(descriptor);
184 if (intrinsicMethod != null) {
185 return intrinsicMethod;
186 }
187
188 String value = CompileTimeConstantUtils.getIntrinsicAnnotationArgument(descriptor);
189 if (value != null) {
190 return namedMethods.get(value);
191 }
192
193 return null;
194 }
195 }