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 }