bool tvSame(const TypedValue* tv1, const TypedValue* tv2) { bool const null1 = IS_NULL_TYPE(tv1->m_type); bool const null2 = IS_NULL_TYPE(tv2->m_type); if (null1 && null2) return true; if (null1 || null2) return false; if (tv1->m_type == KindOfRef) tv1 = tv1->m_data.pref->tv(); if (tv2->m_type == KindOfRef) tv2 = tv2->m_data.pref->tv(); switch (tv1->m_type) { case KindOfInt64: case KindOfBoolean: if (tv2->m_type != tv1->m_type) return false; return tv1->m_data.num == tv2->m_data.num; case KindOfDouble: if (tv2->m_type != tv1->m_type) return false; return tv1->m_data.dbl == tv2->m_data.dbl; case KindOfStaticString: case KindOfString: if (!IS_STRING_TYPE(tv2->m_type)) return false; return tv1->m_data.pstr->same(tv2->m_data.pstr); case KindOfArray: if (tv2->m_type != KindOfArray) return false; return tv1->m_data.parr->equal(tv2->m_data.parr, true); case KindOfObject: return tv2->m_type == KindOfObject && tv1->m_data.pobj == tv2->m_data.pobj; default: break; } not_reached(); }
Resource Variant::toResourceHelper() const { switch (m_type) { case KindOfUninit: case KindOfNull: case KindOfBoolean: case KindOfInt64: case KindOfDouble: case KindOfStaticString: case KindOfString: case KindOfArray: case KindOfObject: return Resource(makeSmartPtr<DummyResource>()); case KindOfResource: return m_data.pres; case KindOfRef: return m_data.pref->var()->toResource(); case KindOfClass: break; } not_reached(); }
void Variant::setEvalScalar() { switch (m_type) { DT_UNCOUNTED_CASE: return; case KindOfString: { StringData *pstr = m_data.pstr; if (!pstr->isStatic()) { StringData *sd = makeStaticString(pstr); decRefStr(pstr); m_data.pstr = sd; assert(m_data.pstr->isStatic()); m_type = KindOfStaticString; } return; } case KindOfArray: { ArrayData *parr = m_data.parr; if (!parr->isStatic()) { ArrayData *ad = ArrayData::GetScalarArray(parr); decRefArr(parr); m_data.parr = ad; assert(m_data.parr->isStatic()); } return; } case KindOfObject: case KindOfResource: case KindOfRef: case KindOfClass: break; } not_reached(); }
bool cellSame(Cell c1, Cell c2) { assert(cellIsPlausible(c1)); assert(cellIsPlausible(c2)); bool const null1 = IS_NULL_TYPE(c1.m_type); bool const null2 = IS_NULL_TYPE(c2.m_type); if (null1 && null2) return true; if (null1 || null2) return false; switch (c1.m_type) { case KindOfInt64: case KindOfBoolean: if (c2.m_type != c1.m_type) return false; return c1.m_data.num == c2.m_data.num; case KindOfDouble: if (c2.m_type != c1.m_type) return false; return c1.m_data.dbl == c2.m_data.dbl; case KindOfStaticString: case KindOfString: if (!IS_STRING_TYPE(c2.m_type)) return false; return c1.m_data.pstr->same(c2.m_data.pstr); case KindOfArray: if (c2.m_type != KindOfArray) return false; return c1.m_data.parr->equal(c2.m_data.parr, true); case KindOfObject: return c2.m_type == KindOfObject && c1.m_data.pobj == c2.m_data.pobj; default: break; } not_reached(); }
bool Variant::isScalar() const noexcept { switch (getType()) { case KindOfUninit: case KindOfNull: case KindOfArray: case KindOfObject: case KindOfResource: return false; case KindOfBoolean: case KindOfInt64: case KindOfDouble: case KindOfStaticString: case KindOfString: return true; case KindOfRef: always_assert(false && "isScalar() called on a boxed value"); case KindOfClass: break; } not_reached(); }
void IRTranslator::translateSetOpL(const NormalizedInstruction& i) { auto const opc = [&] { switch (static_cast<SetOpOp>(i.imm[1].u_OA)) { case SetOpOp::PlusEqual: return Op::Add; case SetOpOp::MinusEqual: return Op::Sub; case SetOpOp::MulEqual: return Op::Mul; case SetOpOp::PlusEqualO: return Op::AddO; case SetOpOp::MinusEqualO: return Op::SubO; case SetOpOp::MulEqualO: return Op::MulO; case SetOpOp::DivEqual: HHIR_UNIMPLEMENTED(SetOpL_Div); case SetOpOp::ConcatEqual: return Op::Concat; case SetOpOp::ModEqual: HHIR_UNIMPLEMENTED(SetOpL_Mod); case SetOpOp::PowEqual: HHIR_UNIMPLEMENTED(SetOpL_Pow);; case SetOpOp::AndEqual: return Op::BitAnd; case SetOpOp::OrEqual: return Op::BitOr; case SetOpOp::XorEqual: return Op::BitXor; case SetOpOp::SlEqual: HHIR_UNIMPLEMENTED(SetOpL_Shl); case SetOpOp::SrEqual: HHIR_UNIMPLEMENTED(SetOpL_Shr); } not_reached(); }(); HHIR_EMIT(SetOpL, opc, i.imm[0].u_LA); }
DataType Type::toDataType() const { assert(!isPtr()); if (isBoxed()) { return KindOfRef; } // Order is important here: types must progress from more specific // to less specific to return the most specific DataType. if (subtypeOf(Uninit)) return KindOfUninit; if (subtypeOf(Null)) return KindOfNull; if (subtypeOf(Bool)) return KindOfBoolean; if (subtypeOf(Int)) return KindOfInt64; if (subtypeOf(Dbl)) return KindOfDouble; if (subtypeOf(StaticStr)) return KindOfStaticString; if (subtypeOf(Str)) return KindOfString; if (subtypeOf(Arr)) return KindOfArray; if (subtypeOf(Obj)) return KindOfObject; if (subtypeOf(Res)) return KindOfResource; if (subtypeOf(Cls)) return KindOfClass; if (subtypeOf(UncountedInit)) return KindOfUncountedInit; if (subtypeOf(Uncounted)) return KindOfUncounted; if (subtypeOf(Gen)) return KindOfAny; not_reached(); }
RegionDescPtr selectRegion(const RegionContext& context, TransKind kind) { auto const mode = regionMode(); FTRACE(1, "Select region: mode={} context:\n{}", static_cast<int>(mode), show(context) ); auto region = [&]{ try { switch (mode) { case RegionMode::None: return RegionDescPtr{nullptr}; case RegionMode::Method: return selectMethod(context); case RegionMode::Tracelet: return selectTracelet(context, RuntimeOption::EvalJitMaxRegionInstrs, kind == TransKind::Profile); } not_reached(); } catch (const std::exception& e) { FTRACE(1, "region selector threw: {}\n", e.what()); return RegionDescPtr{nullptr}; } }(); if (region) { FTRACE(3, "{}", show(*region)); always_assert(region->instrSize() <= RuntimeOption::EvalJitMaxRegionInstrs); } else { FTRACE(1, "no region selectable; using tracelet compiler\n"); } return region; }
/** * Returns the expected input flavor of stack slot idx. */ FlavorDesc instrInputFlavor(PC op, uint32_t idx) { #define NOV always_assert(0 && "Opcode has no stack inputs"); #define ONE(f1) return doFlavor(idx, f1); #define TWO(f1, f2) return doFlavor(idx, f1, f2); #define THREE(f1, f2, f3) return doFlavor(idx, f1, f2, f3); #define FOUR(f1, f2, f3, f4) return doFlavor(idx, f1, f2, f3, f4); #define MFINAL return manyFlavor(op, idx, CRV); #define F_MFINAL MFINAL #define C_MFINAL return idx == 0 ? CV : CRV; #define V_MFINAL return idx == 0 ? VV : CRV; #define FMANY return manyFlavor(op, idx, FV); #define CVUMANY return manyFlavor(op, idx, CVUV); #define CMANY return manyFlavor(op, idx, CV); #define SMANY return manyFlavor(op, idx, CV); #define IDX_A return baseSFlavor(op, idx); #define O(name, imm, pop, push, flags) case Op::name: pop switch (peek_op(op)) { OPCODES } not_reached(); #undef NOV #undef ONE #undef TWO #undef THREE #undef FOUR #undef MFINAL #undef F_MFINAL #undef C_MFINAL #undef V_MFINAL #undef FMANY #undef CVUMANY #undef CMANY #undef SMANY #undef IDX_A #undef O }
DataType DataTypeProfiler::operator()(DataType type) { switch (type) { case KindOfUninit: m_uninit.count(); break; case KindOfNull: m_null.count(); break; case KindOfBoolean: m_boolean.count(); break; case KindOfInt64: m_int.count(); break; case KindOfDouble: m_double.count(); break; case KindOfPersistentString: m_persistent_string.count(); break; case KindOfString: m_string.count(); break; case KindOfPersistentVec: m_persistent_vec.count(); break; case KindOfVec: m_vec.count(); break; case KindOfPersistentDict: m_persistent_dict.count(); break; case KindOfDict: m_dict.count(); break; case KindOfPersistentKeyset: m_persistent_keyset.count(); break; case KindOfKeyset: m_keyset.count(); break; case KindOfPersistentArray: m_persistent_array.count(); break; case KindOfArray: m_array.count(); break; case KindOfObject: m_object.count(); break; case KindOfResource: m_resource.count(); break; case KindOfRef: m_ref.count(); break; case KindOfClass: not_reached(); } return type; }
StringData* tvCastToString(const TypedValue* tv) { assert(tvIsPlausible(*tv)); if (tv->m_type == KindOfRef) { tv = tv->m_data.pref->tv(); } StringData* s; switch (tv->m_type) { case KindOfUninit: case KindOfNull: return empty_string.get(); case KindOfBoolean: return tv->m_data.num ? s_1.get() : empty_string.get(); case KindOfInt64: s = buildStringData(tv->m_data.num); break; case KindOfDouble: s = buildStringData(tv->m_data.dbl); break; case KindOfStaticString: return tv->m_data.pstr; case KindOfString: s = tv->m_data.pstr; break; case KindOfArray: return s_Array.get(); case KindOfObject: return tv->m_data.pobj->invokeToString().detach(); case KindOfResource: return tv->m_data.pres->o_toString().detach(); default: not_reached(); } s->incRefCount(); return s; }
/* * Returns true iff t is specific enough to fit tc, meaning a consumer * constraining a value with tc would be satisfied with t as the value's type * after relaxation. */ bool typeFitsConstraint(Type t, TypeConstraint tc) { assert(t != Type::Bottom); if (tc.innerCat > DataTypeGeneric) { // First check the outer constraint. if (!typeFitsConstraint(t, tc.category)) return false; // Then, if t might be boxed, check the inner type. return t.notBoxed() || typeFitsConstraint((t & Type::BoxedCell).innerType(), tc.innerCat); } switch (tc.category) { case DataTypeGeneric: return true; case DataTypeCountness: // Consumers using this constraint are probably going to decref the // value, so it's ok if we know whether t is counted or not. Arr and Str // are special cased because we don't guard on staticness for them. return t.notCounted() || t <= (Type::Counted | Type::StaticArr | Type::StaticStr); case DataTypeCountnessInit: return typeFitsConstraint(t, DataTypeCountness) && (t <= Type::Uninit || t.not(Type::Uninit)); case DataTypeSpecific: return t.isKnownDataType(); case DataTypeSpecialized: return t.isSpecialized(); } not_reached(); }
MemberKey decode_member_key(PC& pc, Either<const Unit*, const UnitEmitter*> u) { auto const mcode = static_cast<MemberCode>(decode_byte(pc)); switch (mcode) { case MEC: case MEL: case MPC: case MPL: return MemberKey{mcode, decode_iva(pc)}; case MEI: return MemberKey{mcode, decode_raw<int64_t>(pc)}; case MET: case MPT: case MQT: { auto const id = decode_raw<Id>(pc); auto const str = u.match( [id](const Unit* u) { return u->lookupLitstrId(id); }, [id](const UnitEmitter* ue) { return ue->lookupLitstr(id); } ); return MemberKey{mcode, str}; } case MW: return MemberKey{}; } not_reached(); }
/* * Returns the least specific supertype of t that maintains the properties * required by cat. */ Type relaxType(Type t, DataTypeCategory cat) { always_assert(t <= Type::Gen); switch (cat) { case DataTypeGeneric: return Type::Gen; case DataTypeCountness: return t.notCounted() ? Type::Uncounted : t.unspecialize(); case DataTypeCountnessInit: if (t <= Type::Uninit) return Type::Uninit; return t.notCounted() ? Type::UncountedInit : t.unspecialize(); case DataTypeSpecific: return t.unspecialize(); case DataTypeSpecialized: assert(t.isSpecialized()); return t; } not_reached(); }
Type typeSetOp(SetOpOp op, Type lhs, Type rhs) { switch (op) { case SetOpOp::PlusEqual: return typeAdd(lhs, rhs); case SetOpOp::MinusEqual: return typeSub(lhs, rhs); case SetOpOp::MulEqual: return typeMul(lhs, rhs); case SetOpOp::DivEqual: return typeDiv(lhs, rhs); case SetOpOp::ModEqual: return typeMod(lhs, rhs); case SetOpOp::PowEqual: return typePow(lhs, rhs); case SetOpOp::AndEqual: return typeBitAnd(lhs, rhs); case SetOpOp::OrEqual: return typeBitOr(lhs, rhs); case SetOpOp::XorEqual: return typeBitXor(lhs, rhs); case SetOpOp::PlusEqualO: return typeAddO(lhs, rhs); case SetOpOp::MinusEqualO: return typeSubO(lhs, rhs); case SetOpOp::MulEqualO: return typeMulO(lhs, rhs); case SetOpOp::ConcatEqual: return TStr; case SetOpOp::SlEqual: return typeShl(lhs, rhs); case SetOpOp::SrEqual: return typeShr(lhs, rhs); } not_reached(); }
void CodeGenerator::cgLdRaw(IRInstruction* inst) { auto* addr = inst->src(0); auto* offset = inst->src(1); auto destReg = x2a(curOpd(inst->dst()).reg()); auto addrReg = x2a(curOpd(addr).reg()); if (addr->isConst()) { not_implemented(); } if (offset->isConst()) { auto kind = offset->getValInt(); auto& slot = RawMemSlot::Get(RawMemSlot::Kind(kind)); auto ldSize = slot.size(); auto offs = slot.offset(); switch (ldSize) { case sz::qword: m_as. Ldr (destReg, addrReg[offs]); break; case sz::dword: m_as. Ldr (destReg.W(), addrReg[offs]); break; case sz::byte: // Ldrb zero-extends m_as. Ldrb (destReg.W(), addrReg[offs]); break; default: not_reached(); } } else { auto offsetReg = x2a(curOpd(offset).reg()); assert(inst->dst()->type().nativeSize() == sz::qword); m_as. Ldr (destReg, addrReg[offsetReg]); } }
double Variant::toDoubleHelper() const { switch (m_type) { case KindOfUninit: case KindOfNull: return 0.0; case KindOfBoolean: case KindOfInt64: return (double)toInt64(); case KindOfDouble: return m_data.dbl; case KindOfPersistentString: case KindOfString: return m_data.pstr->toDouble(); case KindOfPersistentVec: case KindOfVec: case KindOfPersistentDict: case KindOfDict: case KindOfPersistentKeyset: case KindOfKeyset: case KindOfPersistentArray: case KindOfArray: return (double)toInt64(); case KindOfObject: return m_data.pobj->toDouble(); case KindOfResource: return m_data.pres->data()->o_toDouble(); case KindOfRef: return m_data.pref->var()->toDouble(); case KindOfClass: break; } not_reached(); }
void GlobalsArray::OnSetEvalScalar(ArrayData*) { not_reached(); }
void c_AsyncGeneratorWaitHandle::t___construct() { // gen-ext-hhvm requires at least one declared method in the class to work not_reached(); }
std::string Scanner::escape(const char *str, int len, char quote_type) const { std::string output; output.reserve(len); if (quote_type == '\'') { for (int i = 0; i < len; i++) { unsigned char ch = str[i]; if (ch == '\\') { if (++i < len) { switch (str[i]) { case '\\': output += "\\"; break; case '\'': output += '\''; break; default: { output += ch; output += str[i]; break; } } } else { assert(false); output += ch; } } else { output += ch; } } } else { for (int i = 0; i < len; i++) { unsigned char ch = str[i]; if (ch == '\\') { if (++i < len) { switch (str[i]) { case 'n': output += '\n'; break; case 't': output += '\t'; break; case 'r': output += '\r'; break; case 'v': output += '\v'; break; case 'f': output += '\f'; break; case 'e': output += '\033'; break; case '\\': output += '\\'; break; case '$': output += '$'; break; case '"': case '`': if (str[i] != quote_type) { output += '\\'; } output += str[i]; break; case 'x': case 'X': { if (isxdigit(str[i+1])) { std::string shex; shex += str[++i]; // 0th hex digit if (isxdigit(str[i+1])) { shex += str[++i]; // 1st hex digit } output += strtol(shex.c_str(), nullptr, 16); } else { output += ch; output += str[i]; } break; } case 'u': { // Unicode escape sequence // "\u{123456}" if (str[i+1] != '{') { // BC for "\u1234" passthrough output += ch; output += str[i]; break; } bool valid = true; auto start = str + i + 2; auto closebrace = strchr(start, '}'); if (closebrace > start) { for (auto p = start; p < closebrace; ++p) { if (!isxdigit(*p)) { valid = false; break; } } } else { valid = false; } auto fatal = [this](const char *msg) { auto loc = getLocation(); return ParseTimeFatalException( loc->file, loc->r.line0, "%s", msg); }; if (!valid) { throw fatal("Invalid UTF-8 codepoint escape sequence"); } std::string codepoint(start, closebrace - start); char *end = nullptr; int32_t uchar = strtol(codepoint.c_str(), &end, 16); if ((end && *end) || (uchar > 0x10FFFF)) { throw fatal( "Invalid UTF-8 codepoint escape sequence: " "Codepoint too large"); } if (uchar <= 0x0007F) { output += (char)uchar; } else if (uchar <= 0x007FF) { output += (char)(0xC0 | ( uchar >> 6 )); output += (char)(0x80 | ( uchar & 0x3F)); } else if (uchar <= 0x00FFFF) { output += (char)(0xE0 | ( uchar >> 12 )); output += (char)(0x80 | ((uchar >> 6) & 0x3F)); output += (char)(0x80 | ( uchar & 0x3F)); } else if (uchar <= 0x10FFFF) { output += (char)(0xF0 | ( uchar >> 18 )); output += (char)(0x80 | ((uchar >> 12) & 0x3F)); output += (char)(0x80 | ((uchar >> 6) & 0x3F)); output += (char)(0x80 | ( uchar & 0x3F)); } else { not_reached(); assert(false); } i += codepoint.size() + 2 /* strlen("{}") */; break; }
void staticArrayStreamer(ArrayData* ad, std::ostream& out) { out << "array("; if (!ad->empty()) { bool comma = false; for (ArrayIter it(ad); !it.end(); it.next()) { if (comma) { out << ","; } else { comma = true; } Variant key = it.first(); // Key. if (IS_INT_TYPE(key.getType())) { out << *key.getInt64Data(); } else if (IS_STRING_TYPE(key.getType())) { out << "\"" << escapeStringForCPP(key.getStringData()->data(), key.getStringData()->size()) << "\""; } else { assert(false); } out << "=>"; Variant val = it.second(); // Value. [&] { switch (val.getType()) { case KindOfUninit: case KindOfNull: out << "null"; return; case KindOfBoolean: out << (val.toBoolean() ? "true" : "false"); return; case KindOfInt64: out << *val.getInt64Data(); return; case KindOfDouble: out << *val.getDoubleData(); return; case KindOfStaticString: case KindOfString: out << "\"" << escapeStringForCPP(val.getStringData()->data(), val.getStringData()->size()) << "\""; return; case KindOfArray: staticArrayStreamer(val.getArrayData(), out); return; case KindOfObject: case KindOfResource: case KindOfRef: case KindOfClass: not_reached(); } }(); } } out << ")"; }
size_t APCLocalArray::Vsize(const ArrayData*) { not_reached(); }
int immSize(PC origPC, int idx) { auto pc = origPC; auto const op = decode_op(pc); assert(idx >= 0 && idx < numImmediates(op)); always_assert(idx < 4); // No origPCs have more than four immediates static const int8_t argTypeToSizes[] = { #define ARGTYPE(nm, type) sizeof(type), #define ARGTYPEVEC(nm, type) 0, ARGTYPES #undef ARGTYPE #undef ARGTYPEVEC }; if (immType(op, idx) == IVA || immType(op, idx) == LA || immType(op, idx) == IA) { if (idx >= 1) pc += immSize(origPC, 0); if (idx >= 2) pc += immSize(origPC, 1); if (idx >= 3) pc += immSize(origPC, 2); return encoded_iva_size(decode_raw<uint8_t>(pc)); } if (immType(op, idx) == KA) { if (idx >= 1) pc += immSize(origPC, 0); if (idx >= 2) pc += immSize(origPC, 1); if (idx >= 3) pc += immSize(origPC, 2); switch (decode_raw<MemberCode>(pc)) { case MW: return 1; case MEL: case MPL: case MEC: case MPC: return 1 + encoded_iva_size(decode_raw<uint8_t>(pc)); case MEI: return 1 + sizeof(int64_t); case MET: case MPT: case MQT: return 1 + sizeof(Id); } not_reached(); } if (immType(op, idx) == RATA) { if (idx >= 1) pc += immSize(origPC, 0); if (idx >= 2) pc += immSize(origPC, 1); if (idx >= 3) pc += immSize(origPC, 2); return encodedRATSize(pc); } if (immIsVector(op, idx)) { if (idx >= 1) pc += immSize(origPC, 0); if (idx >= 2) pc += immSize(origPC, 1); if (idx >= 3) pc += immSize(origPC, 2); int vecElemSz; auto itype = immType(op, idx); if (itype == BLA) { vecElemSz = sizeof(Offset); } else if (itype == ILA) { vecElemSz = 2 * sizeof(uint32_t); } else if (itype == VSA) { vecElemSz = sizeof(Id); } else { assert(itype == SLA); vecElemSz = sizeof(StrVecItem); } return sizeof(int32_t) + vecElemSz * decode_raw<int32_t>(pc); } ArgType type = immType(op, idx); return (type >= 0) ? argTypeToSizes[type] : 0; }
bool APCLocalArray::AdvanceMArrayIter(ArrayData* ad, MArrayIter& fp) { not_reached(); // we should've escalated }
void APCLocalArray::OnSetEvalScalar(ArrayData*) { not_reached(); }
bool APCLocalArray::ValidMArrayIter(const ArrayData* ad, const MArrayIter& fp) { assert(fp.getContainer() == ad); not_reached(); // we should've escalated }
bool APCLocalArray::Uasort(ArrayData*, const Variant& cmp_function) { not_reached(); }
void APCLocalArray::Asort(ArrayData*, int sort_flags, bool ascending) { not_reached(); }
static Variant get_icu_display_value(const String &locale, const String &disp_locale, LocaleTag tag) { String locname(locale); if (tag != LOC_DISPLAY) { int ofs = getGrandfatheredOffset(locale); if (ofs >= 0) { if (tag == LOC_LANG) { locname = getGrandfatheredPreferred(ofs); } else { return false; } } } int32_t (*ulocfunc)(const char *loc, const char *dloc, UChar *dest, int32_t destcap, UErrorCode *err); switch (tag) { case LOC_LANG: ulocfunc = uloc_getDisplayLanguage; break; case LOC_SCRIPT: ulocfunc = uloc_getDisplayScript; break; case LOC_REGION: ulocfunc = uloc_getDisplayCountry; break; case LOC_VARIANT: ulocfunc = uloc_getDisplayVariant; break; case LOC_DISPLAY: ulocfunc = uloc_getDisplayName; break; default: assert(false); return false; } icu::UnicodeString buf; auto ubuf = buf.getBuffer(64); do { UErrorCode error = U_ZERO_ERROR; int32_t len = ulocfunc(locname.c_str(), disp_locale.c_str(), ubuf, buf.getCapacity(), &error); if (error != U_BUFFER_OVERFLOW_ERROR && error != U_STRING_NOT_TERMINATED_WARNING) { if (U_FAILURE(error)) { s_intl_error->setError(error, "locale_get_display_%s : unable to " "get locale %s", LocaleName(tag).c_str(), LocaleName(tag).c_str()); return false; } buf.releaseBuffer(len); error = U_ZERO_ERROR; String out(u8(buf, error)); if (U_FAILURE(error)) { s_intl_error->setError(error, "Unable to convert result from " "locale_get_display_%s to UTF-8", LocaleName(tag).c_str()); return false; } return out; } if (len <= buf.getCapacity()) { // Avoid infinite loop buf.releaseBuffer(0); s_intl_error->setError(U_INTERNAL_PROGRAM_ERROR, "Got invalid response from ICU"); return false; } // Grow the buffer to sufficient size buf.releaseBuffer(0); ubuf = buf.getBuffer(len); } while (true); not_reached(); return false; }
static Variant get_icu_value(const String &locale, LocaleTag tag, bool fromParseLocale = false) { String locale_name(locale); if (tag != LOC_CANONICALIZE) { if (getGrandfatheredOffset(locale) >= 0) { if (tag == LOC_LANG) { return locale; } return false; } if (fromParseLocale) { auto localecstr = locale.c_str(); if (tag == LOC_LANG && locale.size() > 1 && isIDPrefix(localecstr)) { return locale; } int pos = singleton_pos(locale); if (pos == 0) { return null_string; } else if (pos > 0) { locale_name = f_substr(locale, 0, pos - 1); } } } int32_t (*ulocfunc)(const char *loc, char *val, int32_t len, UErrorCode *err); switch (tag) { case LOC_SCRIPT: ulocfunc = uloc_getScript; break; case LOC_LANG: ulocfunc = uloc_getLanguage; break; case LOC_REGION: ulocfunc = uloc_getCountry; break; case LOC_VARIANT: ulocfunc = uloc_getVariant; break; case LOC_CANONICALIZE: ulocfunc = uloc_canonicalize; break; default: assert(false); return false; } String buf(64, ReserveString); do { UErrorCode error = U_ZERO_ERROR; int32_t len = ulocfunc(locale_name.c_str(), buf->mutableData(), buf->capacity(), &error); if (error != U_BUFFER_OVERFLOW_ERROR && error != U_STRING_NOT_TERMINATED_WARNING) { if (U_FAILURE(error)) { s_intl_error->setError(error, "unable to get locale info"); return false; } buf.setSize(len); return buf; } if (len <= buf->capacity()) { // Avoid infinite loop s_intl_error->setError(U_INTERNAL_PROGRAM_ERROR, "Got invalid response from ICU"); return false; } buf = String(len, ReserveString); } while (true); not_reached(); return false; }