예제 #1
0
static bool
markFastSafeFn(FnSymbol *fn, int recurse, Vec<FnSymbol*> *visited) {
  if (fn->hasFlag(FLAG_FAST_ON))
    return true;

  if (fn->hasFlag(FLAG_EXPORT))
    return true;

  if (fn->hasFlag(FLAG_EXTERN)) {
    // consider a pragma to indicate that it would be "fast"
    return false;
  }

  if (fn->hasFlag(FLAG_NON_BLOCKING))
    return false;

  visited->add_exclusive(fn);

  std::vector<CallExpr*> calls;

  collectCallExprs(fn, calls);

  for_vector(CallExpr, call, calls) {
    DEBUG_PRINTF("\tcall %p (id=%d): ", call, call->id);
    bool isLocal = fn->hasFlag(FLAG_LOCAL_FN) || inLocalBlock(call);

    if (!call->primitive) {
      DEBUG_PRINTF("(non-primitive CALL)\n");
      if ((recurse>0) && call->isResolved()) {
        if (call->isResolved()->hasFlag(FLAG_ON_BLOCK)) {
          visited->add_exclusive(call->isResolved());
          call->isResolved()->removeFlag(FLAG_FAST_ON);
          DEBUG_PRINTF("%d: recurse FAILED (nested on block, id=%d).\n",
                       recurse-1, call->id);
          return false;
        }
        if (!visited->in(call->isResolved())) {
          DEBUG_PRINTF("%d: recurse %p (block=%p, id=%d)\n", recurse-1,
                       call->isResolved(), call->isResolved()->body,
                       call->isResolved()->id);
          DEBUG_PRINTF("\tlength=%d\n", call->isResolved()->body->length());
          if (!markFastSafeFn(call->isResolved(), recurse-1, visited)) {
            DEBUG_PRINTF("%d: recurse FAILED (id=%d).\n", recurse-1, call->id);
            return false;
          }
        } else {
          DEBUG_PRINTF("%d: recurse ALREADY VISITED %p (id=%d)\n", recurse-1,
                       call->isResolved(), call->isResolved()->id);
          DEBUG_PRINTF("\tlength=%d\n", call->isResolved()->body->length());
        }
        DEBUG_PRINTF("%d: recurse DONE.\n", recurse-1);
      } else {
        // No function calls allowed
        DEBUG_PRINTF("%d: recurse FAILED (%s, id=%d).\n", recurse-1,
                     recurse == 1 ? "too deep" : "function not resolved",
                     call->id);
        return false;
      }
    } else if (isFastPrimitive(call, isLocal)) {
      DEBUG_PRINTF(" (FAST primitive CALL)\n");
    } else {
      DEBUG_PRINTF("%d: FAILED (non-FAST primitive CALL: %s, id=%d)\n",
                   recurse-1, call->primitive->name, call->id);
      return false;
    }
  }
예제 #2
0
static int
markFastSafeFn(FnSymbol *fn, int recurse, std::set<FnSymbol*>& visited) {

  // First, handle functions we've already visited.
  if (visited.count(fn) != 0) {
    if (fn->hasFlag(FLAG_FAST_ON))
      return FAST_AND_LOCAL;
    if (fn->hasFlag(FLAG_LOCAL_FN))
      return LOCAL_NOT_FAST;
    return NOT_FAST_NOT_LOCAL;
  }

  // Now, add fn to the set of visited functions,
  // since we will categorize it now.
  visited.insert(fn);

  // Next, classify extern functions
  if (fn->hasFlag(FLAG_EXTERN)) {
    if (fn->hasFlag(FLAG_FAST_ON_SAFE_EXTERN)) {
      // Make sure the FAST_ON and LOCAL_FN flags are set.
      fn->addFlag(FLAG_FAST_ON);
      fn->addFlag(FLAG_LOCAL_FN);
      return FAST_AND_LOCAL;
    } else if(fn->hasFlag(FLAG_LOCAL_FN)) {
      return LOCAL_NOT_FAST;
    } else {
      // Other extern functions are not fast or local.
      return NOT_FAST_NOT_LOCAL;
    }
  }

  // Next, go through function bodies.
  // We will set maybefast=false if we see something in the function
  //  that is local but not suitable for a signal handler
  //  (mostly allocation or locking).
  // We will return NOT_FAST_NOT_LOCAL immediately if we see something
  // in the function that is not local.
  bool maybefast = true;

  if (fn->hasFlag(FLAG_NON_BLOCKING))
    maybefast = false;

  std::vector<CallExpr*> calls;

  collectCallExprs(fn, calls);

  for_vector(CallExpr, call, calls) {
    bool inLocal = fn->hasFlag(FLAG_LOCAL_FN) || inLocalBlock(call);

    if (call->primitive) {
      int is = classifyPrimitive(call, inLocal);

      if (!isLocal(is)) {
        // FAST_NOT_LOCAL or NOT_FAST_NOT_LOCAL
        return NOT_FAST_NOT_LOCAL;
      }

      // is == FAST_AND_LOCAL requires no action
      if (is == LOCAL_NOT_FAST) {
        maybefast = false;
      }

    } else {
      if (recurse<=0 || !call->isResolved()) {
        // didn't resolve or past too much recursion.
        // No function calls allowed
        return NOT_FAST_NOT_LOCAL;

      } else {
        // Handle nested 'on' statements
        if (call->resolvedFunction()->hasFlag(FLAG_ON_BLOCK)) {
          if (inLocal) {
            maybefast = false;
          } else {
            return NOT_FAST_NOT_LOCAL;
          }
        }

        // is the call to a fast/local function?
        int is = markFastSafeFn(call->resolvedFunction(),
                                recurse - 1,
                                visited);

        // Remove NOT_LOCAL parts if it's in a local block
        is = setLocal(is, inLocal);

        if (!isLocal(is)) {
          return NOT_FAST_NOT_LOCAL;
        }

        if (is == LOCAL_NOT_FAST) {
          maybefast = false;
        }
        // otherwise, possibly still fast.
      }
    }
  }