001 /*
002 * Copyright 2010-2016 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.backend.jvm.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.lexer.KtTokens;
027 import org.jetbrains.kotlin.name.FqName;
028 import org.jetbrains.kotlin.name.FqNameUnsafe;
029 import org.jetbrains.kotlin.name.Name;
030 import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType;
031 import org.jetbrains.kotlin.types.expressions.OperatorConventions;
032
033 import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.*;
034 import static org.jetbrains.org.objectweb.asm.Opcodes.*;
035
036 public class IntrinsicMethods {
037 public static final String INTRINSICS_CLASS_NAME = "kotlin/jvm/internal/Intrinsics";
038
039 private static final FqName KOTLIN_JVM = new FqName("kotlin.jvm");
040 /* package */ static final FqNameUnsafe RECEIVER_PARAMETER_FQ_NAME = new FqNameUnsafe("T");
041
042 private static final IntrinsicMethod UNARY_MINUS = new UnaryMinus();
043 private static final IntrinsicMethod UNARY_PLUS = new UnaryPlus();
044 private static final IntrinsicMethod NUMBER_CAST = new NumberCast();
045 private static final IntrinsicMethod INV = new Inv();
046 private static final IntrinsicMethod RANGE_TO = new RangeTo();
047 private static final IntrinsicMethod INC = new Increment(1);
048 private static final IntrinsicMethod DEC = new Increment(-1);
049 private static final IntrinsicMethod HASH_CODE = new HashCode();
050
051 private static final IntrinsicMethod ARRAY_SIZE = new ArraySize();
052 private static final Equals EQUALS = new Equals(KtTokens.EQEQ);
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 static final IntrinsicMethod ARRAY_ITERATOR = new ArrayIterator();
061 private final IntrinsicsMap intrinsicsMap = new IntrinsicsMap();
062
063 public IntrinsicMethods() {
064 intrinsicsMap.registerIntrinsic(KOTLIN_JVM, RECEIVER_PARAMETER_FQ_NAME, "javaClass", -1, JavaClassProperty.INSTANCE);
065 intrinsicsMap.registerIntrinsic(KOTLIN_JVM, KotlinBuiltIns.FQ_NAMES.kClass, "java", -1, new KClassJavaProperty());
066 intrinsicsMap.registerIntrinsic(KotlinBuiltIns.FQ_NAMES.kCallable.toSafe(), null, "name", -1, new KCallableNameProperty());
067 intrinsicsMap.registerIntrinsic(new FqName("kotlin.jvm.internal.unsafe"), null, "monitorEnter", 1, MonitorInstruction.MONITOR_ENTER);
068 intrinsicsMap.registerIntrinsic(new FqName("kotlin.jvm.internal.unsafe"), null, "monitorExit", 1, MonitorInstruction.MONITOR_EXIT);
069 intrinsicsMap.registerIntrinsic(KOTLIN_JVM, KotlinBuiltIns.FQ_NAMES.array, "isArrayOf", 0, new IsArrayOf());
070
071 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, null, "arrayOf", 1, new ArrayOf());
072
073 ImmutableList<Name> primitiveCastMethods = OperatorConventions.NUMBER_CONVERSIONS.asList();
074 for (Name method : primitiveCastMethods) {
075 String methodName = method.asString();
076 declareIntrinsicFunction(FQ_NAMES.number, methodName, 0, NUMBER_CAST);
077 for (PrimitiveType type : PrimitiveType.NUMBER_TYPES) {
078 declareIntrinsicFunction(type.getTypeFqName(), methodName, 0, NUMBER_CAST);
079 }
080 }
081
082 for (PrimitiveType type : PrimitiveType.NUMBER_TYPES) {
083 FqName typeFqName = type.getTypeFqName();
084 declareIntrinsicFunction(typeFqName, "plus", 0, UNARY_PLUS);
085 declareIntrinsicFunction(typeFqName, "unaryPlus", 0, UNARY_PLUS);
086 declareIntrinsicFunction(typeFqName, "minus", 0, UNARY_MINUS);
087 declareIntrinsicFunction(typeFqName, "unaryMinus", 0, UNARY_MINUS);
088 declareIntrinsicFunction(typeFqName, "inv", 0, INV);
089 declareIntrinsicFunction(typeFqName, "rangeTo", 1, RANGE_TO);
090 declareIntrinsicFunction(typeFqName, "inc", 0, INC);
091 declareIntrinsicFunction(typeFqName, "dec", 0, DEC);
092 }
093
094 for (PrimitiveType type : PrimitiveType.values()) {
095 FqName typeFqName = type.getTypeFqName();
096 declareIntrinsicFunction(typeFqName, "equals", 1, EQUALS);
097 declareIntrinsicFunction(typeFqName, "hashCode", 0, HASH_CODE);
098 declareIntrinsicFunction(typeFqName, "toString", 0, TO_STRING);
099
100 intrinsicsMap.registerIntrinsic(
101 BUILT_INS_PACKAGE_FQ_NAME, null, StringsKt.decapitalize(type.getArrayTypeName().asString()) + "Of", 1, new ArrayOf()
102 );
103 }
104
105 declareBinaryOp("plus", IADD);
106 declareBinaryOp("minus", ISUB);
107 declareBinaryOp("times", IMUL);
108 declareBinaryOp("div", IDIV);
109 declareBinaryOp("mod", IREM);
110 declareBinaryOp("rem", 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(FQ_NAMES._boolean, "not", 0, new Not());
119
120 declareIntrinsicFunction(FQ_NAMES.string, "plus", 1, new Concat());
121 declareIntrinsicFunction(FQ_NAMES.string, "get", 1, new StringGetChar());
122
123 declareIntrinsicFunction(FQ_NAMES.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.string, "plus", 1, STRING_PLUS);
127 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, null, "arrayOfNulls", 1, new NewArray());
128
129 for (PrimitiveType type : PrimitiveType.values()) {
130 declareIntrinsicFunction(type.getTypeFqName(), "compareTo", 1, new CompareTo());
131 declareIntrinsicFunction(COLLECTIONS_PACKAGE_FQ_NAME.child(Name.identifier(type.getTypeName().asString() + "Iterator")), "next", 0, ITERATOR_NEXT);
132 }
133
134 declareArrayMethods();
135 }
136
137 private void declareArrayMethods() {
138 for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) {
139 declareArrayMethods(jvmPrimitiveType.getPrimitiveType().getArrayTypeFqName());
140 }
141 declareArrayMethods(FQ_NAMES.array.toSafe());
142 }
143
144 private void declareArrayMethods(@NotNull FqName arrayTypeFqName) {
145 declareIntrinsicFunction(arrayTypeFqName, "size", -1, ARRAY_SIZE);
146 declareIntrinsicFunction(arrayTypeFqName, "set", 2, ARRAY_SET);
147 declareIntrinsicFunction(arrayTypeFqName, "get", 1, ARRAY_GET);
148 declareIntrinsicFunction(arrayTypeFqName, "clone", 0, CLONE);
149 declareIntrinsicFunction(arrayTypeFqName, "iterator", 0, ARRAY_ITERATOR);
150 declareIntrinsicFunction(arrayTypeFqName, "<init>", 2, ArrayConstructor.INSTANCE);
151 }
152
153 private void declareBinaryOp(@NotNull String methodName, int opcode) {
154 BinaryOp op = new BinaryOp(opcode);
155 for (PrimitiveType type : PrimitiveType.values()) {
156 declareIntrinsicFunction(type.getTypeFqName(), methodName, 1, op);
157 }
158 }
159
160 private void declareIntrinsicFunction(
161 @NotNull FqName classFqName,
162 @NotNull String methodName,
163 int arity,
164 @NotNull IntrinsicMethod implementation
165 ) {
166 intrinsicsMap.registerIntrinsic(classFqName, null, methodName, arity, implementation);
167 }
168
169 private void declareIntrinsicFunction(
170 @NotNull FqNameUnsafe classFqName,
171 @NotNull String methodName,
172 int arity,
173 @NotNull IntrinsicMethod implementation
174 ) {
175 intrinsicsMap.registerIntrinsic(classFqName.toSafe(), null, methodName, arity, implementation);
176 }
177
178 @Nullable
179 public IntrinsicMethod getIntrinsic(@NotNull CallableMemberDescriptor descriptor) {
180 return intrinsicsMap.getIntrinsic(descriptor);
181 }
182 }