bool operator== ( const Type& t1, const Type& t2) { SimpleType *st1, *st2; TableType *tt1, *tt2; TupletType *nt1, *nt2; if (t1->variability() != t2->variability()) return false; if (t1->computability() != t2->computability()) return false; if ( (st1 = isSimpleType(t1)) && (st2 = isSimpleType(t2)) ) return (st1->nature() == st2->nature()) && (st1->variability() == st2->variability()) && (st1->computability() == st2->computability()) && (st1->vectorability() == st2->vectorability()) && (st1->boolean() == st2->boolean()) && (st1->getInterval().lo == st2->getInterval().lo) && (st1->getInterval().hi == st2->getInterval().hi) && (st1->getInterval().valid == st2->getInterval().valid); if ( (tt1 = isTableType(t1)) && (tt2 = isTableType(t2)) ) return tt1->content()== tt2->content(); if ( (nt1 = isTupletType(t1)) && (nt2 = isTupletType(t2)) ) { int a1 = nt1->arity(); int a2 = nt2->arity(); if (a1 == a2) { for (int i=0; i<a1; i++) { if ((*nt1)[i] != (*nt2)[i]) return false; } return true; } else { return false; } } return false; }
Type operator| ( const Type& t1, const Type& t2) { SimpleType *st1, *st2; TableType *tt1, *tt2; TupletType *nt1, *nt2; if ( (st1 = isSimpleType(t1)) && (st2 = isSimpleType(t2)) ) { return makeSimpleType( st1->nature()|st2->nature(), st1->variability()|st2->variability(), st1->computability()|st2->computability(), st1->vectorability()|st2->vectorability(), st1->boolean()|st2->boolean(), reunion(st1->getInterval(), st2->getInterval()) ); } else if ( (tt1 = isTableType(t1)) && (tt2 = isTableType(t2)) ) { return makeTableType( tt1->content() | tt2->content() ); } else if ( (nt1 = isTupletType(t1)) && (nt2 = isTupletType(t2)) ) { vector<Type> v; int n = min(nt1->arity(), nt2->arity()); for (int i=0; i<n; i++) { v.push_back( (*nt1)[i] | (*nt2)[i]); } return new TupletType( v ); } else { stringstream error; error << "Error : trying to combine incompatible types, " << t1 << " and " << t2 << endl; throw faustexception(error.str()); } }
/** * codeAudioType(Type) -> Tree * Code an audio type as a tree in order to benefit of memoization * The type field (of the coded type) is used to store the audio * type */ Tree codeAudioType(AudioType* t) { SimpleType *st; TableType *tt; TupletType *nt; Tree r; if ((r=t->getCode())) return r; if ((st = isSimpleType(t))) { r = codeSimpleType(st); } else if ((tt = isTableType(t))) { r = codeTableType(tt); } else if ((nt = isTupletType(t))) { r = codeTupletType(nt); } else { stringstream error; error << "ERROR in codeAudioType() : invalide pointer " << t << endl; throw faustexception(error.str()); } r->setType(t); return r; }
Type checkInt(Type t) { // verifie que t est entier SimpleType* st = isSimpleType(t); if (st == 0 || st->nature() > kInt) { stringstream error; error << "Error : checkInt failed for type " << t << endl; throw faustexception(error.str()); } return t; }
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 isSimpleType(const mongo::BSONElement &elem) { return isSimpleType(elem.type()); }