void storeTV(Vout& v, Vptr dst, Vloc srcLoc, const SSATmp* src) { auto const type = src->type(); if (srcLoc.isFullSIMD()) { // The whole TV is stored in a single SIMD reg. assertx(RuntimeOption::EvalHHIRAllocSIMDRegs); v << storeups{srcLoc.reg(), dst}; return; } if (type.needsReg()) { assertx(srcLoc.hasReg(1)); v << storeb{srcLoc.reg(1), dst + TVOFF(m_type)}; } else { v << storeb{v.cns(type.toDataType()), dst + TVOFF(m_type)}; } // We ignore the values of statically nullish types. if (src->isA(TNull) || src->isA(TNullptr)) return; // Store the value. if (src->hasConstVal()) { // Skip potential zero-extend if we know the value. v << store{v.cns(src->rawVal()), dst + TVOFF(m_data)}; } else { assertx(srcLoc.hasReg(0)); auto const extended = zeroExtendIfBool(v, src->type(), srcLoc.reg(0)); v << store{extended, dst + TVOFF(m_data)}; } }
void IRTranslator::translateLtGtOp(const NormalizedInstruction& i) { auto const op = i.op(); assert(op == Op::Lt || op == Op::Lte || op == Op::Gt || op == Op::Gte); auto leftType = m_hhbcTrans.topType(1, DataTypeGeneric); auto rightType = m_hhbcTrans.topType(0, DataTypeGeneric); bool ok = equivDataTypes(leftType.toDataType(), rightType.toDataType()) && leftType.subtypeOfAny(Type::Null, Type::Bool, Type::Int); HHIR_UNIMPLEMENTED_WHEN(!ok, LtGtOp); switch (op) { case Op::Lt : HHIR_EMIT(Lt); case Op::Lte : HHIR_EMIT(Lte); case Op::Gt : HHIR_EMIT(Gt); case Op::Gte : HHIR_EMIT(Gte); default : HHIR_UNIMPLEMENTED(LtGtOp); } }
RuntimeType Type::toRuntimeType() const { assert(!isPtr()); auto const outer = isBoxed() ? KindOfRef : toDataType(); auto const inner = isBoxed() ? innerType().toDataType() : KindOfNone; auto rtt = RuntimeType{outer, inner}; if (isSpecialized()) { if (subtypeOf(Type::Arr)) { return rtt.setArrayKind(getArrayKind()); } else if (subtypeOf(Type::Obj)) { return rtt.setKnownClass(getClass()); } } return rtt; }
void cgCallBuiltin(IRLS& env, const IRInstruction* inst) { auto const extra = inst->extra<CallBuiltin>(); auto const callee = extra->callee; auto const returnType = inst->typeParam(); auto const funcReturnType = callee->returnType(); auto const returnByValue = callee->isReturnByValue(); auto const dstData = dstLoc(env, inst, 0).reg(0); auto const dstType = dstLoc(env, inst, 0).reg(1); auto& v = vmain(env); // Whether `t' is passed in/out of C++ as String&/Array&/Object&. auto const isReqPtrRef = [] (MaybeDataType t) { return isStringType(t) || isArrayLikeType(t) || t == KindOfObject || t == KindOfResource; }; if (FixupMap::eagerRecord(callee)) { auto const sp = srcLoc(env, inst, 1).reg(); auto const spOffset = cellsToBytes(extra->spOffset.offset); auto const& marker = inst->marker(); auto const pc = marker.fixupSk().unit()->entry() + marker.fixupBcOff(); auto const synced_sp = v.makeReg(); v << lea{sp[spOffset], synced_sp}; emitEagerSyncPoint(v, pc, rvmtl(), srcLoc(env, inst, 0).reg(), synced_sp); } int returnOffset = rds::kVmMInstrStateOff + offsetof(MInstrState, tvBuiltinReturn); auto args = argGroup(env, inst); if (!returnByValue) { if (isBuiltinByRef(funcReturnType)) { if (isReqPtrRef(funcReturnType)) { returnOffset += TVOFF(m_data); } // Pass the address of tvBuiltinReturn to the native function as the // location where it can construct the return Array, String, Object, or // Variant. args.addr(rvmtl(), returnOffset); args.indirect(); } } // The srcs past the first two (sp and fp) are the arguments to the callee. auto srcNum = uint32_t{2}; // Add the this_ or self_ argument for HNI builtins. if (callee->isMethod()) { if (callee->isStatic()) { args.ssa(srcNum); ++srcNum; } else { // Note that we don't support objects with vtables here (if they may need // a $this pointer adjustment). This should be filtered out during irgen // or before. args.ssa(srcNum); ++srcNum; } } // Add the func_num_args() value if needed. if (callee->attrs() & AttrNumArgs) { // If `numNonDefault' is negative, this is passed as an src. if (extra->numNonDefault >= 0) { args.imm((int64_t)extra->numNonDefault); } else { args.ssa(srcNum); ++srcNum; } } // Add the positional arguments. for (uint32_t i = 0; i < callee->numParams(); ++i, ++srcNum) { auto const& pi = callee->params()[i]; // Non-pointer and NativeArg args are passed by value. String, Array, // Object, and Variant are passed by const&, i.e. a pointer to stack memory // holding the value, so we expect PtrToT types for these. Pointers to // req::ptr types (String, Array, Object) need adjusting to point to // &ptr->m_data. if (TVOFF(m_data) && !pi.nativeArg && isReqPtrRef(pi.builtinType)) { assertx(inst->src(srcNum)->type() <= TPtrToGen); args.addr(srcLoc(env, inst, srcNum).reg(), TVOFF(m_data)); } else if (pi.nativeArg && !pi.builtinType && !callee->byRef(i)) { // This condition indicates a MixedTV (i.e., TypedValue-by-value) arg. args.typedValue(srcNum); } else { args.ssa(srcNum, pi.builtinType == KindOfDouble); } } auto dest = [&] () -> CallDest { if (isBuiltinByRef(funcReturnType)) { if (!returnByValue) return kVoidDest; // indirect return return funcReturnType ? callDest(dstData) // String, Array, or Object : callDest(dstData, dstType); // Variant } return funcReturnType == KindOfDouble ? callDestDbl(env, inst) : callDest(env, inst); }(); cgCallHelper(v, env, CallSpec::direct(callee->nativeFuncPtr()), dest, SyncOptions::Sync, args); // For primitive return types (int, bool, double) and returnByValue, the // return value is already in dstData/dstType. if (returnType.isSimpleType() || returnByValue) return; // For return by reference (String, Object, Array, Variant), the builtin // writes the return value into MInstrState::tvBuiltinReturn, from where it // has to be tested and copied. if (returnType.isReferenceType()) { // The return type is String, Array, or Object; fold nullptr to KindOfNull. assertx(isBuiltinByRef(funcReturnType) && isReqPtrRef(funcReturnType)); v << load{rvmtl()[returnOffset], dstData}; if (dstType.isValid()) { auto const sf = v.makeReg(); auto const rtype = v.cns(returnType.toDataType()); auto const nulltype = v.cns(KindOfNull); v << testq{dstData, dstData, sf}; v << cmovb{CC_Z, sf, rtype, nulltype, dstType}; } return; } if (returnType <= TCell || returnType <= TBoxedCell) { // The return type is Variant; fold KindOfUninit to KindOfNull. assertx(isBuiltinByRef(funcReturnType) && !isReqPtrRef(funcReturnType)); static_assert(KindOfUninit == 0, "KindOfUninit must be 0 for test"); v << load{rvmtl()[returnOffset + TVOFF(m_data)], dstData}; if (dstType.isValid()) { auto const rtype = v.makeReg(); v << loadb{rvmtl()[returnOffset + TVOFF(m_type)], rtype}; auto const sf = v.makeReg(); auto const nulltype = v.cns(KindOfNull); v << testb{rtype, rtype, sf}; v << cmovb{CC_Z, sf, rtype, nulltype, dstType}; } return; } not_reached(); }
bool VOCatalogHeaderParser::startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &attributes) { if (qName == "TABLEDATA") { m_tableData++; m_desc = true; } if (qName == "RESOURCE") { m_resource++; for (int i = 0; i < attributes.count(); i++) { if (attributes.qName(i) == "name") { m_current.m_name = attributes.value(i); } else if (attributes.qName(i) == "ID") { m_current.m_id = attributes.value(i); } /* else if (attributes.qName(i) == "type") { m_current.m_type = attributes.value(i); } */ } } if (m_resource) { if (qName == "DESCRIPTION" && m_queue.last() == "RESOURCE") { m_desc = true; } if (qName == "TABLE") { m_table++; for (int i = 0; i < attributes.count(); i++) { if (attributes.qName(i) == "nrows") { m_current.m_count = attributes.value(i).toLongLong(); } } } if (m_table) { if (qName == "COOSYS") { VOCooSys coo; for (int i = 0; i < attributes.count(); i++) { if (attributes.qName(i) == "ID") { coo.m_id = attributes.value(i); } else if (attributes.qName(i) == "system") { coo.m_system = attributes.value(i); } else if (attributes.qName(i) == "equinox") { coo.m_equinox = attributes.value(i); } else if (attributes.qName(i) == "epoch") { coo.m_epoch = attributes.value(i).toDouble(); } } m_cooSys.append(coo); } if (qName == "FIELD") { m_field.clear(); for (int i = 0; i < attributes.count(); i++) { if (attributes.qName(i) == "name") { m_field.m_name = attributes.value(i); } else if (attributes.qName(i) == "ucd") { m_field.m_ucd = attributes.value(i); } else if (attributes.qName(i) == "ref") { m_field.m_ref = attributes.value(i); } else if (attributes.qName(i) == "display") { m_field.m_display = attributes.value(i).toInt(); } else if (attributes.qName(i) == "datatype") { m_field.m_dataType = toDataType(attributes.value(i)); } else if (attributes.qName(i) == "unit") { m_field.m_unit = attributes.value(i); } else if (attributes.qName(i) == "width") { m_field.m_width = attributes.value(i).toInt(); } else if (attributes.qName(i) == "precision") { m_field.m_precision = attributes.value(i).toInt(); } else if (attributes.qName(i) == "arraysize") { m_field.m_arraysize = attributes.value(i).toInt(); } } m_desc = true; } } } m_queue.append(qName); return true; }