code: def perform_merge(self) -> cudf.DataFrame:
      left_join_cols = []
      right_join_cols = []
  
      for left_key, right_key in zip(self._left_keys, self._right_keys):
          lcol = left_key.get(self.lhs)
          rcol = right_key.get(self.rhs)
          lcol_casted, rcol_casted = _match_join_keys(
              lcol, rcol, self.how
          )
          left_join_cols.append(lcol_casted)
          right_join_cols.append(rcol_casted)
  
          # Categorical dtypes must be cast back from the underlying codes
          # type that was returned by _match_join_keys.
          if (
              self.how == "inner"
              and isinstance(lcol.dtype, cudf.CategoricalDtype)
              and isinstance(rcol.dtype, cudf.CategoricalDtype)
          ):
              lcol_casted = lcol_casted.astype("category")
              rcol_casted = rcol_casted.astype("category")
  
          left_key.set(self.lhs, lcol_casted, validate=False)
          right_key.set(self.rhs, rcol_casted, validate=False)
  
      left_rows, right_rows = self._gather_maps(
          left_join_cols, right_join_cols
      )
      gather_kwargs = {
          "keep_index": self._using_left_index
          or self._using_right_index,
      }
      left_result = (
          self.lhs._gather(
              GatherMap.from_column_unchecked(
                  left_rows, len(self.lhs), nullify=True
              ),
              **gather_kwargs,
          )
          if left_rows is not None
          else cudf.DataFrame._from_data({})
      )
      del left_rows
      right_result = (
          self.rhs._gather(
              GatherMap.from_column_unchecked(
                  right_rows, len(self.rhs), nullify=True
              ),
              **gather_kwargs,
          )
          if right_rows is not None
          else cudf.DataFrame._from_data({})
      )
      del right_rows
      result = cudf.DataFrame._from_data(
          *self._merge_results(left_result, right_result)
      )
  
      if self.sort:
          result = self._sort_result(result)
      return result
  
file_path: cudf/python/cudf/cudf/core/join/join.py
imports: from __future__ import annotations
  import itertools
  import warnings
  from typing import Any, ClassVar, List, Optional
  import cudf
  from cudf import _lib
  from cudf._lib.types import size_type_dtype
  from cudf.core.copy_types import GatherMap
  from cudf.core.join._join_helpers import _coerce_to_tuple, _ColumnIndexer, _IndexIndexer, _match_join_keys
label_desc: Use image node_id 3 for calling the Merge obj's underlying member method code with example usage: obj.perform_merge() and returns: result