# Global Metrics

path: .metrics.halstead.bugs
old: 1.6610538565683188
new: 2.0811604723074724
path: .metrics.halstead.N2
old: 1010.0
new: 574.0
path: .metrics.halstead.effort
old: 351768.9098607888
new: 493333.07713167695
path: .metrics.halstead.vocabulary
old: 247.0
new: 189.0
path: .metrics.halstead.n1
old: 10.0
new: 28.0
path: .metrics.halstead.N1
old: 1067.0
new: 733.0
path: .metrics.halstead.difficulty
old: 21.30801687763713
new: 49.91304347826087
path: .metrics.halstead.n2
old: 237.0
new: 161.0
path: .metrics.halstead.length
old: 2077.0
new: 1307.0
path: .metrics.halstead.volume
old: 16508.758740001376
new: 9883.850848456945
path: .metrics.halstead.level
old: 0.04693069306930693
new: 0.020034843205574915
path: .metrics.halstead.time
old: 19542.717214488264
new: 27407.393173982055
path: .metrics.halstead.purity_ratio
old: 0.9161537943850558
new: 1.006031794333639
path: .metrics.halstead.estimated_program_length
old: 1902.851430937761
new: 1314.883555194066
path: .metrics.nom.functions
old: 0.0
new: 15.0
path: .metrics.nom.closures
old: 0.0
new: 2.0
path: .metrics.nom.total
old: 0.0
new: 17.0
path: .metrics.cognitive.average
old: null
new: 1.1764705882352942
path: .metrics.cognitive.sum
old: 0.0
new: 20.0
path: .metrics.mi.mi_original
old: 16.654019488795512
new: 14.057110188185035
path: .metrics.mi.mi_visual_studio
old: 9.739192683506149
new: 8.220532273792418
path: .metrics.mi.mi_sei
old: -40.522422291641625
new: -17.49561427264998
path: .metrics.nargs.average
old: null
new: 3.411764705882353
path: .metrics.nargs.sum
old: 0.0
new: 58.0
path: .metrics.loc.ploc
old: 484.0
new: 292.0
path: .metrics.loc.lloc
old: 0.0
new: 77.0
path: .metrics.loc.cloc
old: 12.0
new: 103.0
path: .metrics.loc.blank
old: 95.0
new: 62.0
path: .metrics.loc.sloc
old: 591.0
new: 457.0
path: .metrics.cyclomatic.sum
old: 2.0
new: 43.0
path: .metrics.cyclomatic.average
old: 1.0
new: 2.15
path: .metrics.nexits.average
old: null
new: 0.8823529411764706
path: .metrics.nexits.sum
old: 0.0
new: 15.0

# Spaces Data

## Minimal test - lines (33, 388)

path: .spaces[0].metrics.nom.closures
old: 0.0
new: 1.0
path: .spaces[0].metrics.nom.functions
old: 0.0
new: 13.0
path: .spaces[0].metrics.nom.total
old: 0.0
new: 14.0
path: .spaces[0].metrics.cyclomatic.average
old: 1.0
new: 2.3125
path: .spaces[0].metrics.cyclomatic.sum
old: 1.0
new: 37.0
path: .spaces[0].metrics.loc.cloc
old: 0.0
new: 81.0
path: .spaces[0].metrics.loc.sloc
old: 568.0
new: 356.0
path: .spaces[0].metrics.loc.ploc
old: 476.0
new: 227.0
path: .spaces[0].metrics.loc.blank
old: 92.0
new: 48.0
path: .spaces[0].metrics.loc.lloc
old: 0.0
new: 54.0
path: .spaces[0].metrics.nargs.average
old: null
new: 4.142857142857143
path: .spaces[0].metrics.nargs.sum
old: 0.0
new: 58.0
path: .spaces[0].metrics.mi.mi_original
old: 17.535912016900838
new: 20.539086189106413
path: .spaces[0].metrics.mi.mi_sei
old: -50.300058828360235
new: -8.625764022220217
path: .spaces[0].metrics.mi.mi_visual_studio
old: 10.254919308129145
new: 12.01116151409732
path: .spaces[0].metrics.nexits.sum
old: 0.0
new: 14.0
path: .spaces[0].metrics.nexits.average
old: null
new: 1.0
path: .spaces[0].metrics.cognitive.sum
old: 0.0
new: 18.0
path: .spaces[0].metrics.cognitive.average
old: null
new: 1.2857142857142858
path: .spaces[0].metrics.halstead.vocabulary
old: 246.0
new: 148.0
path: .spaces[0].metrics.halstead.estimated_program_length
old: 1893.523040598268
new: 963.4328092906352
path: .spaces[0].metrics.halstead.length
old: 2075.0
new: 1119.0
path: .spaces[0].metrics.halstead.effort
old: 351961.0876984651
new: 458361.5446619526
path: .spaces[0].metrics.halstead.n2
old: 236.0
new: 120.0
path: .spaces[0].metrics.halstead.purity_ratio
old: 0.9125412243847076
new: 0.8609765945403353
path: .spaces[0].metrics.halstead.time
old: 19553.39376102584
new: 25464.530258997365
path: .spaces[0].metrics.halstead.bugs
old: 1.6616587777173484
new: 1.9816070019897325
path: .spaces[0].metrics.halstead.level
old: 0.046825396825396826
new: 0.01760046934584922
path: .spaces[0].metrics.halstead.N2
old: 1008.0
new: 487.0
path: .spaces[0].metrics.halstead.n1
old: 10.0
new: 28.0
path: .spaces[0].metrics.halstead.N1
old: 1067.0
new: 632.0
path: .spaces[0].metrics.halstead.difficulty
old: 21.35593220338983
new: 56.81666666666667
path: .spaces[0].metrics.halstead.volume
old: 16480.71759857892
new: 8067.3783161387955

### Code

    namespace {

    // Keep track of poisoned state. Notice that there is no reason to lock access
    // to this variable as it's only changed in InitPoisonIOInterposer and
    // ClearPoisonIOInterposer which may only be called on the main-thread when no
    // other threads are running.
    static bool sIOPoisoned = false;

    /************************ Internal NT API Declarations ************************/

    /*
     * Function pointer declaration for internal NT routine to create/open files.
     * For documentation on the NtCreateFile routine, see MSDN.
     */
    typedef NTSTATUS(NTAPI* NtCreateFileFn)(
        PHANDLE aFileHandle, ACCESS_MASK aDesiredAccess,
        POBJECT_ATTRIBUTES aObjectAttributes, PIO_STATUS_BLOCK aIoStatusBlock,
        PLARGE_INTEGER aAllocationSize, ULONG aFileAttributes, ULONG aShareAccess,
        ULONG aCreateDisposition, ULONG aCreateOptions, PVOID aEaBuffer,
        ULONG aEaLength);

    /**
     * Function pointer declaration for internal NT routine to read data from file.
     * For documentation on the NtReadFile routine, see ZwReadFile on MSDN.
     */
    typedef NTSTATUS(NTAPI* NtReadFileFn)(HANDLE aFileHandle, HANDLE aEvent,
                                          PIO_APC_ROUTINE aApc, PVOID aApcCtx,
                                          PIO_STATUS_BLOCK aIoStatus, PVOID aBuffer,
                                          ULONG aLength, PLARGE_INTEGER aOffset,
                                          PULONG aKey);

    /**
     * Function pointer declaration for internal NT routine to read data from file.
     * No documentation exists, see wine sources for details.
     */
    typedef NTSTATUS(NTAPI* NtReadFileScatterFn)(
        HANDLE aFileHandle, HANDLE aEvent, PIO_APC_ROUTINE aApc, PVOID aApcCtx,
        PIO_STATUS_BLOCK aIoStatus, FILE_SEGMENT_ELEMENT* aSegments, ULONG aLength,
        PLARGE_INTEGER aOffset, PULONG aKey);

    /**
     * Function pointer declaration for internal NT routine to write data to file.
     * For documentation on the NtWriteFile routine, see ZwWriteFile on MSDN.
     */
    typedef NTSTATUS(NTAPI* NtWriteFileFn)(HANDLE aFileHandle, HANDLE aEvent,
                                           PIO_APC_ROUTINE aApc, PVOID aApcCtx,
                                           PIO_STATUS_BLOCK aIoStatus,
                                           PVOID aBuffer, ULONG aLength,
                                           PLARGE_INTEGER aOffset, PULONG aKey);

    /**
     * Function pointer declaration for internal NT routine to write data to file.
     * No documentation exists, see wine sources for details.
     */
    typedef NTSTATUS(NTAPI* NtWriteFileGatherFn)(
        HANDLE aFileHandle, HANDLE aEvent, PIO_APC_ROUTINE aApc, PVOID aApcCtx,
        PIO_STATUS_BLOCK aIoStatus, FILE_SEGMENT_ELEMENT* aSegments, ULONG aLength,
        PLARGE_INTEGER aOffset, PULONG aKey);

    /**
     * Function pointer declaration for internal NT routine to flush to disk.
     * For documentation on the NtFlushBuffersFile routine, see ZwFlushBuffersFile
     * on MSDN.
     */
    typedef NTSTATUS(NTAPI* NtFlushBuffersFileFn)(HANDLE aFileHandle,
                                                  PIO_STATUS_BLOCK aIoStatusBlock);

    typedef struct _FILE_NETWORK_OPEN_INFORMATION* PFILE_NETWORK_OPEN_INFORMATION;
    /**
     * Function pointer delaration for internal NT routine to query file attributes.
     * (equivalent to stat)
     */
    typedef NTSTATUS(NTAPI* NtQueryFullAttributesFileFn)(
        POBJECT_ATTRIBUTES aObjectAttributes,
        PFILE_NETWORK_OPEN_INFORMATION aFileInformation);

    /*************************** Auxiliary Declarations ***************************/

    // Cache of filenames associated with handles.
    // `static` to be shared between all calls to `Filename()`.
    // This assumes handles are not reused, at least within a windows of 32
    // handles.
    // Profiling showed that during startup, around half of `Filename()` calls are
    // resolved with the first entry (best case), and 32 entries cover >95% of
    // cases, reducing the average `Filename()` cost by 5-10x.
    using HandleToFilenameCache = mozilla::SmallArrayLRUCache;
    static mozilla::UniquePtr sHandleToFilenameCache;

    /**
     * RAII class for timing the duration of an I/O call and reporting the result
     * to the mozilla::IOInterposeObserver API.
     */
    class WinIOAutoObservation : public mozilla::IOInterposeObserver::Observation {
     public:
      WinIOAutoObservation(mozilla::IOInterposeObserver::Operation aOp,
                           HANDLE aFileHandle, const LARGE_INTEGER* aOffset)
          : mozilla::IOInterposeObserver::Observation(
                aOp, sReference,
                !mozilla::IsDebugFile(reinterpret_cast(aFileHandle))),
            mFileHandle(aFileHandle),
            mFileHandleType(GetFileType(aFileHandle)),
            mHasQueriedFilename(false) {
        if (mShouldReport) {
          mOffset.QuadPart = aOffset ? aOffset->QuadPart : 0;
        }
      }

      WinIOAutoObservation(mozilla::IOInterposeObserver::Operation aOp,
                           nsAString& aFilename)
          : mozilla::IOInterposeObserver::Observation(aOp, sReference),
            mFileHandle(nullptr),
            mFileHandleType(FILE_TYPE_UNKNOWN),
            mHasQueriedFilename(false) {
        if (mShouldReport) {
          nsAutoString dosPath;
          if (mozilla::NtPathToDosPath(aFilename, dosPath)) {
            mFilename = dosPath;
          } else {
            // If we can't get a dosPath, what we have is better than nothing.
            mFilename = aFilename;
          }
          mHasQueriedFilename = true;
          mOffset.QuadPart = 0;
        }
      }

      void SetHandle(HANDLE aFileHandle) {
        mFileHandle = aFileHandle;
        if (aFileHandle) {
          // Note: `GetFileType()` is fast enough that we don't need to cache it.
          mFileHandleType = GetFileType(aFileHandle);

          if (mHasQueriedFilename) {
            // `mHasQueriedFilename` indicates we already have a filename, add it to
            // the cache with the now-known handle.
            sHandleToFilenameCache->Add(aFileHandle, mFilename);
          }
        }
      }

      const char* FileType() const override;

      void Filename(nsAString& aFilename) override;

      ~WinIOAutoObservation() { Report(); }

     private:
      HANDLE mFileHandle;
      DWORD mFileHandleType;
      LARGE_INTEGER mOffset;
      bool mHasQueriedFilename;
      nsString mFilename;
      static const char* sReference;
    };

    const char* WinIOAutoObservation::sReference = "PoisonIOInterposer";

    // Get filename for this observation
    void WinIOAutoObservation::Filename(nsAString& aFilename) {
      // If mHasQueriedFilename is true, then filename is already stored in
      // mFilename
      if (mHasQueriedFilename) {
        aFilename = mFilename;
        return;
      }

      if (mFileHandle) {
        mFilename = sHandleToFilenameCache->FetchOrAdd(mFileHandle, [&]() {
          nsString filename;
          if (!mozilla::HandleToFilename(mFileHandle, mOffset, filename)) {
            // HandleToFilename could fail (return false) but still have added
            // something to `filename`, so it should be cleared in this case.
            filename.Truncate();
          }
          return filename;
        });
      }
      mHasQueriedFilename = true;

      aFilename = mFilename;
    }

    const char* WinIOAutoObservation::FileType() const {
      if (mFileHandle) {
        switch (mFileHandleType) {
          case FILE_TYPE_CHAR:
            return "Char";
          case FILE_TYPE_DISK:
            return "File";
          case FILE_TYPE_PIPE:
            return "Pipe";
          case FILE_TYPE_REMOTE:
            return "Remote";
          case FILE_TYPE_UNKNOWN:
          default:
            break;
        }
      }
      // Fallback to base class default implementation.
      return mozilla::IOInterposeObserver::Observation::FileType();
    }

    /*************************** IO Interposing Methods ***************************/

    // Function pointers to original functions
    static mozilla::WindowsDllInterceptor::FuncHookType
        gOriginalNtCreateFile;
    static mozilla::WindowsDllInterceptor::FuncHookType
        gOriginalNtReadFile;
    static mozilla::WindowsDllInterceptor::FuncHookType
        gOriginalNtReadFileScatter;
    static mozilla::WindowsDllInterceptor::FuncHookType
        gOriginalNtWriteFile;
    static mozilla::WindowsDllInterceptor::FuncHookType
        gOriginalNtWriteFileGather;
    static mozilla::WindowsDllInterceptor::FuncHookType
        gOriginalNtFlushBuffersFile;
    static mozilla::WindowsDllInterceptor::FuncHookType
        gOriginalNtQueryFullAttributesFile;

    static NTSTATUS NTAPI InterposedNtCreateFile(
        PHANDLE aFileHandle, ACCESS_MASK aDesiredAccess,
        POBJECT_ATTRIBUTES aObjectAttributes, PIO_STATUS_BLOCK aIoStatusBlock,
        PLARGE_INTEGER aAllocationSize, ULONG aFileAttributes, ULONG aShareAccess,
        ULONG aCreateDisposition, ULONG aCreateOptions, PVOID aEaBuffer,
        ULONG aEaLength) {
      // Report IO
      const wchar_t* buf =
          aObjectAttributes ? aObjectAttributes->ObjectName->Buffer : L"";
      uint32_t len = aObjectAttributes
                         ? aObjectAttributes->ObjectName->Length / sizeof(WCHAR)
                         : 0;
      nsDependentSubstring filename(buf, len);
      WinIOAutoObservation timer(mozilla::IOInterposeObserver::OpCreateOrOpen,
                                 filename);

      // Something is badly wrong if this function is undefined
      MOZ_ASSERT(gOriginalNtCreateFile);

      // Execute original function
      NTSTATUS status = gOriginalNtCreateFile(
          aFileHandle, aDesiredAccess, aObjectAttributes, aIoStatusBlock,
          aAllocationSize, aFileAttributes, aShareAccess, aCreateDisposition,
          aCreateOptions, aEaBuffer, aEaLength);
      if (NT_SUCCESS(status) && aFileHandle) {
        timer.SetHandle(*aFileHandle);
      }
      return status;
    }

    static NTSTATUS NTAPI InterposedNtReadFile(HANDLE aFileHandle, HANDLE aEvent,
                                               PIO_APC_ROUTINE aApc, PVOID aApcCtx,
                                               PIO_STATUS_BLOCK aIoStatus,
                                               PVOID aBuffer, ULONG aLength,
                                               PLARGE_INTEGER aOffset,
                                               PULONG aKey) {
      // Report IO
      WinIOAutoObservation timer(mozilla::IOInterposeObserver::OpRead, aFileHandle,
                                 aOffset);

      // Something is badly wrong if this function is undefined
      MOZ_ASSERT(gOriginalNtReadFile);

      // Execute original function
      return gOriginalNtReadFile(aFileHandle, aEvent, aApc, aApcCtx, aIoStatus,
                                 aBuffer, aLength, aOffset, aKey);
    }

    static NTSTATUS NTAPI InterposedNtReadFileScatter(
        HANDLE aFileHandle, HANDLE aEvent, PIO_APC_ROUTINE aApc, PVOID aApcCtx,
        PIO_STATUS_BLOCK aIoStatus, FILE_SEGMENT_ELEMENT* aSegments, ULONG aLength,
        PLARGE_INTEGER aOffset, PULONG aKey) {
      // Report IO
      WinIOAutoObservation timer(mozilla::IOInterposeObserver::OpRead, aFileHandle,
                                 aOffset);

      // Something is badly wrong if this function is undefined
      MOZ_ASSERT(gOriginalNtReadFileScatter);

      // Execute original function
      return gOriginalNtReadFileScatter(aFileHandle, aEvent, aApc, aApcCtx,
                                        aIoStatus, aSegments, aLength, aOffset,
                                        aKey);
    }

    // Interposed NtWriteFile function
    static NTSTATUS NTAPI InterposedNtWriteFile(HANDLE aFileHandle, HANDLE aEvent,
                                                PIO_APC_ROUTINE aApc, PVOID aApcCtx,
                                                PIO_STATUS_BLOCK aIoStatus,
                                                PVOID aBuffer, ULONG aLength,
                                                PLARGE_INTEGER aOffset,
                                                PULONG aKey) {
      // Report IO
      WinIOAutoObservation timer(mozilla::IOInterposeObserver::OpWrite, aFileHandle,
                                 aOffset);

      // Something is badly wrong if this function is undefined
      MOZ_ASSERT(gOriginalNtWriteFile);

      // Execute original function
      return gOriginalNtWriteFile(aFileHandle, aEvent, aApc, aApcCtx, aIoStatus,
                                  aBuffer, aLength, aOffset, aKey);
    }

    // Interposed NtWriteFileGather function
    static NTSTATUS NTAPI InterposedNtWriteFileGather(
        HANDLE aFileHandle, HANDLE aEvent, PIO_APC_ROUTINE aApc, PVOID aApcCtx,
        PIO_STATUS_BLOCK aIoStatus, FILE_SEGMENT_ELEMENT* aSegments, ULONG aLength,
        PLARGE_INTEGER aOffset, PULONG aKey) {
      // Report IO
      WinIOAutoObservation timer(mozilla::IOInterposeObserver::OpWrite, aFileHandle,
                                 aOffset);

      // Something is badly wrong if this function is undefined
      MOZ_ASSERT(gOriginalNtWriteFileGather);

      // Execute original function
      return gOriginalNtWriteFileGather(aFileHandle, aEvent, aApc, aApcCtx,
                                        aIoStatus, aSegments, aLength, aOffset,
                                        aKey);
    }

    static NTSTATUS NTAPI InterposedNtFlushBuffersFile(
        HANDLE aFileHandle, PIO_STATUS_BLOCK aIoStatusBlock) {
      // Report IO
      WinIOAutoObservation timer(mozilla::IOInterposeObserver::OpFSync, aFileHandle,
                                 nullptr);

      // Something is badly wrong if this function is undefined
      MOZ_ASSERT(gOriginalNtFlushBuffersFile);

      // Execute original function
      return gOriginalNtFlushBuffersFile(aFileHandle, aIoStatusBlock);
    }

    static NTSTATUS NTAPI InterposedNtQueryFullAttributesFile(
        POBJECT_ATTRIBUTES aObjectAttributes,
        PFILE_NETWORK_OPEN_INFORMATION aFileInformation) {
      // Report IO
      const wchar_t* buf =
          aObjectAttributes ? aObjectAttributes->ObjectName->Buffer : L"";
      uint32_t len = aObjectAttributes
                         ? aObjectAttributes->ObjectName->Length / sizeof(WCHAR)
                         : 0;
      nsDependentSubstring filename(buf, len);
      WinIOAutoObservation timer(mozilla::IOInterposeObserver::OpStat, filename);

      // Something is badly wrong if this function is undefined
      MOZ_ASSERT(gOriginalNtQueryFullAttributesFile);

      // Execute original function
      return gOriginalNtQueryFullAttributesFile(aObjectAttributes,
                                                aFileInformation);
    }

    }  // namespace