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.google.common.collect.Maps;
020 import com.intellij.openapi.util.Pair;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.jet.codegen.ExpressionCodegen;
023 import org.jetbrains.jet.lang.psi.JetWhenExpression;
024 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
025 import org.jetbrains.jet.lang.resolve.constants.StringValue;
026 import org.jetbrains.org.objectweb.asm.Label;
027 import org.jetbrains.org.objectweb.asm.Type;
028
029 import java.util.ArrayList;
030 import java.util.List;
031 import java.util.Map;
032
033 public class StringSwitchCodegen extends SwitchCodegen {
034 private static final String HASH_CODE_METHOD_DESC = Type.getMethodDescriptor(Type.INT_TYPE);
035 private static final String EQUALS_METHOD_DESC = Type.getMethodDescriptor(Type.BOOLEAN_TYPE, Type.getType(Object.class));
036
037 private final Map<Integer, List<Pair<String, Label>>> hashCodesToStringAndEntryLabel = Maps.newHashMap();
038 private int tempVarIndex;
039
040 public StringSwitchCodegen(
041 @NotNull JetWhenExpression expression,
042 boolean isStatement,
043 @NotNull ExpressionCodegen codegen
044 ) {
045 super(expression, isStatement, codegen);
046 }
047
048 @Override
049 protected void processConstant(
050 @NotNull CompileTimeConstant constant, @NotNull Label entryLabel
051 ) {
052 assert constant instanceof StringValue : "guaranteed by usage contract";
053 int hashCode = constant.hashCode();
054
055 if (!transitionsTable.containsKey(hashCode)) {
056 transitionsTable.put(hashCode, new Label());
057 hashCodesToStringAndEntryLabel.put(hashCode, new ArrayList<Pair<String, Label>>());
058 }
059
060 hashCodesToStringAndEntryLabel.get(hashCode).add(
061 new Pair<String, Label>(((StringValue) constant).getValue(), entryLabel)
062 );
063 }
064
065 @Override
066 public void generate() {
067 super.generate();
068 codegen.myFrameMap.leaveTemp(subjectType);
069 }
070
071 @Override
072 protected void generateSubject() {
073 tempVarIndex = codegen.myFrameMap.enterTemp(subjectType);
074 super.generateSubject();
075 v.store(tempVarIndex, subjectType);
076
077 v.load(tempVarIndex, subjectType);
078
079 generateNullCheckIfNeeded();
080
081 v.invokevirtual(
082 subjectType.getInternalName(),
083 "hashCode", HASH_CODE_METHOD_DESC, false
084 );
085 }
086
087 @Override
088 protected void generateEntries() {
089 for (int hashCode : hashCodesToStringAndEntryLabel.keySet()) {
090 v.visitLabel(transitionsTable.get(hashCode));
091
092 List<Pair<String, Label>> items = hashCodesToStringAndEntryLabel.get(hashCode);
093 Label nextLabel = null;
094
095 for (int i = 0; i < items.size(); i++) {
096 if (nextLabel != null) {
097 v.visitLabel(nextLabel);
098 }
099
100 Pair<String, Label> stringAndEntryLabel = items.get(i);
101
102 v.load(tempVarIndex, subjectType);
103 v.aconst(stringAndEntryLabel.first);
104 v.invokevirtual(
105 subjectType.getInternalName(),
106 "equals",
107 EQUALS_METHOD_DESC,
108 false
109 );
110
111 if (i + 1 < items.size()) {
112 nextLabel = new Label();
113 }
114 else {
115 nextLabel = defaultLabel;
116 }
117
118 v.ifeq(nextLabel);
119 v.goTo(stringAndEntryLabel.getSecond());
120 }
121 }
122
123 super.generateEntries();
124 }
125 }