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