@@ -2034,34 +2034,46 @@ void RecordThreadState::enqueue_host_func(void (*callback)(void *),
20342034 (void ) callback; (void ) payload;
20352035}
20362036
2037- void Recording::validate () {
2037+ void Recording::validate (uint32_t scope ) {
20382038 for (uint32_t i = 0 ; i < recorded_variables.size (); i++) {
20392039 RecordedVariable &rv = recorded_variables[i];
20402040 if (rv.state == RecordedVarState::Uninitialized) {
20412041 Operation &last_op = operations[rv.last_op ];
20422042#ifndef NDEBUG
2043+ uint32_t index = 0 ;
2044+ const char *scope_string = " before" ;
2045+ auto it = state.ptr_to_variable .find (rv.ptr );
2046+ if (it != state.ptr_to_variable .end ()) {
2047+ index = it->second ;
2048+ Variable *var = jitc_var (index);
2049+ if (var->scope >= scope)
2050+ scope_string = " inside" ;
2051+ }
20432052 if (last_op.type == OpType::Aggregate) {
20442053 jitc_raise (
20452054 " validate(): The frozen function included a virtual "
2046- " function call involving variable s%u <%p>, last used by "
2047- " operation o%u. Dr.Jit would normally traverse a registry "
2048- " of all relevant object instances in order to collect "
2049- " their member variables. However, when recording this "
2050- " frozen function, this traversal was skipped because no "
2051- " such object instance was found in the function's inputs. "
2052- " You can trigger traversal by including the relevant "
2053- " objects in the function input, or by specifying them "
2054- " using the state_fn argument. Alternatively, this error "
2055- " might be caused by a nested "
2055+ " function call involving Variable r%u at slot s%u <%p>"
2056+ " which created %s the frozen function and was last used by "
2057+ " operation o%u. Dr.Jit would "
2058+ " normally traverse a registry of all relevant object "
2059+ " instances in order to collect their member variables. "
2060+ " However, when recording this frozen function, this "
2061+ " traversal was skipped because no such object instance was "
2062+ " found in the function's inputs. You can trigger traversal "
2063+ " by including the relevant objects in the function input, "
2064+ " or by specifying them using the state_fn argument. "
2065+ " Alternatively, this error might be caused by a nested "
20562066 " virtual function call." ,
2057- i, rv.ptr , rv.last_op );
2067+ index, i, rv.ptr , scope_string , rv.last_op );
20582068 } else
20592069 jitc_raise (
2060- " validate(): Variable at slot s%u <%p> was used by %s operation "
2061- " o%u but left in an uninitialized state! This indicates "
2062- " that the associated variable was used, but not traversed "
2063- " as part of the frozen function input." ,
2064- i, rv.ptr , op_type_name[(uint32_t ) last_op.type ], rv.last_op );
2070+ " validate(): Variable r%u at slot s%u <%p> which was "
2071+ " created %s the frozen function and was last used by %s "
2072+ " operation o%u but left in an uninitialized state! This "
2073+ " indicates that the associated variable was used, but not "
2074+ " traversed as part of the frozen function input." ,
2075+ index, i, rv.ptr , scope_string,
2076+ op_type_name[(uint32_t ) last_op.type ], rv.last_op );
20652077#else
20662078 if (last_op.type == OpType::Aggregate) {
20672079 jitc_raise (
@@ -2301,14 +2313,29 @@ void RecordThreadState::add_param(AccessInfo info) {
23012313 jitc_log (LogLevel::Debug, " -> param s%u" , info.slot );
23022314
23032315 RecordedVariable &rv = m_recording.recorded_variables [info.slot ];
2304- if (info.test_uninit && rv.state == RecordedVarState::Uninitialized)
2316+ if (info.test_uninit && rv.state == RecordedVarState::Uninitialized){
2317+ #ifndef NDEBUG
2318+ uint32_t index = 0 ;
2319+ auto it = state.ptr_to_variable .find (rv.ptr );
2320+ if (it != state.ptr_to_variable .end ())
2321+ index = it->second ;
2322+ jitc_raise (" record(): Variable r%u at slot s%u was read by "
2323+ " operation o%u, but it had not yet been initialized! "
2324+ " This can occur if the variable was not part of "
2325+ " the input but is used by a recorded operation, for "
2326+ " example if it was not specified as a member in a "
2327+ " DRJIT_STRUCT but used in the frozen function." ,
2328+ index, info.slot , (uint32_t ) m_recording.operations .size ());
2329+ #else
23052330 jitc_raise (" record(): Variable at slot s%u was read by "
23062331 " operation o%u, but it had not yet been initialized! "
23072332 " This can occur if the variable was not part of "
23082333 " the input but is used by a recorded operation, for "
23092334 " example if it was not specified as a member in a "
23102335 " DRJIT_STRUCT but used in the frozen function." ,
23112336 info.slot , (uint32_t ) m_recording.operations .size ());
2337+ #endif
2338+ }
23122339
23132340 if (info.vtype == VarType::Void)
23142341 info.vtype = rv.type ;
@@ -2544,6 +2571,7 @@ Recording *jitc_freeze_stop(JitBackend backend, const uint32_t *outputs,
25442571 dynamic_cast <RecordThreadState *>(thread_state (backend));
25452572 rts != nullptr ) {
25462573 ThreadState *internal = rts->m_internal ;
2574+ uint32_t scope = internal->scope ;
25472575
25482576 // Perform reassignments to internal thread-state of possibly changed
25492577 // variables
@@ -2571,7 +2599,7 @@ Recording *jitc_freeze_stop(JitBackend backend, const uint32_t *outputs,
25712599 }
25722600 Recording *recording = new Recording (std::move (rts->m_recording ));
25732601 try {
2574- recording->validate ();
2602+ recording->validate (scope );
25752603 } catch (const std::exception &) {
25762604 recording->destroy ();
25772605 throw ;
0 commit comments