set the stack-allocation flag on the fresh-alloc init expression; returns true if it changed it. only the shapes the codegen tiers can stack-allocate: a plain `new T()` (no initializer call, no dim) over a plain struct, and `new T(f=v)` which lowers to an ascend over a make-struct. capped by size. classes / constructors / handles are excluded: their construction has semantics (ctor invocation, rtt
| 224 | // capped by size. classes / constructors / handles are excluded: their construction has semantics |
| 225 | // (ctor invocation, rtti) that the plain in-frame build does not reproduce (breaks under JIT). |
| 226 | static bool setAllocateOnStack ( Expression * init ) { |
| 227 | if ( init && init->rtti_isNewExpr() ) { |
| 228 | auto en = (ExprNew *) init; |
| 229 | auto st = en->typeexpr ? en->typeexpr->structType : nullptr; |
| 230 | bool persistent = st && st->persistent; |
| 231 | bool isClass = st && st->isClass; |
| 232 | // use the non-asserting 64-bit size: a malformed/oversized type (e.g. in invalid_types.das) |
| 233 | // yields a huge value that simply fails the cap, instead of tripping the size<=0x7fffffff assert |
| 234 | bool fits = en->typeexpr && en->typeexpr->getBaseSizeOf64() <= uint64_t(MAX_STACK_ALLOC_SIZE); |
| 235 | if ( !en->initializer && en->typeexpr && en->typeexpr->dim.empty() && !persistent && !isClass && fits && !en->allocate_on_stack ) { |
| 236 | en->allocate_on_stack = true; return true; |
| 237 | } |
| 238 | } else if ( init && init->rtti_isAscend() ) { |
| 239 | auto ea = (ExprAscend *) init; |
| 240 | bool plainStruct = false; |
| 241 | if ( ea->subexpr && ea->subexpr->rtti_isMakeStruct() ) { |
| 242 | auto mks = (ExprMakeStruct *) ea->subexpr; |
| 243 | auto st = mks->makeType ? mks->makeType->structType : nullptr; |
| 244 | // note: isNewClass means "make-struct produced by a `new`" (set for plain structs too), |
| 245 | // NOT "is a class" - the class signal is the constructor / forceClass / structType->isClass |
| 246 | plainStruct = !mks->constructor && !mks->isNewHandle |
| 247 | && !mks->forceClass && !( st && st->isClass ); |
| 248 | } |
| 249 | bool persistent = ea->subexpr && ea->subexpr->type && ea->subexpr->type->structType |
| 250 | && ea->subexpr->type->structType->persistent; |
| 251 | bool fits = ea->subexpr && ea->subexpr->type && ea->subexpr->type->getSizeOf64() <= uint64_t(MAX_STACK_ALLOC_SIZE); |
| 252 | if ( plainStruct && !persistent && fits && !ea->allocate_on_stack ) { |
| 253 | ea->allocate_on_stack = true; return true; |
| 254 | } |
| 255 | } |
| 256 | return false; |
| 257 | } |
| 258 | |
| 259 | static bool initIsAllocatedOnStack ( Expression * init ) { |
| 260 | if ( init && init->rtti_isNewExpr() ) return ((ExprNew *)init)->allocate_on_stack; |
no test coverage detected