| 299 | } |
| 300 | } |
| 301 | uint32_t getSideEffects ( const FunctionPtr & fnc ) { |
| 302 | if ( fnc->stub || fnc->isTemplate || fnc->builtIn || fnc->knownSideEffects ) { |
| 303 | return fnc->sideEffectFlags; |
| 304 | } |
| 305 | if ( asked.find(fnc)!=asked.end() ) { |
| 306 | return fnc->sideEffectFlags; // assume no extra side effects |
| 307 | } |
| 308 | asked.insert(fnc); |
| 309 | auto sfn = func; |
| 310 | func = fnc; |
| 311 | fnc->visit(*this); |
| 312 | TrackVariableFlags vaf; |
| 313 | fnc->visit(vaf); |
| 314 | func = sfn; |
| 315 | // now, for the side-effects |
| 316 | uint32_t flags = fnc->sideEffectFlags; |
| 317 | if (fnc->useGlobalVariables.size()) { |
| 318 | flags |= uint32_t(SideEffects::accessGlobal); |
| 319 | } |
| 320 | // it has side effects, if it writes to its arguments |
| 321 | for ( auto & arg : fnc->arguments ) { |
| 322 | if ( arg->access_ref ) { |
| 323 | flags |= uint32_t(SideEffects::modifyArgument); |
| 324 | } |
| 325 | } |
| 326 | // string capture |
| 327 | // if it calls string capture, it captures string, or has string builder at all |
| 328 | // note - having string builder is there because we git rid of temp string in the string builder. if we had better place to put it, we could get rid of this |
| 329 | if ( fnc->callCaptureString || fnc->captureString || fnc->hasStringBuilder ) { |
| 330 | flags |= uint32_t(SideEffects::captureString); |
| 331 | } |
| 332 | // it captures strings if it touches globals with strings |
| 333 | if ( !(flags & uint32_t(SideEffects::captureString)) ) { |
| 334 | for ( auto & gv : fnc->useGlobalVariables ) { |
| 335 | if ( !gv->type->constant && gv->type->hasStringData() ) { |
| 336 | flags |= uint32_t(SideEffects::captureString); |
| 337 | break; |
| 338 | } |
| 339 | } |
| 340 | } |
| 341 | // it captures strings if it returns a string |
| 342 | if ( !(flags & uint32_t(SideEffects::captureString)) ) { |
| 343 | if ( fnc->result->hasStringData() ) { |
| 344 | flags |= uint32_t(SideEffects::captureString); |
| 345 | } |
| 346 | } |
| 347 | // it captures strings if it writes to an argument, that is a string |
| 348 | if ( !(flags & uint32_t(SideEffects::captureString)) ) { |
| 349 | for ( auto & arg : fnc->arguments ) { |
| 350 | if ( !arg->type->constant && arg->access_ref ) { |
| 351 | if ( arg->type->ref && arg->type->isString() ) { // string &, otherwise we can write but its not a capture |
| 352 | flags |= uint32_t(SideEffects::captureString); |
| 353 | break; |
| 354 | } else if ( arg->type->hasStringData() ) { // [[ string ]] |
| 355 | flags |= uint32_t(SideEffects::captureString); |
| 356 | break; |
| 357 | } |
| 358 | } |