Ejemplo n.º 1
0
void emitSSwitch(HTS& env, const ImmVector& iv) {
  const int numCases = iv.size() - 1;

  /*
   * We use a fast path translation with a hashtable if none of the
   * cases are numeric strings and if the input is actually a string.
   *
   * Otherwise we do a linear search through the cases calling string
   * conversion routines.
   */
  const bool fastPath =
    topC(env)->isA(Type::Str) &&
    std::none_of(iv.strvec(), iv.strvec() + numCases,
      [&](const StrVecItem& item) {
        return curUnit(env)->lookupLitstrId(item.str)->isNumeric();
      }
    );

  auto const testVal = popC(env);

  std::vector<LdSSwitchData::Elm> cases(numCases);
  for (int i = 0; i < numCases; ++i) {
    auto const& kv = iv.strvec()[i];
    cases[i].str  = curUnit(env)->lookupLitstrId(kv.str);
    cases[i].dest = SrcKey{curSrcKey(env), bcOff(env) + kv.dest};
  }

  LdSSwitchData data;
  data.numCases   = numCases;
  data.cases      = &cases[0];
  data.defaultSk  = SrcKey{curSrcKey(env),
                           bcOff(env) + iv.strvec()[iv.size() - 1].dest};

  auto const dest = gen(env,
                        fastPath ? LdSSwitchDestFast
                                 : LdSSwitchDestSlow,
                        data,
                        testVal);
  gen(env, DecRef, testVal);
  gen(env, AdjustSP, IRSPOffsetData { offsetFromIRSP(env, BCSPOffset{0}) },
    sp(env));
  gen(env, JmpSSwitchDest, dest, sp(env));
}
Ejemplo n.º 2
0
void emitIterBreak(IRGS& env, Offset relOffset, const ImmVector& iv) {
  for (int iterIndex = 0; iterIndex < iv.size(); iterIndex += 2) {
    IterKind iterKind = (IterKind)iv.vec32()[iterIndex];
    Id       iterId   = iv.vec32()[iterIndex + 1];
    switch (iterKind) {
    case KindOfIter:  gen(env, IterFree,  IterId(iterId), fp(env)); break;
    case KindOfMIter: gen(env, MIterFree, IterId(iterId), fp(env)); break;
    case KindOfCIter: gen(env, CIterFree, IterId(iterId), fp(env)); break;
    }
  }

  jmpImpl(env, bcOff(env) + relOffset);
}
Ejemplo n.º 3
0
void emitIterBreak(IRGS& env,
                   const ImmVector& iv,
                   Offset relOffset) {
  always_assert(env.currentNormalizedInstruction->endsRegion);

  for (int iterIndex = 0; iterIndex < iv.size(); iterIndex += 2) {
    IterKind iterKind = (IterKind)iv.vec32()[iterIndex];
    Id       iterId   = iv.vec32()[iterIndex + 1];
    switch (iterKind) {
    case KindOfIter:  gen(env, IterFree,  IterId(iterId), fp(env)); break;
    case KindOfMIter: gen(env, MIterFree, IterId(iterId), fp(env)); break;
    case KindOfCIter: gen(env, CIterFree, IterId(iterId), fp(env)); break;
    }
  }

  // Would need to change this if we support not ending regions on this:
  gen(env, Jmp, makeExit(env, bcOff(env) + relOffset));
}
Ejemplo n.º 4
0
void emitNewStructArray(HTS& env, const ImmVector& immVec) {
  auto const numArgs = immVec.size();
  auto const ids = immVec.vec32();

  // The NewPackedArray opcode's helper needs array values passed to it
  // via the stack.  We use spillStack() to flush the eval stack and
  // obtain a pointer to the topmost item; if over-flushing becomes
  // a problem then we should refactor the NewPackedArray opcode to
  // take its values directly as SSA operands.
  spillStack(env);

  NewStructData extra;
  extra.offset  = offsetFromSP(env, 0);
  extra.numKeys = numArgs;
  extra.keys    = new (env.unit.arena()) StringData*[numArgs];
  for (auto i = size_t{0}; i < numArgs; ++i) {
    extra.keys[i] = curUnit(env)->lookupLitstrId(ids[i]);
  }

  discard(env, numArgs);
  push(env, gen(env, NewStructArray, extra, sp(env)));
}
Ejemplo n.º 5
0
void emitSwitch(HTS& env,
                const ImmVector& iv,
                int64_t base,
                int32_t bounded) {
  int nTargets = bounded ? iv.size() - 2 : iv.size();

  SSATmp* const switchVal = popC(env);
  Type type = switchVal->type();
  assert(IMPLIES(!(type <= Type::Int), bounded));
  assert(IMPLIES(bounded, iv.size() > 2));
  SSATmp* index;
  SSATmp* ssabase = cns(env, base);
  SSATmp* ssatargets = cns(env, nTargets);

  Offset defaultOff = bcOff(env) + iv.vec32()[iv.size() - 1];
  Offset zeroOff = 0;
  if (base <= 0 && (base + nTargets) > 0) {
    zeroOff = bcOff(env) + iv.vec32()[0 - base];
  } else {
    zeroOff = defaultOff;
  }

  if (type <= Type::Null) {
    gen(env, Jmp, makeExit(env, zeroOff));
    return;
  }
  if (type <= Type::Bool) {
    Offset nonZeroOff = bcOff(env) + iv.vec32()[iv.size() - 2];
    gen(env, JmpNZero, makeExit(env, nonZeroOff), switchVal);
    gen(env, Jmp, makeExit(env, zeroOff));
    return;
  }

  if (type <= Type::Int) {
    // No special treatment needed
    index = switchVal;
  } else if (type <= Type::Dbl) {
    // switch(Double|String|Obj)Helper do bounds-checking for us, so
    // we need to make sure the default case is in the jump table,
    // and don't emit our own bounds-checking code
    bounded = false;
    index = gen(env, LdSwitchDblIndex, switchVal, ssabase, ssatargets);
  } else if (type <= Type::Str) {
    bounded = false;
    index = gen(env, LdSwitchStrIndex, switchVal, ssabase, ssatargets);
  } else if (type <= Type::Obj) {
    // switchObjHelper can throw exceptions and reenter the VM so we use the
    // catch block here.
    bounded = false;
    index = gen(env, LdSwitchObjIndex, switchVal, ssabase, ssatargets);
  } else if (type <= Type::Arr) {
    gen(env, DecRef, switchVal);
    gen(env, Jmp, makeExit(env, defaultOff));
    return;
  } else {
    PUNT(Switch-UnknownType);
  }

  std::vector<Offset> targets(iv.size());
  for (int i = 0; i < iv.size(); i++) {
    targets[i] = bcOff(env) + iv.vec32()[i];
  }

  JmpSwitchData data;
  data.base        = base;
  data.bounded     = bounded;
  data.cases       = iv.size();
  data.defaultOff  = defaultOff;
  data.targets     = &targets[0];

  spillStack(env);
  gen(env, AdjustSP, StackOffset { offsetFromSP(env, 0) }, sp(env));
  gen(env, JmpSwitchDest, data, index, sp(env));
}