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 }