]> git.vpit.fr Git - perl/modules/Scope-Upper.git/blobdiff - Upper.xs
Add braces around a condition block
[perl/modules/Scope-Upper.git] / Upper.xs
index afab7cc45defc9802a2e8d40532fdb67a5aa5e4a..c2036cce24e91c10f65fee5a780693e95f5cbcb0 100644 (file)
--- a/Upper.xs
+++ b/Upper.xs
@@ -1131,9 +1131,21 @@ static I32 su_init(pTHX_ void *ud, I32 cxix, I32 size) {
 
  SU_D(PerlIO_printf(Perl_debug_log, "%p: ### init for cx %d\n", ud, cxix));
 
- if (size <= SU_SAVE_DESTRUCTOR_SIZE)
+ /* su_pop() is going to be called from leave_scope(), so before pushing the
+  * next callback, we'll want to flush the current scope stack slice first.
+  * However, if we want the next callback not to be processed immediately by
+  * the current leave_scope(), we'll need to hide it by artificially
+  * incrementing the scope stack marker before. For the intermediate bumps,
+  * we will only need a bump of SU_SAVE_DESTRUCTOR_SIZE items, but for the
+  * last one we will need a bump of size items. However, in order to preserve
+  * the natural ordering between scope stack markers, we cannot bump lower
+  * markers more than higher ones. This is why we bump the intermediate markers
+  * by the smallest multiple of SU_SAVE_PLACEHOLDER_SIZE greater or equal to
+  * max(SU_SAVE_DESTRUCTOR_SIZE, size). */
+
+ if (size <= SU_SAVE_DESTRUCTOR_SIZE) {
   pad = 0;
- else {
else {
   I32 extra = size - SU_SAVE_DESTRUCTOR_SIZE;
   pad = extra / SU_SAVE_PLACEHOLDER_SIZE;
   if (extra % SU_SAVE_PLACEHOLDER_SIZE)
@@ -1147,12 +1159,22 @@ static I32 su_init(pTHX_ void *ud, I32 cxix, I32 size) {
  depth = PL_scopestack_ix - cxstack[cxix].blk_oldscopesp;
  SU_D(PerlIO_printf(Perl_debug_log, "%p: going down to depth %d\n", ud, depth));
 
+ /* We need to bump all the intermediary stack markers just in case an
+  * exception is thrown before the target scope is reached. Indeed, in this
+  * case there might be arbitrary many scope frames flushed at the same time,
+  * and since we cannot know in advance whether this will happen or not, we
+  * have to make sure the final frame is protected for the actual action. But
+  * of course, in order to do that, we also need to bump all the previous stack
+  * markers. If not for this, it should have been possible to just bump the two
+  * next frames in su_pop(). */
+
  Newx(origin, depth + 1, I32);
  base = PL_scopestack_ix - depth;
  origin[0] = PL_scopestack[base];
  PL_scopestack[base] += size;
  for (i = 1; i < depth; ++i) {
   I32 j = i + base;
+  /* origin[depth - i] == PL_scopestack[PL_scopestack_ix - i] */
   origin[i] = PL_scopestack[j];
   PL_scopestack[j] += offset;
  }