@@ -828,8 +828,8 @@ static SEXP deoptSentinelContainer = []() {
828828 return store;
829829}();
830830
831- void deoptImpl (rir::Code* c, SEXP cls, DeoptMetadata* m, R_bcstack_t* args,
832- bool leakedEnv, DeoptReason* deoptReason, SEXP deoptTrigger) {
831+ SEXP deopt (rir::Code* c, SEXP cls, DeoptMetadata* m, R_bcstack_t* args,
832+ bool leakedEnv, DeoptReason* deoptReason, SEXP deoptTrigger) {
833833 deoptReason->record (deoptTrigger);
834834
835835 assert (m->numFrames >= 1 );
@@ -854,8 +854,9 @@ void deoptImpl(rir::Code* c, SEXP cls, DeoptMetadata* m, R_bcstack_t* args,
854854 auto le = LazyEnvironment::check (env);
855855 if (deoptless && m->numFrames == 1 && cls != deoptlessRecursion &&
856856 ((le && !le->materialized ()) ||
857- (!le && (!leakedEnv || !deoptlessNoLeakedEnvs)))) {
858- assert (m->frames [0 ].inPromise == false );
857+ (!le && (!leakedEnv || !deoptlessNoLeakedEnvs))) &&
858+ /* TODO: support deoptless when outermost frame is a promise */
859+ !m->frames [0 ].inPromise ) {
859860
860861 size_t envSize = le ? le->nargs : Rf_length (FRAME (env));
861862 if (envSize <= DeoptContext::MAX_ENV &&
@@ -932,8 +933,8 @@ void deoptImpl(rir::Code* c, SEXP cls, DeoptMetadata* m, R_bcstack_t* args,
932933
933934 Rf_findcontext (CTXT_BROWSER | CTXT_FUNCTION,
934935 originalCntxt->cloenv , res);
935- assert (false );
936- return ;
936+ assert (false && " unreachable after deoptless " );
937+ return nullptr ;
937938 }
938939 }
939940 }
@@ -945,13 +946,35 @@ void deoptImpl(rir::Code* c, SEXP cls, DeoptMetadata* m, R_bcstack_t* args,
945946 if (f->body () == c)
946947 Pool::patch (idx, deoptSentinelContainer);
947948
948- CallContext call (ArglistOrder::NOT_REORDERED, c, cls,
949- /* nargs */ -1 , src_pool_at (c->src ), args,
950- (Immediate*)nullptr , env, R_NilValue, Context ());
949+ if (cls) {
950+ CallContext call (ArglistOrder::NOT_REORDERED, c, cls,
951+ /* nargs */ -1 , src_pool_at (c->src ), args,
952+ (Immediate*)nullptr , env, R_NilValue, Context ());
951953
952- deoptFramesWithContext (&call, m, R_NilValue, m->numFrames - 1 , stackHeight,
953- (RCNTXT*)R_GlobalContext);
954- assert (false );
954+ // Deopt in a function longjumps to its context
955+ deoptFramesWithContext (&call, m, R_NilValue, m->numFrames - 1 ,
956+ stackHeight, (RCNTXT*)R_GlobalContext);
957+ assert (false && " unreachable after deopt" );
958+ return nullptr ;
959+ } else {
960+ // Deopt in a promise has nowhere to longjump, so it leaves the result
961+ // on the TOS and returns here, this is immediately returned as the
962+ // result of the promise
963+ deoptFramesWithContext (nullptr , m, R_NilValue, m->numFrames - 1 ,
964+ stackHeight, (RCNTXT*)R_GlobalContext);
965+ return ostack_pop ();
966+ }
967+ }
968+
969+ void deoptImpl (rir::Code* c, SEXP cls, DeoptMetadata* m, R_bcstack_t* args,
970+ bool leakedEnv, DeoptReason* deoptReason, SEXP deoptTrigger) {
971+ deopt (c, cls, m, args, leakedEnv, deoptReason, deoptTrigger);
972+ }
973+
974+ SEXP deoptPromImpl (rir::Code* c, DeoptMetadata* m, R_bcstack_t* args,
975+ bool leakedEnv, DeoptReason* deoptReason,
976+ SEXP deoptTrigger) {
977+ return deopt (c, nullptr , m, args, leakedEnv, deoptReason, deoptTrigger);
955978}
956979
957980void recordTypefeedbackImpl (Opcode* pos, rir::Code* code, SEXP value) {
@@ -2437,6 +2460,14 @@ void NativeBuiltins::initializeBuiltins() {
24372460 t::DeoptReasonPtr, t::SEXP},
24382461 false ),
24392462 {llvm::Attribute::NoReturn}};
2463+ get_ (Id::deoptProm) = {
2464+ " deoptProm" ,
2465+ (void *)&deoptPromImpl,
2466+ llvm::FunctionType::get (t::SEXP,
2467+ {t::voidPtr, t::voidPtr, t::stackCellPtr, t::i1,
2468+ t::DeoptReasonPtr, t::SEXP},
2469+ false ),
2470+ {}};
24402471 get_ (Id::assertFail) = {" assertFail" ,
24412472 (void *)&assertFailImpl,
24422473 t::void_voidPtr,
0 commit comments