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.text.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.FqName;
027 import org.jetbrains.kotlin.name.FqNameUnsafe;
028 import org.jetbrains.kotlin.name.Name;
029 import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType;
030 import org.jetbrains.kotlin.types.expressions.OperatorConventions;
031
032 import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.*;
033 import static org.jetbrains.org.objectweb.asm.Opcodes.*;
034
035 public class IntrinsicMethods {
036 public static final String INTRINSICS_CLASS_NAME = "kotlin/jvm/internal/Intrinsics";
037
038 private static final FqName KOTLIN_JVM = new FqName("kotlin.jvm");
039 /* package */ static final FqNameUnsafe RECEIVER_PARAMETER_FQ_NAME = new FqNameUnsafe("T");
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 IteratorNext ITERATOR_NEXT = new IteratorNext();
053 private static final ArraySet ARRAY_SET = new ArraySet();
054 private static final ArrayGet ARRAY_GET = new ArrayGet();
055 private static final StringPlus STRING_PLUS = new StringPlus();
056 private static final ToString TO_STRING = new ToString();
057 private static final Clone CLONE = new Clone();
058
059 private static final IntrinsicMethod ARRAY_ITERATOR = new ArrayIterator();
060 private final IntrinsicsMap intrinsicsMap = new IntrinsicsMap();
061
062 public IntrinsicMethods() {
063 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, null, "javaClass", 0, new JavaClassFunction());
064 intrinsicsMap.registerIntrinsic(KOTLIN_JVM, RECEIVER_PARAMETER_FQ_NAME, "javaClass", -1, new JavaClassProperty());
065 intrinsicsMap.registerIntrinsic(KOTLIN_JVM, KotlinBuiltIns.FQ_NAMES.kClass, "java", -1, new KClassJavaProperty());
066 intrinsicsMap.registerIntrinsic(new FqName("kotlin.jvm.internal.unsafe"), null, "monitorEnter", 1, MonitorInstruction.MONITOR_ENTER);
067 intrinsicsMap.registerIntrinsic(new FqName("kotlin.jvm.internal.unsafe"), null, "monitorExit", 1, MonitorInstruction.MONITOR_EXIT);
068 intrinsicsMap.registerIntrinsic(KOTLIN_JVM, KotlinBuiltIns.FQ_NAMES.array, "isArrayOf", 0, new IsArrayOf());
069
070 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, null, "arrayOf", 1, new JavaClassArray());
071
072 // TODO: drop when deprecated kotlin.javaClass property is gone
073 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, RECEIVER_PARAMETER_FQ_NAME, "javaClass", -1, new JavaClassProperty());
074
075 ImmutableList<Name> primitiveCastMethods = OperatorConventions.NUMBER_CONVERSIONS.asList();
076 for (Name method : primitiveCastMethods) {
077 String methodName = method.asString();
078 declareIntrinsicFunction(FQ_NAMES.number, methodName, 0, NUMBER_CAST);
079 for (PrimitiveType type : PrimitiveType.NUMBER_TYPES) {
080 declareIntrinsicFunction(type.getTypeFqName(), methodName, 0, NUMBER_CAST);
081 }
082 }
083
084 for (PrimitiveType type : PrimitiveType.NUMBER_TYPES) {
085 FqName typeFqName = type.getTypeFqName();
086 declareIntrinsicFunction(typeFqName, "plus", 0, UNARY_PLUS);
087 declareIntrinsicFunction(typeFqName, "unaryPlus", 0, UNARY_PLUS);
088 declareIntrinsicFunction(typeFqName, "minus", 0, UNARY_MINUS);
089 declareIntrinsicFunction(typeFqName, "unaryMinus", 0, UNARY_MINUS);
090 declareIntrinsicFunction(typeFqName, "inv", 0, INV);
091 declareIntrinsicFunction(typeFqName, "rangeTo", 1, RANGE_TO);
092 declareIntrinsicFunction(typeFqName, "inc", 0, INC);
093 declareIntrinsicFunction(typeFqName, "dec", 0, DEC);
094 }
095
096 for (PrimitiveType type : PrimitiveType.values()) {
097 FqName typeFqName = type.getTypeFqName();
098 declareIntrinsicFunction(typeFqName, "equals", 1, EQUALS);
099 declareIntrinsicFunction(typeFqName, "hashCode", 0, HASH_CODE);
100 declareIntrinsicFunction(typeFqName, "toString", 0, TO_STRING);
101
102 intrinsicsMap.registerIntrinsic(
103 BUILT_INS_PACKAGE_FQ_NAME, null, StringsKt.decapitalize(type.getArrayTypeName().asString()) + "Of", 1, new JavaClassArray()
104 );
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(FQ_NAMES._boolean, "not", 0, new Not());
120
121 declareIntrinsicFunction(FQ_NAMES.string, "plus", 1, new Concat());
122 declareIntrinsicFunction(FQ_NAMES.string, "get", 1, new StringGetChar());
123
124 declareIntrinsicFunction(FQ_NAMES.cloneable, "clone", 0, CLONE);
125
126 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KotlinBuiltIns.FQ_NAMES.any, "toString", 0, TO_STRING);
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 declareIntrinsicFunction(type.getTypeFqName(), "compareTo", 1, new CompareTo());
132 declareIntrinsicFunction(COLLECTIONS_PACKAGE_FQ_NAME.child(Name.identifier(type.getTypeName().asString() + "Iterator")), "next", 0, ITERATOR_NEXT);
133 }
134
135 declareArrayMethods();
136 }
137
138 private void declareArrayMethods() {
139 for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) {
140 declareArrayMethods(jvmPrimitiveType.getPrimitiveType().getArrayTypeFqName());
141 }
142 declareArrayMethods(FQ_NAMES.array.toSafe());
143 }
144
145 private void declareArrayMethods(@NotNull FqName arrayTypeFqName) {
146 declareIntrinsicFunction(arrayTypeFqName, "size", -1, ARRAY_SIZE);
147 declareIntrinsicFunction(arrayTypeFqName, "set", 2, ARRAY_SET);
148 declareIntrinsicFunction(arrayTypeFqName, "get", 1, ARRAY_GET);
149 declareIntrinsicFunction(arrayTypeFqName, "clone", 0, CLONE);
150 declareIntrinsicFunction(arrayTypeFqName, "iterator", 0, ARRAY_ITERATOR);
151 declareIntrinsicFunction(arrayTypeFqName, "<init>", 2, ArrayConstructor.INSTANCE);
152 }
153
154 private void declareBinaryOp(@NotNull String methodName, int opcode) {
155 BinaryOp op = new BinaryOp(opcode);
156 for (PrimitiveType type : PrimitiveType.values()) {
157 declareIntrinsicFunction(type.getTypeFqName(), methodName, 1, op);
158 }
159 }
160
161 private void declareIntrinsicFunction(
162 @NotNull FqName classFqName,
163 @NotNull String methodName,
164 int arity,
165 @NotNull IntrinsicMethod implementation
166 ) {
167 intrinsicsMap.registerIntrinsic(classFqName, null, methodName, arity, implementation);
168 }
169
170 private void declareIntrinsicFunction(
171 @NotNull FqNameUnsafe classFqName,
172 @NotNull String methodName,
173 int arity,
174 @NotNull IntrinsicMethod implementation
175 ) {
176 intrinsicsMap.registerIntrinsic(classFqName.toSafe(), null, methodName, arity, implementation);
177 }
178
179 @Nullable
180 public IntrinsicMethod getIntrinsic(@NotNull CallableMemberDescriptor descriptor) {
181 return intrinsicsMap.getIntrinsic(descriptor);
182 }
183 }