// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include <mach/mach.h>
#include <mach/mach_vm.h>

typedef struct {
  void* isa;
  int flags;
  // There are other fields, but we just need the flags and isa.
} BlockRefCountExtractor;

uint64_t getBlockRetainCount(BlockRefCountExtractor* block) {
  // The ref count is stored in the lower bits of the flags field, but skips the
  // 0x1 bit.
  return (block->flags & 0xFFFF) >> 1;
}

typedef struct {
  uint64_t header;
} ObjectRefCountExtractor;

static const uint64_t k128OrMore = 128;

// Returns the ref count of the object, up to 127. For counts above this, always
// returns k128OrMore.
uint64_t getObjectRetainCount(ObjectRefCountExtractor* object) {
  uint64_t count = object->header >> 56;
  return count < 0x80 ? count : k128OrMore;
}

int isReadableMemory(void* ptr) {
  vm_map_t task = mach_task_self();
  mach_vm_address_t address = (mach_vm_address_t)ptr;
  mach_vm_size_t size = 0;
  vm_region_basic_info_data_64_t info;
  mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
  mach_port_t object_name;
  kern_return_t status =
      mach_vm_region(task, &address, &size, VM_REGION_BASIC_INFO_64,
                     (vm_region_info_t)&info, &count, &object_name);
  if (status != KERN_SUCCESS) return 0;
  return ((mach_vm_address_t)ptr) >= address &&
         (info.protection & VM_PROT_READ);
}
