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.codegen.AsmUtil.writeKotlinSyntheticClassAnnotation; 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 KtFile srcFile) { 047 ClassBuilder cb = state.getFactory().newVisitor(JvmDeclarationOrigin.NO_ORIGIN, mappingsClass, srcFile); 048 cb.defineClass( 049 srcFile, 050 V1_6, 051 ACC_PUBLIC | ACC_FINAL | ACC_SUPER | 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, state); 062 063 WriteAnnotationUtilKt.writeSyntheticClassMetadata(cb); 064 065 cb.done(); 066 } 067 068 private static void generateFields(@NotNull ClassBuilder cb, @NotNull List<WhenByEnumsMapping> mappings) { 069 for (WhenByEnumsMapping mapping : mappings) { 070 cb.newField( 071 JvmDeclarationOrigin.NO_ORIGIN, 072 ACC_STATIC | ACC_PUBLIC | ACC_FINAL | ACC_SYNTHETIC, 073 mapping.getFieldName(), 074 MAPPINGS_FIELD_DESCRIPTOR, 075 null, null 076 ); 077 } 078 } 079 080 private void generateInitialization(@NotNull ClassBuilder cb, @NotNull List<WhenByEnumsMapping> mappings) { 081 MethodVisitor mv = cb.newMethod( 082 JvmDeclarationOrigin.NO_ORIGIN, 083 ACC_STATIC | ACC_SYNTHETIC, "<clinit>", "()V", null, ArrayUtil.EMPTY_STRING_ARRAY 084 ); 085 086 mv.visitCode(); 087 088 InstructionAdapter v = new InstructionAdapter(mv); 089 090 for (WhenByEnumsMapping mapping : mappings) { 091 generateInitializationForMapping(cb, v, mapping); 092 } 093 094 v.areturn(Type.VOID_TYPE); 095 096 mv.visitMaxs(-1, -1); 097 mv.visitEnd(); 098 } 099 100 private void generateInitializationForMapping( 101 @NotNull ClassBuilder cb, 102 @NotNull InstructionAdapter v, 103 @NotNull WhenByEnumsMapping mapping 104 ) { 105 Type enumType = state.getTypeMapper().mapClass(mapping.getEnumClassDescriptor()); 106 107 v.invokestatic(enumType.getInternalName(), "values", Type.getMethodDescriptor(Type.getType("[" + enumType.getDescriptor())), false); 108 v.arraylength(); 109 110 v.newarray(Type.INT_TYPE); 111 v.putstatic(cb.getThisName(), mapping.getFieldName(), MAPPINGS_FIELD_DESCRIPTOR); 112 113 for (Map.Entry<EnumValue, Integer> item : mapping.enumValuesToIntMapping()) { 114 EnumValue enumEntry = item.getKey(); 115 int mappedValue = item.getValue(); 116 117 v.getstatic(cb.getThisName(), mapping.getFieldName(), MAPPINGS_FIELD_DESCRIPTOR); 118 v.getstatic(enumType.getInternalName(), enumEntry.getValue().getName().asString(), enumType.getDescriptor()); 119 v.invokevirtual(enumType.getInternalName(), "ordinal", Type.getMethodDescriptor(Type.INT_TYPE), false); 120 v.iconst(mappedValue); 121 v.astore(Type.INT_TYPE); 122 } 123 } 124 }