| 293 | return Visitor::visit(block); |
| 294 | } |
| 295 | virtual VariablePtr visitLet ( ExprLet * expr, const VariablePtr & var, bool last ) override { |
| 296 | if ( var->does_not_escape && !blocks.empty() ) { |
| 297 | // put the pointee in the stack frame instead of the heap; idempotent so the |
| 298 | // notInferred re-infer loop terminates once the flag is already set |
| 299 | if ( forceStack && setAllocateOnStack(var->init) ) { |
| 300 | anyWork = true; |
| 301 | func->notInferred(); |
| 302 | } |
| 303 | // emit the scope-free only when it frees something real: a heap shell (not stack- |
| 304 | // allocated) or owned heap members (arrays/tables) inside the pointee. a stack- |
| 305 | // allocated POD frees nothing, so skip it - else every scope pays an interop call. |
| 306 | bool stacked = forceStack && initIsAllocatedOnStack(var->init); |
| 307 | bool ownsHeap = !( var->type->firstType && var->type->firstType->isNoHeapType() ); |
| 308 | if ( !stacked || ownsHeap ) { |
| 309 | pending.push_back({var, blocks.back()}); |
| 310 | } |
| 311 | } |
| 312 | return Visitor::visitLet(expr,var,last); |
| 313 | } |
| 314 | void emitScopeFree ( ExprBlock * block, Variable * var ) { |
| 315 | if ( var->type->firstType->getSizeOf64() > 0x7fffffffull ) return; // skip pointees over the 2^31 (32-bit) size limit - oversized/invalid types that error out anyway |
| 316 | anyWork = true; |
nothing calls this directly
no test coverage detected