Ejemplo n.º 1
0
/*
 * Helper for the freeLocalsHelpers which does the actual work of decrementing
 * a value's refcount or releasing it.
 *
 * This helper is reached via call from the various freeLocalHelpers.  It
 * expects `tv' to be the address of a TypedValue with refcounted type `type'
 * (though it may be static, and we will do nothing in that case).
 *
 * The `live' registers must be preserved across any native calls (and
 * generally left untouched).
 */
static TCA emitDecRefHelper(CodeBlock& cb, DataBlock& data, CGMeta& fixups,
                            PhysReg tv, PhysReg type, RegSet live) {
  return vwrap(cb, data, fixups, [&] (Vout& v) {
    // Set up frame linkage to avoid an indirect fixup.
    v << pushp{rlr(), rfp()};
    v << copy{rsp(), rfp()};

    // We use the first argument register for the TV data because we might pass
    // it to the native release call.  It's not live when we enter the helper.
    auto const data = rarg(0);
    v << load{tv[TVOFF(m_data)], data};

    auto const sf = v.makeReg();
    v << cmplim{1, data[FAST_REFCOUNT_OFFSET], sf};

    ifThen(v, CC_NL, sf, [&] (Vout& v) {
      // The refcount is positive, so the value is refcounted.  We need to
      // either decref or release.
      ifThen(v, CC_NE, sf, [&] (Vout& v) {
        // The refcount is greater than 1; decref it.
        v << declm{data[FAST_REFCOUNT_OFFSET], v.makeReg()};
        // Pop FP/LR and return
        v << popp{rfp(), rlr()};
        v << ret{live};
      });

      // Note that the stack is aligned since we called to this helper from an
      // stack-unaligned stub.
      PhysRegSaver prs{v, live};

      // The refcount is exactly 1; release the value.
      // Avoid 'this' pointer overwriting by reserving it as an argument.
      v << callm{lookupDestructor(v, type), arg_regs(1)};

      // Between where %rsp is now and the saved RIP of the call into the
      // freeLocalsHelpers stub, we have all the live regs we pushed, plus the
      // saved RIP of the call from the stub to this helper.
      v << syncpoint{makeIndirectFixup(prs.dwordsPushed())};
      // fallthru
    });

    // Either we did a decref, or the value was static.
    // Pop FP/LR and return
    v << popp{rfp(), rlr()};
    v << ret{live};
  });
}
Ejemplo n.º 2
0
static int
rd_pars( FILE *fp )  /* returns NO_ERROR if no error, ERROR otherwise */
{
  if( get_next_line(name, NAME_LEN_LIMIT, fp) != NO_ERROR) {
    return(ERROR);
  }

  if(strcmp(name, "\\generate_subalgebra")== 0)
  {
    return(gen_subalg(fp));
  }
  if(strcmp(name, "\\create_direct_product")== 0)
  {
    return(cr_dir_prod(fp));
  }
  if(strcmp(name, "\\create_factor_algebra")== 0)
  {
    return(cr_fact_alg(fp));
  }
  if(strcmp(name, "\\create_subproduct_algebra")== 0)
  {
    return(cr_subpr_alg(fp));
  }
  if(strcmp(name, "\\product_congruence")== 0)
  {
    return(cr_prod_cong(fp));
  }
  if(strcmp(name, "\\find_congruence_number")== 0)
  {
    return(find_congnum(fp));
  }
  if(strcmp(name, "\\generate_congruence")== 0)
  {
    return(gen_cong(fp));
  }
  if(strcmp(name, "\\compute_congruence_lattice")== 0)
  {
    return(gen_conlat(fp));
  }
  if(strcmp(name, "\\centrality")== 0)
  {
    return(is_centr(fp, CENTR_NORMAL));
  }
  if(strcmp(name, "\\weak_centrality")== 0)
  {
    return(is_centr(fp, CENTR_WEAK));
  }
  if(strcmp(name, "\\strong_centrality")== 0)
  {
    return(is_centr(fp, CENTR_STRONG));
  }
  if(strcmp(name, "\\rectangular_centrality")== 0)
  {
    return(is_centr(fp, CENTR_RECT));
  }
  if(strcmp(name, "\\compute_R(L,R)")== 0)
  {
    return(rlr(fp));
  }
  if(strcmp(name, "\\compute_min_sets")== 0)
  {
    return(min_sets(fp));
  }
  if(strcmp(name, "\\unary_polynomials")== 0)
  {
    return(un_pol(fp));
  }
  if(strcmp(name, "\\compute_type")== 0)
  {
    return(type_q(fp));
  }
  if(strcmp(name, "\\label_congruence_lattice")== 0)
  {
    return(label_conlat(fp));
  }
  if(strcmp(name, "\\find_kkvm_germ")== 0)
  {
    return(kkvm_germ(fp));
  }
  print_derr("Unrecognized command `%s'.", name);
  hlp_commands();
  return(ERROR);
}
Ejemplo n.º 3
0
TCA emitFreeLocalsHelpers(CodeBlock& cb, DataBlock& data, UniqueStubs& us) {
  // The address of the first local is passed in the second argument register.
  // We use the third and fourth as scratch registers.
  auto const local = rarg(1);
  auto const last = rarg(2);
  auto const type = rarg(3);
  CGMeta fixups;
  TCA freeLocalsHelpers[kNumFreeLocalsHelpers];
  TCA freeManyLocalsHelper;

  // This stub is very hot; keep it cache-aligned.
  align(cb, &fixups, Alignment::CacheLine, AlignContext::Dead);
  auto const release =
    emitDecRefHelper(cb, data, fixups, local, type, local | last);

  auto const decref_local = [&] (Vout& v) {
    auto const sf = v.makeReg();

    // We can't use emitLoadTVType() here because it does a byte load, and we
    // need to sign-extend since we use `type' as a 32-bit array index to the
    // destructor table.
    v << loadzbl{local[TVOFF(m_type)], type};
    emitCmpTVType(v, sf, KindOfRefCountThreshold, type);

    ifThen(v, CC_G, sf, [&] (Vout& v) {
      v << call{release, arg_regs(3)};
    });
  };

  auto const next_local = [&] (Vout& v) {
    v << addqi{static_cast<int>(sizeof(TypedValue)),
               local, local, v.makeReg()};
  };

  alignJmpTarget(cb);

  freeManyLocalsHelper = vwrap(cb, data, [&] (Vout& v) {
    // We always unroll the final `kNumFreeLocalsHelpers' decrefs, so only loop
    // until we hit that point.
    v << lea{rvmfp()[localOffset(kNumFreeLocalsHelpers - 1)], last};

    // Set up frame linkage to avoid an indirect fixup.
    v << copy{rsp(), rfp()};

    doWhile(v, CC_NZ, {},
      [&] (const VregList& in, const VregList& out) {
        auto const sf = v.makeReg();

        decref_local(v);
        next_local(v);
        v << cmpq{local, last, sf};
        return sf;
      }
    );
  });

  for (auto i = kNumFreeLocalsHelpers - 1; i >= 0; --i) {
    freeLocalsHelpers[i] = vwrap(cb, data, [&] (Vout& v) {
      decref_local(v);
      if (i != 0) next_local(v);
    });
  }

  // All the stub entrypoints share the same ret.
  vwrap(cb, data, fixups, [] (Vout& v) {
    v << popp{rfp(), rlr()};
    v << ret{};
  });

  // Create a table of branches
  us.freeManyLocalsHelper = vwrap(cb, data, [&] (Vout& v) {
    v << pushp{rlr(), rfp()};

    // rvmfp() is needed by the freeManyLocalsHelper stub above, so frame
    // linkage setup is deferred until after its use in freeManyLocalsHelper.
    v << jmpi{freeManyLocalsHelper};
  });
  for (auto i = kNumFreeLocalsHelpers - 1; i >= 0; --i) {
    us.freeLocalsHelpers[i] = vwrap(cb, data, [&] (Vout& v) {
      // We set up frame linkage to avoid an indirect fixup.
      v << pushp{rlr(), rfp()};
      v << copy{rsp(), rfp()};
      v << jmpi{freeLocalsHelpers[i]};
    });
  }

  // FIXME: This stub is hot, so make sure to keep it small.
#if 0
  always_assert(Stats::enabled() ||
                (cb.frontier() - release <= 4 * x64::cache_line_size()));
#endif

  fixups.process(nullptr);
  return release;
}