예제 #1
0
/// Transform AccessedStorage from a callee into the caller context. If this is
/// uniquely identified local storage, then return an invalid storage object.
///
/// For correctness, AccessEnforcementOpts relies on all Argument access to
/// either be mapped into the caller's context or marked as an unidentified
/// access at the call site.
///
/// Note: This does *not* map the storage index into the caller function's index
/// range. (When the storage value doesn't need to be remapped, it returns the
/// original storage value.) It's simpler to set the storage index later when it
/// is actually added to the function's storageAccessSet.
static StorageAccessInfo
transformCalleeStorage(const StorageAccessInfo &storage,
                       FullApplySite fullApply) {
  switch (storage.getKind()) {
  case AccessedStorage::Box:
  case AccessedStorage::Stack:
    // Do not merge local storage.
    return StorageAccessInfo(AccessedStorage(), storage);
  case AccessedStorage::Global:
    // Global accesses is universal.
    return storage;
  case AccessedStorage::Class: {
    // If the object's value is an argument, translate it into a value on the
    // caller side.
    SILValue obj = storage.getObjectProjection().getObject();
    if (auto *arg = dyn_cast<SILFunctionArgument>(obj)) {
      SILValue argVal = getCallerArg(fullApply, arg->getIndex());
      if (argVal) {
        auto &proj = storage.getObjectProjection().getProjection();
        // Remap the argument source value and inherit the old storage info.
        return StorageAccessInfo(AccessedStorage(argVal, proj), storage);
      }
    }
    // Otherwise, continue to reference the value in the callee because we don't
    // have any better placeholder for a callee-defined object.
    return storage;
  }
  case AccessedStorage::Argument: {
    // Transitively search for the storage base in the caller.
    SILValue argVal = getCallerArg(fullApply, storage.getParamIndex());
    if (argVal) {
      // Remap the argument source value and inherit the old storage info.
      auto calleeStorage = findAccessedStorageNonNested(argVal);
      if (calleeStorage)
        return StorageAccessInfo(calleeStorage, storage);
    }
    // If the argument can't be transformed, demote it to an unidentified
    // access.
    return StorageAccessInfo(
      AccessedStorage(storage.getValue(), AccessedStorage::Unidentified),
      storage);
  }
  case AccessedStorage::Nested:
    llvm_unreachable("Unexpected nested access");
  case AccessedStorage::Yield:
    // Continue to hold on to yields from the callee because we don't have
    // any better placeholder in the callee.
    return storage;
  case AccessedStorage::Unidentified:
    // For unidentified storage, continue to reference the value in the callee
    // because we don't have any better placeholder for a callee-defined object.
    return storage;
  }
}
예제 #2
0
/// Transform AccessedStorage from a callee into the caller context. If this is
/// uniquely identified local storage, then return an invalid storage object.
///
/// For correctness, AccessEnforcementOpts relies on all Argument access to
/// either be mapped into the caller's context or marked as an unidentified
/// access at the call site.
///
/// Note: This does *not* map the storage index into the caller function's index
/// range. (When the storage value doesn't need to be remapped, it returns the
/// original storage value.) It's simpler to set the storage index later when it
/// is actually added to the function's storageAccessSet.
static StorageAccessInfo
transformCalleeStorage(const StorageAccessInfo &storage,
                       FullApplySite fullApply) {
  switch (storage.getKind()) {
  case AccessedStorage::Box:
  case AccessedStorage::Stack:
    // Do not merge local storage.
    return StorageAccessInfo(AccessedStorage(), storage);
  case AccessedStorage::Global:
    // Global accesses is universal.
    return storage;
  case AccessedStorage::Class: {
    // If the object's value is an argument, translate it into a value on the
    // caller side.
    SILValue obj = storage.getObjectProjection().getObject();
    if (auto *arg = dyn_cast<SILFunctionArgument>(obj)) {
      SILValue argVal = getCallerArg(fullApply, arg->getIndex());
      if (argVal) {
        auto *instr = storage.getObjectProjection().getInstr();
        // Remap the argument source value and inherit the old storage info.
        return StorageAccessInfo(AccessedStorage(argVal, instr), storage);
      }
    }
    // Otherwise, continue to reference the value in the callee because we don't
    // have any better placeholder for a callee-defined object.
    return storage;
  }
  case AccessedStorage::Argument: {
    // Transitively search for the storage base in the caller.
    SILValue argVal = getCallerArg(fullApply, storage.getParamIndex());
    if (argVal) {
      // Remap the argument source value and inherit the old storage info.
      auto calleeStorage = findAccessedStorageNonNested(argVal);
      if (calleeStorage)
        return StorageAccessInfo(calleeStorage, storage);
    }
    // If the argument can't be transformed, demote it to an unidentified
    // access.
    //
    // This is an untested bailout. It is only reachable if the call graph
    // contains an edge that getCallerArg is unable to analyze OR if
    // findAccessedStorageNonNested returns an invalid SILValue, which won't
    // pass SIL verification.
    //
    // FIXME: In case argVal is invalid, support Unidentified access for invalid
    // values. This would also be useful for partially invalidating results.
    return StorageAccessInfo(
        AccessedStorage(argVal, AccessedStorage::Unidentified), storage);
  }
  case AccessedStorage::Nested:
    llvm_unreachable("Unexpected nested access");
  case AccessedStorage::Yield:
    // Continue to hold on to yields from the callee because we don't have
    // any better placeholder in the callee.
    return storage;
  case AccessedStorage::Unidentified:
    // For unidentified storage, continue to reference the value in the callee
    // because we don't have any better placeholder for a callee-defined object.
    return storage;
  }
  llvm_unreachable("unhandled kind");
}