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 }