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