}
Type type = arguments.get(0).getType();
Class<?> javaType = type.getJavaType();
FunctionInfo hashCodeFunction = generatorContext.getRegistry().resolveOperator(OperatorType.HASH_CODE, ImmutableList.of(type));
ImmutableListMultimap.Builder<Integer, ByteCodeNode> hashBucketsBuilder = ImmutableListMultimap.builder();
ImmutableList.Builder<ByteCodeNode> defaultBucket = ImmutableList.builder();
ImmutableSet.Builder<Object> constantValuesBuilder = ImmutableSet.builder();
for (RowExpression testValue : values) {
ByteCodeNode testByteCode = generatorContext.generate(testValue);
if (testValue instanceof ConstantExpression && ((ConstantExpression) testValue).getValue() != null) {
ConstantExpression constant = (ConstantExpression) testValue;
Object object = constant.getValue();
constantValuesBuilder.add(object);
try {
int hashCode = (int) hashCodeFunction.getMethodHandle().invoke(object);
hashBucketsBuilder.put(hashCode, testByteCode);
}
catch (Throwable throwable) {
throw new IllegalArgumentException("Error processing IN statement: error calculating hash code for " + object, throwable);
}
}
else {
defaultBucket.add(testByteCode);
}
}
ImmutableListMultimap<Integer, ByteCodeNode> hashBuckets = hashBucketsBuilder.build();
ImmutableSet<Object> constantValues = constantValuesBuilder.build();
LabelNode end = new LabelNode("end");
LabelNode match = new LabelNode("match");
LabelNode noMatch = new LabelNode("noMatch");
LabelNode defaultLabel = new LabelNode("default");
CompilerContext context = generatorContext.getContext();
ByteCodeNode switchBlock;
if (constantValues.size() < 1000) {
Block switchCaseBlocks = new Block(context);
LookupSwitch.LookupSwitchBuilder switchBuilder = lookupSwitchBuilder();
for (Map.Entry<Integer, Collection<ByteCodeNode>> bucket : hashBuckets.asMap().entrySet()) {
LabelNode label = new LabelNode("inHash" + bucket.getKey());
switchBuilder.addCase(bucket.getKey(), label);
Collection<ByteCodeNode> testValues = bucket.getValue();
Block caseBlock = buildInCase(generatorContext, context, type, label, match, defaultLabel, testValues, false);
switchCaseBlocks
.append(caseBlock.setDescription("case " + bucket.getKey()));
}
switchBuilder.defaultCase(defaultLabel);
Binding hashCodeBinding = generatorContext
.getCallSiteBinder()
.bind(hashCodeFunction.getMethodHandle());
switchBlock = new Block(context)
.comment("lookupSwitch(hashCode(<stackValue>))")
.dup(javaType)
.append(invoke(generatorContext.getContext(), hashCodeBinding))