001 /* 002 * Copyright 2010-2014 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.jet.codegen.when; 018 019 import com.intellij.util.ArrayUtil; 020 import org.jetbrains.annotations.NotNull; 021 import org.jetbrains.jet.codegen.AsmUtil; 022 import org.jetbrains.jet.codegen.ClassBuilder; 023 import org.jetbrains.jet.codegen.state.GenerationState; 024 import org.jetbrains.jet.lang.psi.JetFile; 025 import org.jetbrains.jet.lang.resolve.constants.EnumValue; 026 import org.jetbrains.jet.lang.resolve.java.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.jet.lang.resolve.java.AsmTypeConstants.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( 046 @NotNull List<WhenByEnumsMapping> mappings, 047 @NotNull Type mappingsClass, 048 @NotNull JetFile srcFile 049 ) { 050 ClassBuilder cb = state.getFactory().newVisitor( 051 JvmDeclarationOrigin.NO_ORIGIN, 052 mappingsClass, 053 srcFile 054 ); 055 cb.defineClass( 056 srcFile, 057 V1_6, 058 ACC_FINAL | ACC_SYNTHETIC, 059 mappingsClass.getInternalName(), 060 null, 061 OBJECT_TYPE.getInternalName(), 062 ArrayUtil.EMPTY_STRING_ARRAY 063 ); 064 065 generateFields(cb, mappings); 066 generateInitialization(cb, mappings); 067 068 cb.done(); 069 } 070 071 private static void generateFields( 072 @NotNull ClassBuilder cb, 073 @NotNull List<WhenByEnumsMapping> mappings 074 ) { 075 for (WhenByEnumsMapping mapping : mappings) { 076 cb.newField( 077 JvmDeclarationOrigin.NO_ORIGIN, 078 ACC_STATIC | ACC_PUBLIC | ACC_FINAL | ACC_SYNTHETIC, 079 mapping.getFieldName(), 080 MAPPINGS_FIELD_DESCRIPTOR, 081 null, null 082 ); 083 } 084 } 085 086 private static void generateInitialization( 087 @NotNull ClassBuilder cb, 088 @NotNull List<WhenByEnumsMapping> mappings 089 ) { 090 MethodVisitor mv = cb.newMethod( 091 JvmDeclarationOrigin.NO_ORIGIN, 092 ACC_STATIC | ACC_SYNTHETIC, "<clinit>", "()V", null, ArrayUtil.EMPTY_STRING_ARRAY 093 ); 094 095 mv.visitCode(); 096 097 InstructionAdapter v = new InstructionAdapter(mv); 098 099 for (WhenByEnumsMapping mapping : mappings) { 100 generateInitializationForMapping(cb, v, mapping); 101 } 102 103 v.areturn(Type.VOID_TYPE); 104 105 mv.visitMaxs(-1, -1); 106 mv.visitEnd(); 107 } 108 109 private static void generateInitializationForMapping( 110 @NotNull ClassBuilder cb, 111 @NotNull InstructionAdapter v, 112 @NotNull WhenByEnumsMapping mapping 113 ) { 114 v.invokestatic( 115 mapping.getEnumClassInternalName(), "values", 116 Type.getMethodDescriptor( 117 AsmUtil.getArrayOf(mapping.getEnumClassInternalName()) 118 ), 119 false 120 ); 121 v.arraylength(); 122 123 v.newarray(Type.INT_TYPE); 124 v.putstatic(cb.getThisName(), mapping.getFieldName(), MAPPINGS_FIELD_DESCRIPTOR); 125 126 String enumClassDesc = Type.getObjectType(mapping.getEnumClassInternalName()).getDescriptor(); 127 128 for (Map.Entry<EnumValue, Integer> item : mapping.enumValuesToIntMapping()) { 129 EnumValue enumEntry = item.getKey(); 130 int mappedValue = item.getValue(); 131 132 v.getstatic(cb.getThisName(), mapping.getFieldName(), MAPPINGS_FIELD_DESCRIPTOR); 133 v.getstatic( 134 mapping.getEnumClassInternalName(), 135 enumEntry.getValue().getName().asString(), 136 enumClassDesc 137 ); 138 v.invokevirtual( 139 mapping.getEnumClassInternalName(), "ordinal", 140 Type.getMethodDescriptor(Type.INT_TYPE), 141 false 142 ); 143 v.iconst(mappedValue); 144 v.astore(Type.INT_TYPE); 145 } 146 } 147 }