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 }