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.when; 018 019 import com.intellij.util.ArrayUtil; 020 import org.jetbrains.annotations.NotNull; 021 import org.jetbrains.kotlin.codegen.ClassBuilder; 022 import org.jetbrains.kotlin.codegen.state.GenerationState; 023 import org.jetbrains.kotlin.psi.JetFile; 024 import org.jetbrains.kotlin.resolve.constants.EnumValue; 025 import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; 026 import org.jetbrains.org.objectweb.asm.MethodVisitor; 027 import org.jetbrains.org.objectweb.asm.Type; 028 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; 029 030 import java.util.List; 031 import java.util.Map; 032 033 import static org.jetbrains.kotlin.codegen.AsmUtil.writeKotlinSyntheticClassAnnotation; 034 import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass.Kind.WHEN_ON_ENUM_MAPPINGS; 035 import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE; 036 import static org.jetbrains.org.objectweb.asm.Opcodes.*; 037 038 public class MappingClassesForWhenByEnumCodegen { 039 public static final String MAPPINGS_FIELD_DESCRIPTOR = Type.getDescriptor(int[].class); 040 private final GenerationState state; 041 042 public MappingClassesForWhenByEnumCodegen(@NotNull GenerationState state) { 043 this.state = state; 044 } 045 046 public void generate(@NotNull List<WhenByEnumsMapping> mappings, @NotNull Type mappingsClass, @NotNull JetFile srcFile) { 047 ClassBuilder cb = state.getFactory().newVisitor(JvmDeclarationOrigin.NO_ORIGIN, mappingsClass, srcFile); 048 cb.defineClass( 049 srcFile, 050 V1_6, 051 ACC_FINAL | ACC_SYNTHETIC, 052 mappingsClass.getInternalName(), 053 null, 054 OBJECT_TYPE.getInternalName(), 055 ArrayUtil.EMPTY_STRING_ARRAY 056 ); 057 058 generateFields(cb, mappings); 059 generateInitialization(cb, mappings); 060 061 writeKotlinSyntheticClassAnnotation(cb, WHEN_ON_ENUM_MAPPINGS); 062 063 cb.done(); 064 } 065 066 private static void generateFields(@NotNull ClassBuilder cb, @NotNull List<WhenByEnumsMapping> mappings) { 067 for (WhenByEnumsMapping mapping : mappings) { 068 cb.newField( 069 JvmDeclarationOrigin.NO_ORIGIN, 070 ACC_STATIC | ACC_PUBLIC | ACC_FINAL | ACC_SYNTHETIC, 071 mapping.getFieldName(), 072 MAPPINGS_FIELD_DESCRIPTOR, 073 null, null 074 ); 075 } 076 } 077 078 private void generateInitialization(@NotNull ClassBuilder cb, @NotNull List<WhenByEnumsMapping> mappings) { 079 MethodVisitor mv = cb.newMethod( 080 JvmDeclarationOrigin.NO_ORIGIN, 081 ACC_STATIC | ACC_SYNTHETIC, "<clinit>", "()V", null, ArrayUtil.EMPTY_STRING_ARRAY 082 ); 083 084 mv.visitCode(); 085 086 InstructionAdapter v = new InstructionAdapter(mv); 087 088 for (WhenByEnumsMapping mapping : mappings) { 089 generateInitializationForMapping(cb, v, mapping); 090 } 091 092 v.areturn(Type.VOID_TYPE); 093 094 mv.visitMaxs(-1, -1); 095 mv.visitEnd(); 096 } 097 098 private void generateInitializationForMapping( 099 @NotNull ClassBuilder cb, 100 @NotNull InstructionAdapter v, 101 @NotNull WhenByEnumsMapping mapping 102 ) { 103 Type enumType = state.getTypeMapper().mapClass(mapping.getEnumClassDescriptor()); 104 105 v.invokestatic(enumType.getInternalName(), "values", Type.getMethodDescriptor(Type.getType("[" + enumType.getDescriptor())), false); 106 v.arraylength(); 107 108 v.newarray(Type.INT_TYPE); 109 v.putstatic(cb.getThisName(), mapping.getFieldName(), MAPPINGS_FIELD_DESCRIPTOR); 110 111 for (Map.Entry<EnumValue, Integer> item : mapping.enumValuesToIntMapping()) { 112 EnumValue enumEntry = item.getKey(); 113 int mappedValue = item.getValue(); 114 115 v.getstatic(cb.getThisName(), mapping.getFieldName(), MAPPINGS_FIELD_DESCRIPTOR); 116 v.getstatic(enumType.getInternalName(), enumEntry.getValue().getName().asString(), enumType.getDescriptor()); 117 v.invokevirtual(enumType.getInternalName(), "ordinal", Type.getMethodDescriptor(Type.INT_TYPE), false); 118 v.iconst(mappedValue); 119 v.astore(Type.INT_TYPE); 120 } 121 } 122 }