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

Optimize property access evaluation #1213

Merged
merged 1 commit into from Jun 19, 2022

Conversation

jridgewell
Copy link
Collaborator

Given the input a.b.c.d.e.f, the previous code would call _eval 57 times when using unsafe (and 15 times when using normal):

1 a.b
2 a.b.c
3 a.b
4 a.b
5 a.b.c.d
6 a.b.c
7 a.b
8 a.b
9 a.b.c
10 a.b
11 a.b
12 a.b.c.d.e
13 a.b.c.d
14 a.b.c
15 a.b
16 a.b
17 a.b.c
18 a.b
19 a.b
20 a.b.c.d
21 a.b.c
22 a.b
23 a.b
24 a.b.c
25 a.b
26 a.b
27 a.b.c.d.e.f
28 a.b.c.d.e
29 a.b.c.d
30 a.b.c
31 a.b
32 a.b
33 a.b.c
34 a.b
35 a.b
36 a.b.c.d
37 a.b.c
38 a.b
39 a.b
40 a.b.c
41 a.b
42 a.b
43 a.b.c.d.e
44 a.b.c.d
45 a.b.c
46 a.b
47 a.b
48 a.b.c
49 a.b
50 a.b
51 a.b.c.d
52 a.b.c
53 a.b
54 a.b
55 a.b.c
56 a.b
57 a.b

The first optimization is to only call expression._eval(…) a single time per evaluation of a AST_PropAccess. We've already called it to determine if we're a nullish, so there's no reason to do it a second time in the unsafe path. This alone brings us down to 15 calls (this is the same as the old normal path):

1 a.b
2 a.b.c
3 a.b
4 a.b.c.d
5 a.b.c
6 a.b
7 a.b.c.d.e
8 a.b.c.d
9 a.b.c
10 a.b
11 a.b.c.d.e.f
12 a.b.c.d.e
13 a.b.c.d
14 a.b.c
15 a.b

But, we can do even better by avoiding the evaluation mid–chain. There's no reason to evaluation unless the evaluation comes from the top of the chain (the rightmost property access). If anything can be optimized, it can optimize while we descend one time from that point. This brings us to 6 evaluations:

1 a.b
2 a.b.c.d.e.f
3 a.b.c.d.e
4 a.b.c.d
5 a.b.c
6 a.b

(I'm not sure why that first one happens)

Fixes #1212

Given the input `a.b.c.d.e.f`, the previous code would call `_eval` 57 times:

```
1 a.b
2 a.b.c
3 a.b
4 a.b
5 a.b.c.d
6 a.b.c
7 a.b
8 a.b
9 a.b.c
10 a.b
11 a.b
12 a.b.c.d.e
13 a.b.c.d
14 a.b.c
15 a.b
16 a.b
17 a.b.c
18 a.b
19 a.b
20 a.b.c.d
21 a.b.c
22 a.b
23 a.b
24 a.b.c
25 a.b
26 a.b
27 a.b.c.d.e.f
28 a.b.c.d.e
29 a.b.c.d
30 a.b.c
31 a.b
32 a.b
33 a.b.c
34 a.b
35 a.b
36 a.b.c.d
37 a.b.c
38 a.b
39 a.b
40 a.b.c
41 a.b
42 a.b
43 a.b.c.d.e
44 a.b.c.d
45 a.b.c
46 a.b
47 a.b
48 a.b.c
49 a.b
50 a.b
51 a.b.c.d
52 a.b.c
53 a.b
54 a.b
55 a.b.c
56 a.b
57 a.b
```

The first optimization is to only call `expression._eval(…)` a single time per evaluation of a `AST_PropAccess`. We've already called it to determine if we're a nullish, so there's no reason to do it a second time in the unsafe path. This alone brings us down to 15 calls:

```
1 a.b
2 a.b.c
3 a.b
4 a.b.c.d
5 a.b.c
6 a.b
7 a.b.c.d.e
8 a.b.c.d
9 a.b.c
10 a.b
11 a.b.c.d.e.f
12 a.b.c.d.e
13 a.b.c.d
14 a.b.c
15 a.b
```

But, we can do even better by avoiding the evaluation mid–chain. There's no reason to evaluation unless the evaluation comes from the top of the chain (the rightmost property access). If anything can be optimized, it can optimize while we descend one time from that point. This brings us to 6 evaluations:

```
1 a.b
2 a.b.c.d.e.f
3 a.b.c.d.e
4 a.b.c.d
5 a.b.c
6 a.b
```

(I'm not sure why that first one happens)
@fabiosantoscode
Copy link
Collaborator

Nice work, thanks! ❤️

@fabiosantoscode fabiosantoscode merged commit 645a092 into terser:master Jun 19, 2022
@jridgewell jridgewell deleted the quadratic-prop-access branch June 19, 2022 22:55
@ChristophP
Copy link

ChristophP commented Jun 20, 2022

Awesome thank you for responding so quickly ❤️

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.

Terser hangs forever
3 participants