Fix thread safety issue for flushing variable scopes

There was a race condition when flushing the variable scope, because
another thread might already see isolated set to true, before the heap
locals were properly initialized.

This result in this other thread seeing nil as the local value instead
of the proper value. This commit changes the flushing strategy to be
both safe for reads and writes of the locals.

The first step is to delay the allocation of the heap locals tuple. We
then atomically indicate that this scope uses heap locals. If any other
thread also wants to use the scope, it will spin until the heap locals
have been allocated. Spinning for both the read and write ensures that
we don't see any intermediate state during the move from stack to heap
locals. This means no writes are lost and no stale reads occur.

We then create the heap locals and only store then in the heap_locals_
ivar after initializing them, so any reads or writes will see the proper
locals and write to the correct slots.

Fixes #2124