void flush( const std::string& name ) const { getPromise( name ).flush(); }
void reset( const std::string& name ) const { getPromise( name ).reset(); }
void CodeVerifier::verifyFunctionLayout(SEXP sexp, InterpreterInstance* ctx) { if (TYPEOF(sexp) != EXTERNALSXP) Rf_error("RIR Verifier: Invalid SEXPTYPE"); Function* f = Function::unpack(sexp); // get the code objects std::vector<Code*> objs; objs.push_back(f->body()); for (size_t i = 0; i < f->numArgs; ++i) if (f->defaultArg(i)) objs.push_back(f->defaultArg(i)); if (f->size > XLENGTH(sexp)) Rf_error("RIR Verifier: Reported size must be smaller than the size of " "the vector"); // check that the call instruction has proper arguments and number of // instructions is valid while (!objs.empty()) { auto c = objs.back(); objs.pop_back(); if (c->info.magic != CODE_MAGIC) Rf_error("RIR Verifier: Invalid code magic number"); if (c->src == 0) Rf_error("RIR Verifier: Code must have AST"); unsigned oldo = c->stackLength; calculateAndVerifyStack(c); if (oldo != c->stackLength) Rf_error("RIR Verifier: Invalid stack layout reported"); if (((uintptr_t)(c + 1) + pad4(c->codeSize) + c->srcLength * sizeof(Code::SrclistEntry)) == 0) Rf_error("RIR Verifier: Invalid code length reported"); Opcode* cptr = c->code(); Opcode* start = cptr; Opcode* end = start + c->codeSize; while (true) { if (cptr > end) Rf_error("RIR Verifier: Bytecode overflow"); BC cur = BC::decode(cptr, c); switch (hasSources(cur.bc)) { case Sources::Required: if (c->getSrcIdxAt(cptr, true) == 0) Rf_error("RIR Verifier: Source required but not found"); break; case Sources::NotNeeded: if (c->getSrcIdxAt(cptr, true) != 0) Rf_error("RIR Verifier: Sources not needed but stored"); break; case Sources::May: { } } if (*cptr == Opcode::br_ || *cptr == Opcode::brobj_ || *cptr == Opcode::brtrue_ || *cptr == Opcode::brfalse_) { int off = *reinterpret_cast<int*>(cptr + 1); if (cptr + cur.size() + off < start || cptr + cur.size() + off > end) Rf_error("RIR Verifier: Branch outside closure"); } if (*cptr == Opcode::ldvar_) { unsigned* argsIndex = reinterpret_cast<Immediate*>(cptr + 1); if (*argsIndex >= cp_pool_length(ctx)) Rf_error("RIR Verifier: Invalid arglist index"); SEXP sym = cp_pool_at(ctx, *argsIndex); if (TYPEOF(sym) != SYMSXP) Rf_error("RIR Verifier: LdVar binding not a symbol"); if (!(strlen(CHAR(PRINTNAME(sym))))) Rf_error("RIR Verifier: LdVar empty binding name"); } if (*cptr == Opcode::promise_) { unsigned* promidx = reinterpret_cast<Immediate*>(cptr + 1); objs.push_back(c->getPromise(*promidx)); } if (*cptr == Opcode::ldarg_) { unsigned idx = *reinterpret_cast<Immediate*>(cptr + 1); if (idx >= MAX_ARG_IDX) Rf_error("RIR Verifier: Loading out of index argument"); } if (*cptr == Opcode::call_implicit_ || *cptr == Opcode::named_call_implicit_) { uint32_t nargs = *reinterpret_cast<Immediate*>(cptr + 1); for (size_t i = 0, e = nargs; i != e; ++i) { uint32_t offset = cur.callExtra().immediateCallArguments[i]; if (offset == MISSING_ARG_IDX || offset == DOTS_ARG_IDX) continue; objs.push_back(c->getPromise(offset)); } if (*cptr == Opcode::named_call_implicit_) { for (size_t i = 0, e = nargs; i != e; ++i) { uint32_t offset = cur.callExtra().callArgumentNames[i]; if (offset) { SEXP name = cp_pool_at(ctx, offset); if (TYPEOF(name) != SYMSXP && name != R_NilValue) Rf_error("RIR Verifier: Calling target not a " "symbol"); } } } } if (*cptr == Opcode::named_call_) { uint32_t nargs = *reinterpret_cast<Immediate*>(cptr + 1); for (size_t i = 0, e = nargs; i != e; ++i) { uint32_t offset = cur.callExtra().callArgumentNames[i]; if (offset) { SEXP name = cp_pool_at(ctx, offset); if (TYPEOF(name) != SYMSXP && name != R_NilValue) Rf_error( "RIR Verifier: Calling target not a symbol"); } } } if (*cptr == Opcode::mk_env_ || *cptr == Opcode::mk_stub_env_) { uint32_t nargs = *reinterpret_cast<Immediate*>(cptr + 1); for (size_t i = 0, e = nargs; i != e; ++i) { uint32_t offset = cur.mkEnvExtra().names[i]; SEXP name = cp_pool_at(ctx, offset); if (TYPEOF(name) != SYMSXP) Rf_error( "RIR Verifier: environment argument not a symbol"); } } cptr += cur.size(); if (cptr == start + c->codeSize) { if (!(cur.isJmp() && cur.immediate.offset < 0) && !(cur.isExit())) Rf_error("RIR Verifier: Last opcode should jump backwards " "or exit"); break; } } } }