Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Walk up data frames for nested @partial-block #1243

Merged
merged 3 commits into from
Sep 10, 2016

Conversation

lawnsea
Copy link
Collaborator

@lawnsea lawnsea commented Aug 16, 2016

The root cause of #1218 is that invokePartial creates a stack of data frames
for nested partial blocks, but resolvePartial always uses the value at top of
the stack without "popping" it. The result is an infinite recursive loop, as
references to @partial-block in the partial at the top of the stack resolve to
itself.

So, walk up the stack of data frames when evaluating. This is accomplished by

  1. setting the partial-block property to noop after use and
  2. using _parent['partial-block'] if partial-block is noop

Fix #1218

The root cause of handlebars-lang#1218 is that `invokePartial` creates a stack of data frames
for nested partial blocks, but `resolvePartial` always uses the value at top of
the stack without "popping" it. The result is an infinite recursive loop, as
references to `@partial-block` in the partial at the top of the stack resolve to
itself.

So, walk up the stack of data frames when evaluating. This is accomplished by
1) setting the `partial-block` property to `noop` after use and
2) using `_parent['partial-block']` if `partial-block` is `noop`

Fix handlebars-lang#1218
@@ -197,7 +197,12 @@ export function wrapProgram(container, i, fn, data, declaredBlockParams, blockPa
export function resolvePartial(partial, context, options) {
if (!partial) {
if (options.name === '@partial-block') {
partial = options.data['partial-block'];
let data = options.data;
while (data['partial-block'] === noop) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This loop is a bit scary, I know. I'm open to suggestions for a base case to bail on.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain where noop comes from?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I.e. what causes it to be populated in the first place.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After I set partial to data['partial-block'], I set data['partial-block'] to noop on line 205 so that we'll know it's been used the next time we're in here.

@lawnsea
Copy link
Collaborator Author

lawnsea commented Aug 17, 2016

I just verified that this also fixes the reduced test cases provided by @damncabbage and @stringbean in #1185.

@lawnsea
Copy link
Collaborator Author

lawnsea commented Aug 17, 2016

Added a test for #1185 and changed the test for #1218 to use a less bizarre syntax in its template.

@lawnsea
Copy link
Collaborator Author

lawnsea commented Aug 17, 2016

@kpdecker I know you don't have any time for Handlebars right now. Unfortunately, you're the only recently active collaborator to this repo. Is there another collaborator you can suggest that I ask to review and land this PR? This bug is blocking us. Thanks!

@lawnsea
Copy link
Collaborator Author

lawnsea commented Aug 29, 2016

@wycats can you find someone to review this PR, please?

@fivetanley
Copy link
Contributor

@ErisDS do you have any time to review this one?

@dpehrson
Copy link

dpehrson commented Sep 5, 2016

Just hit this using handlebars for the first time as part of frctl/fractal for building a component-focused interface. Anything I can do to help get this out the door? My use case is similar to the original reporters:

paragraph.hbs

<p>{{> @partial-block}}</p>

blockquote.hbs

<blockquote>
    {{#> @paragraph}}
        {{> @partial-block}}
    {{/@paragraph}}
</blockquote>

With the latter it basically wraps and passes it's partial-block along to another partial expecting a partial-block.

@wycats
Copy link
Collaborator

wycats commented Sep 6, 2016

@lawnsea this looks pretty good to me. Do you know whether this regresses performance for Handlebars templates that aren't using partials? I generally try to make .. and partials very "pay as you go" in Handlebars.

@lawnsea
Copy link
Collaborator Author

lawnsea commented Sep 6, 2016

@wycats I don't expect it to, no. The code path I modified should only be hit when resolving a partial named @partial-block. But, just to be sure, lemme run grunt bench. I'll be back with details in a few.

@lawnsea
Copy link
Collaborator Author

lawnsea commented Sep 6, 2016

@wycats Here are the benchmark results:

master

Precompiled sizes: {
  "arguments": 381,
  "knownOnly_arguments": 328,
  "array-each": 706,
  "knownOnly_array-each": 514,
  "array-mustache": 979,
  "knownOnly_array-mustache": 533,
  "complex": 2542,
  "knownOnly_complex": 1809,
  "data": 965,
  "knownOnly_data": 602,
  "depth-1": 598,
  "knownOnly_depth-1": 598,
  "depth-2": 1058,
  "knownOnly_depth-2": 1058,
  "object-mustache": 1256,
  "knownOnly_object-mustache": 641,
  "object": 983,
  "knownOnly_object": 624,
  "partial-recursion": 921,
  "knownOnly_partial-recursion": 743,
  "partial": 644,
  "knownOnly_partial": 644,
  "paths": 730,
  "knownOnly_paths": 730,
  "string": 128,
  "knownOnly_string": 128,
  "subexpression": 428,
  "knownOnly_subexpression": 318,
  "variables": 737,
  "knownOnly_variables": 374
}
Execution Throughput
(node) util.print is deprecated. Use console.log instead.

ops/msec            handlebars          compat              dust                eco                 mustache            WINNER(S)
---------------------------------------------------------------------------------------------------------------------------------
arguments           285 ±112 (4)        493 ±6 (4)          NA                  NA                  NA                  compat
array-each          836 ±13 (4)         427 ±6 (6)          525 ±7 (5)          268 ±10 (4)         175 ±3 (4)          handlebars
array-mustache      662 ±10 (4)         348 ±5 (6)          NA                  NA                  NA                  handlebars
complex             227 ±3 (4)          131 ±2 (3)          168 ±3 (3)          143 ±7 (3)          84 ±1 (5)           handlebars
data                401 ±5 (4)          285 ±4 (6)          NA                  NA                  NA                  handlebars
depth-1             403 ±5 (7)          340 ±4 (3)          NA                  285 ±10 (3)         149 ±2 (4)          handlebars
depth-2             131 ±2 (4)          115 ±2 (4)          NA                  165 ±5 (4)          56 ±1 (3)           eco
object-mustache     1124 ±11 (4)        196 ±6 (3)          NA                  NA                  NA                  handlebars
object              1210 ±19 (6)        176 ±3 (3)          716 ±7 (3)          364 ±25 (3)         308 ±5 (4)          handlebars
partial-recursion   67 ±2 (5)           55 ±1 (3)           59 ±1 (6)           NA                  163 ±2 (4)          mustache
partial             324 ±5 (6)          108 ±1 (3)          308 ±5 (6)          NA                  122 ±2 (3)          handlebars
paths               1708 ±21 (6)        1195 ±19 (5)        519 ±7 (3)          304 ±18 (3)         209 ±4 (3)          handlebars
string              1987 ±59 (3)        1687 ±45 (3)        1309 ±49 (6)        1252 ±143 (3)       15090 ±173 (7)      mustache
subexpression       416 ±7 (4)          435 ±4 (4)          NA                  700 ±36 (3)         NA                  eco
variables           2019 ±15 (4)        1783 ±15 (4)        1029 ±24 (7)        375 ±18 (3)         466 ±14 (5)         handlebars


scaled              handlebars          compat              dust                eco                 mustache
------------------------------------------------------------------------------------------------------------------------
arguments           1.52                2.89
array-each          5.14                2.45                3.10                1.41                0.80
array-mustache      4.00                1.93
complex             1.14                0.51                0.75                0.59                0.20
data                2.28                1.52
depth-1             2.29                1.88                                    1.52                0.62
depth-2             0.51                0.40                                    0.73                0.01
object-mustache     7.04                0.93
object              7.60                0.80                4.35                2.04                1.67
partial-recursion   0.09                0.01                0.03                                    0.72
partial             1.78                0.36                1.67                                    0.45
paths               10.88               7.50                3.06                1.64                1.02
string              12.71               10.74               8.25                7.88                98.86
subexpression       2.38                2.51                                    4.25
variables           12.92               11.37               6.41                2.11                2.71

Distribution sizes: {
  "handlebars": 154894,
  "handlebars_min": 70370,
  "handlebars_runtime": 33248,
  "handlebars_runtime_min": 13544,
  "handlebars_runtime_min_gz": 4827,
  "handlebars_runtime_gz": 8241,
  "handlebars_min_gz": 21100,
  "handlebars_gz": 34481
}

This patch

Precompiled sizes: {
  "arguments": 381,
  "knownOnly_arguments": 328,
  "array-each": 706,
  "knownOnly_array-each": 514,
  "array-mustache": 979,
  "knownOnly_array-mustache": 533,
  "complex": 2542,
  "knownOnly_complex": 1809,
  "data": 965,
  "knownOnly_data": 602,
  "depth-1": 598,
  "knownOnly_depth-1": 598,
  "depth-2": 1058,
  "knownOnly_depth-2": 1058,
  "object-mustache": 1256,
  "knownOnly_object-mustache": 641,
  "object": 983,
  "knownOnly_object": 624,
  "partial-recursion": 921,
  "knownOnly_partial-recursion": 743,
  "partial": 644,
  "knownOnly_partial": 644,
  "paths": 730,
  "knownOnly_paths": 730,
  "string": 128,
  "knownOnly_string": 128,
  "subexpression": 428,
  "knownOnly_subexpression": 318,
  "variables": 737,
  "knownOnly_variables": 374
}
Execution Throughput
(node) util.print is deprecated. Use console.log instead.

ops/msec            handlebars          compat              dust                eco                 mustache            WINNER(S)
---------------------------------------------------------------------------------------------------------------------------------
arguments           328 ±134 (5)        544 ±4 (4)          NA                  NA                  NA                  compat
array-each          841 ±5 (5)          446 ±3 (4)          519 ±9 (8)          285 ±12 (3)         224 ±2 (8)          handlebars
array-mustache      858 ±6 (4)          443 ±4 (7)          NA                  NA                  NA                  handlebars
complex             292 ±2 (6)          178 ±2 (4)          229 ±2 (5)          146 ±4 (3)          85 ±1 (3)           handlebars
data                410 ±4 (6)          280 ±5 (7)          NA                  NA                  NA                  handlebars
depth-1             380 ±7 (3)          375 ±4 (4)          NA                  300 ±11 (3)         179 ±1 (4)          handlebars, compat
depth-2             154 ±1 (4)          142 ±3 (5)          NA                  187 ±6 (4)          63 ±1 (3)           eco
object-mustache     1068 ±15 (5)        178 ±5 (4)          NA                  NA                  NA                  handlebars
object              1113 ±16 (5)        196 ±3 (4)          777 ±11 (6)         356 ±17 (4)         359 ±11 (4)         handlebars
partial-recursion   77 ±2 (5)           63 ±1 (4)           60 ±1 (8)           NA                  178 ±3 (5)          mustache
partial             360 ±5 (4)          129 ±1 (5)          314 ±4 (6)          NA                  136 ±1 (5)          handlebars
paths               1824 ±18 (4)        1310 ±17 (6)        535 ±8 (4)          323 ±24 (3)         208 ±4 (4)          handlebars
string              2129 ±49 (3)        1726 ±64 (3)        1468 ±35 (3)        1222 ±136 (3)       14522 ±319 (6)      mustache
subexpression       424 ±14 (4)         391 ±13 (3)         NA                  532 ±44 (3)         NA                  eco
variables           1797 ±73 (4)        1832 ±15 (4)        972 ±56 (5)         319 ±26 (4)         501 ±19 (4)         compat


scaled              handlebars          compat              dust                eco                 mustache
------------------------------------------------------------------------------------------------------------------------
arguments           1.82                3.28
array-each          5.29                2.62                3.11                1.53                1.12
array-mustache      5.41                2.60
complex             1.58                0.81                1.15                0.59                0.18
data                2.37                1.50
depth-1             2.17                2.14                                    1.63                0.81
depth-2             0.64                0.56                                    0.87                0.03
object-mustache     6.83                0.81
object              7.13                0.93                4.86                2.01                2.03
partial-recursion   0.12                0.03                0.01                                    0.81
partial             2.04                0.47                1.73                                    0.52
paths               11.94               8.46                3.22                1.79                1.01
string              14.00               11.28               9.53                7.87                97.84
subexpression       2.47                2.25                                    3.20
variables           11.76               11.99               6.18                1.76                2.99

Distribution sizes: {
  "handlebars": 154894,
  "handlebars_min": 70370,
  "handlebars_runtime": 33248,
  "handlebars_runtime_min": 13544,
  "handlebars_runtime_min_gz": 4827,
  "handlebars_runtime_gz": 8241,
  "handlebars_min_gz": 21100,
  "handlebars_gz": 34481
}

I don't really know how to interpret them.

@wycats
Copy link
Collaborator

wycats commented Sep 7, 2016

The numbers, at first glance, seem to show a regression (arguments: 285 -> 328, but with ±100+). If you think there's no reason for that, it's probably just noise. Let me look a little more closely at the code to make sure nothing jumps out and then I'll merge.

@wycats
Copy link
Collaborator

wycats commented Sep 10, 2016

After thinking about it more, this look good. Good work 😄

@wycats wycats merged commit 7535e48 into handlebars-lang:master Sep 10, 2016
@wycats
Copy link
Collaborator

wycats commented Sep 10, 2016

Sorry it took so long to merge, and thanks so much for your contribution.

@lawnsea
Copy link
Collaborator Author

lawnsea commented Sep 10, 2016

@wycats Thanks!

@dpehrson
Copy link

Thanks for getting this merged, can't wait to take advantage of it! Out of curiosity, I notice there hasn't been a tagged release since last November, should I just be using GitHub as the source or am I missing something?

@Dangoo
Copy link

Dangoo commented Sep 12, 2016

@wycats Will there be a new release soon containing that fixed issue? (Last one was from Nov 2015)

Oh, read @dpehrson post too late…
So +1 ;)

@dpehrson
Copy link

This popped up on my weekly checkin again, what is the status of how people should be installing handlebars? Is this not published to NPM anymore?

@lawnsea lawnsea mentioned this pull request Sep 26, 2016
@lawnsea
Copy link
Collaborator Author

lawnsea commented Sep 26, 2016

@dpehrson I opened #1256 to track getting a release done. /cc @wycats

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Nested partials not working
6 participants