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    }