presto-main/src/main/java/io/prestosql/sql/gen/JoinCompiler.java/JoinCompiler/generatePositionNotDistinctFromRowWithPageMethod
class JoinCompiler:    private void generatePositionNotDistinctFromRowWithPageMethod(
            ClassDefinition classDefinition,
            CallSiteBinder callSiteBinder,
            List<Type> joinChannelTypes,
            List<FieldDefinition> joinChannelFields)
    {
        Parameter leftBlockIndex = arg("leftBlockIndex", int.class);
        Parameter leftBlockPosition = arg("leftBlockPosition", int.class);
        Parameter rightPosition = arg("rightPosition", int.class);
        Parameter page = arg("page", Page.class);
        Parameter rightChannels = arg("rightChannels", int[].class);

        MethodDefinition positionNotDistinctFromRowMethod = classDefinition.declareMethod(
                a(PUBLIC),
                "positionNotDistinctFromRow",
                type(boolean.class),
                leftBlockIndex,
                leftBlockPosition,
                rightPosition,
                page,
                rightChannels);

        Variable thisVariable = positionNotDistinctFromRowMethod.getThis();
        Scope scope = positionNotDistinctFromRowMethod.getScope();
        BytecodeBlock body = positionNotDistinctFromRowMethod.getBody();
        scope.declareVariable("wasNull", body, constantFalse());
        for (int index = 0; index < joinChannelTypes.size(); index++) {
            BytecodeExpression leftBlock = thisVariable
                    .getField(joinChannelFields.get(index))
                    .invoke("get", Object.class, leftBlockIndex)
                    .cast(Block.class);
            BytecodeExpression rightBlock = page.invoke("getBlock", Block.class, rightChannels.getElement(index));
            Type type = joinChannelTypes.get(index);
            // This is a hack for performance reasons.
            // Type.equalTo takes two pairs of Block+position.
            // On the other hand, NOT_DISTINCT_FROM is an operator. It takes two Slices.
            // As a result, two Slices must be constructed for each invocation, which has a nontrivial cost.
            // For these types, their equal semantics is known to be the same as not-distinct-from except for null values.
            //
            // The plan is to allow scalar function to optionally provide an additional implementation using Block+position calling convention.
            // At that point, we'll be able to fully deprecate Type.equalTo (and friends) and remove this hack.
            if (type.getJavaType().equals(Slice.class) && (
                    type instanceof CharType ||
                    type instanceof JsonType ||
                    type instanceof DecimalType ||
                    type instanceof VarbinaryType ||
                    type instanceof VarcharType)) {
                body.append(new IfStatement()
                        .condition(typeEquals(constantType(callSiteBinder, type), leftBlock, leftBlockPosition, rightBlock, rightPosition))
                        .ifFalse(constantFalse().ret()));
                continue;
            }
            ScalarFunctionImplementation operator = metadata.getScalarFunctionImplementation(metadata.resolveOperator(OperatorType.IS_DISTINCT_FROM, ImmutableList.of(type, type)));
            Binding binding = callSiteBinder.bind(operator.getMethodHandle());
            List<BytecodeNode> argumentsBytecode = new ArrayList<>();
            argumentsBytecode.add(generateInputReference(callSiteBinder, scope, type, leftBlock, leftBlockPosition));
            argumentsBytecode.add(generateInputReference(callSiteBinder, scope, type, rightBlock, rightPosition));

            body.append(new IfStatement()
                    .condition(BytecodeUtils.generateInvocation(scope, "isDistinctFrom", operator, Optional.empty(), argumentsBytecode, callSiteBinder))
                    .ifTrue(constantFalse().ret()));
        }
        body.append(constantTrue().ret());
    }