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(KOTLIN_JVM, RECEIVER_PARAMETER_FQ_NAME, "javaClass", -1, JavaClassProperty.INSTANCE);
064 intrinsicsMap.registerIntrinsic(KOTLIN_JVM, KotlinBuiltIns.FQ_NAMES.kClass, "java", -1, new KClassJavaProperty());
065 intrinsicsMap.registerIntrinsic(KotlinBuiltIns.FQ_NAMES.kCallable.toSafe(), null, "name", -1, new KCallableNameProperty());
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 ArrayOf());
071
072 ImmutableList<Name> primitiveCastMethods = OperatorConventions.NUMBER_CONVERSIONS.asList();
073 for (Name method : primitiveCastMethods) {
074 String methodName = method.asString();
075 declareIntrinsicFunction(FQ_NAMES.number, methodName, 0, NUMBER_CAST);
076 for (PrimitiveType type : PrimitiveType.NUMBER_TYPES) {
077 declareIntrinsicFunction(type.getTypeFqName(), methodName, 0, NUMBER_CAST);
078 }
079 }
080
081 for (PrimitiveType type : PrimitiveType.NUMBER_TYPES) {
082 FqName typeFqName = type.getTypeFqName();
083 declareIntrinsicFunction(typeFqName, "plus", 0, UNARY_PLUS);
084 declareIntrinsicFunction(typeFqName, "unaryPlus", 0, UNARY_PLUS);
085 declareIntrinsicFunction(typeFqName, "minus", 0, UNARY_MINUS);
086 declareIntrinsicFunction(typeFqName, "unaryMinus", 0, UNARY_MINUS);
087 declareIntrinsicFunction(typeFqName, "inv", 0, INV);
088 declareIntrinsicFunction(typeFqName, "rangeTo", 1, RANGE_TO);
089 declareIntrinsicFunction(typeFqName, "inc", 0, INC);
090 declareIntrinsicFunction(typeFqName, "dec", 0, DEC);
091 }
092
093 for (PrimitiveType type : PrimitiveType.values()) {
094 FqName typeFqName = type.getTypeFqName();
095 declareIntrinsicFunction(typeFqName, "equals", 1, EQUALS);
096 declareIntrinsicFunction(typeFqName, "hashCode", 0, HASH_CODE);
097 declareIntrinsicFunction(typeFqName, "toString", 0, TO_STRING);
098
099 intrinsicsMap.registerIntrinsic(
100 BUILT_INS_PACKAGE_FQ_NAME, null, StringsKt.decapitalize(type.getArrayTypeName().asString()) + "Of", 1, new ArrayOf()
101 );
102 }
103
104 declareBinaryOp("plus", IADD);
105 declareBinaryOp("minus", ISUB);
106 declareBinaryOp("times", IMUL);
107 declareBinaryOp("div", IDIV);
108 declareBinaryOp("mod", IREM);
109 declareBinaryOp("shl", ISHL);
110 declareBinaryOp("shr", ISHR);
111 declareBinaryOp("ushr", IUSHR);
112 declareBinaryOp("and", IAND);
113 declareBinaryOp("or", IOR);
114 declareBinaryOp("xor", IXOR);
115
116 declareIntrinsicFunction(FQ_NAMES._boolean, "not", 0, new Not());
117
118 declareIntrinsicFunction(FQ_NAMES.string, "plus", 1, new Concat());
119 declareIntrinsicFunction(FQ_NAMES.string, "get", 1, new StringGetChar());
120
121 declareIntrinsicFunction(FQ_NAMES.cloneable, "clone", 0, CLONE);
122
123 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KotlinBuiltIns.FQ_NAMES.any, "toString", 0, TO_STRING);
124 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KotlinBuiltIns.FQ_NAMES.string, "plus", 1, STRING_PLUS);
125 intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, null, "arrayOfNulls", 1, new NewArray());
126
127 for (PrimitiveType type : PrimitiveType.values()) {
128 declareIntrinsicFunction(type.getTypeFqName(), "compareTo", 1, new CompareTo());
129 declareIntrinsicFunction(COLLECTIONS_PACKAGE_FQ_NAME.child(Name.identifier(type.getTypeName().asString() + "Iterator")), "next", 0, ITERATOR_NEXT);
130 }
131
132 declareArrayMethods();
133 }
134
135 private void declareArrayMethods() {
136 for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) {
137 declareArrayMethods(jvmPrimitiveType.getPrimitiveType().getArrayTypeFqName());
138 }
139 declareArrayMethods(FQ_NAMES.array.toSafe());
140 }
141
142 private void declareArrayMethods(@NotNull FqName arrayTypeFqName) {
143 declareIntrinsicFunction(arrayTypeFqName, "size", -1, ARRAY_SIZE);
144 declareIntrinsicFunction(arrayTypeFqName, "set", 2, ARRAY_SET);
145 declareIntrinsicFunction(arrayTypeFqName, "get", 1, ARRAY_GET);
146 declareIntrinsicFunction(arrayTypeFqName, "clone", 0, CLONE);
147 declareIntrinsicFunction(arrayTypeFqName, "iterator", 0, ARRAY_ITERATOR);
148 declareIntrinsicFunction(arrayTypeFqName, "<init>", 2, ArrayConstructor.INSTANCE);
149 }
150
151 private void declareBinaryOp(@NotNull String methodName, int opcode) {
152 BinaryOp op = new BinaryOp(opcode);
153 for (PrimitiveType type : PrimitiveType.values()) {
154 declareIntrinsicFunction(type.getTypeFqName(), methodName, 1, op);
155 }
156 }
157
158 private void declareIntrinsicFunction(
159 @NotNull FqName classFqName,
160 @NotNull String methodName,
161 int arity,
162 @NotNull IntrinsicMethod implementation
163 ) {
164 intrinsicsMap.registerIntrinsic(classFqName, null, methodName, arity, implementation);
165 }
166
167 private void declareIntrinsicFunction(
168 @NotNull FqNameUnsafe classFqName,
169 @NotNull String methodName,
170 int arity,
171 @NotNull IntrinsicMethod implementation
172 ) {
173 intrinsicsMap.registerIntrinsic(classFqName.toSafe(), null, methodName, arity, implementation);
174 }
175
176 @Nullable
177 public IntrinsicMethod getIntrinsic(@NotNull CallableMemberDescriptor descriptor) {
178 return intrinsicsMap.getIntrinsic(descriptor);
179 }
180 }