/* * Copyright 2010-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jetbrains.kotlin.codegen.when; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.codegen.ClassBuilder; import org.jetbrains.kotlin.codegen.WriteAnnotationUtilKt; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.psi.KtFile; import org.jetbrains.kotlin.resolve.constants.EnumValue; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; import org.jetbrains.org.objectweb.asm.MethodVisitor; import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; import java.util.List; import java.util.Map; import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE; import static org.jetbrains.org.objectweb.asm.Opcodes.*; public class MappingClassesForWhenByEnumCodegen { public static final String MAPPINGS_FIELD_DESCRIPTOR = Type.getDescriptor(int[].class); private final GenerationState state; public MappingClassesForWhenByEnumCodegen(@NotNull GenerationState state) { this.state = state; } public void generate(@NotNull List<WhenByEnumsMapping> mappings, @NotNull Type mappingsClass, @NotNull KtFile srcFile) { ClassBuilder cb = state.getFactory().newVisitor(JvmDeclarationOrigin.NO_ORIGIN, mappingsClass, srcFile); cb.defineClass( srcFile, state.getClassFileVersion(), ACC_PUBLIC | ACC_FINAL | ACC_SUPER | ACC_SYNTHETIC, mappingsClass.getInternalName(), null, OBJECT_TYPE.getInternalName(), ArrayUtil.EMPTY_STRING_ARRAY ); generateFields(cb, mappings); generateInitialization(cb, mappings); WriteAnnotationUtilKt.writeSyntheticClassMetadata(cb, state); cb.done(); } private static void generateFields(@NotNull ClassBuilder cb, @NotNull List<WhenByEnumsMapping> mappings) { for (WhenByEnumsMapping mapping : mappings) { cb.newField( JvmDeclarationOrigin.NO_ORIGIN, ACC_STATIC | ACC_PUBLIC | ACC_FINAL | ACC_SYNTHETIC, mapping.getFieldName(), MAPPINGS_FIELD_DESCRIPTOR, null, null ); } } private void generateInitialization(@NotNull ClassBuilder cb, @NotNull List<WhenByEnumsMapping> mappings) { MethodVisitor mv = cb.newMethod( JvmDeclarationOrigin.NO_ORIGIN, ACC_STATIC | ACC_SYNTHETIC, "<clinit>", "()V", null, ArrayUtil.EMPTY_STRING_ARRAY ); mv.visitCode(); InstructionAdapter v = new InstructionAdapter(mv); for (WhenByEnumsMapping mapping : mappings) { generateInitializationForMapping(cb, v, mapping); } v.areturn(Type.VOID_TYPE); mv.visitMaxs(-1, -1); mv.visitEnd(); } private void generateInitializationForMapping( @NotNull ClassBuilder cb, @NotNull InstructionAdapter v, @NotNull WhenByEnumsMapping mapping ) { Type enumType = state.getTypeMapper().mapClass(mapping.getEnumClassDescriptor()); v.invokestatic(enumType.getInternalName(), "values", Type.getMethodDescriptor(Type.getType("[" + enumType.getDescriptor())), false); v.arraylength(); v.newarray(Type.INT_TYPE); v.putstatic(cb.getThisName(), mapping.getFieldName(), MAPPINGS_FIELD_DESCRIPTOR); for (Map.Entry<EnumValue, Integer> item : mapping.enumValuesToIntMapping()) { EnumValue enumEntry = item.getKey(); int mappedValue = item.getValue(); v.getstatic(cb.getThisName(), mapping.getFieldName(), MAPPINGS_FIELD_DESCRIPTOR); v.getstatic(enumType.getInternalName(), enumEntry.getValue().getName().asString(), enumType.getDescriptor()); v.invokevirtual(enumType.getInternalName(), "ordinal", Type.getMethodDescriptor(Type.INT_TYPE), false); v.iconst(mappedValue); v.astore(Type.INT_TYPE); } } }