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    }