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

Fix #1786: use _interopRequireWildcard for import when required by an export #1829

Merged
merged 15 commits into from
Jun 24, 2021

Conversation

cspotcode
Copy link
Contributor

@cspotcode cspotcode commented Jun 17, 2021

Based on advice in #1826
Fixes #1786
Might also fix #1790

The ImportAnalyzer and CommonJs folders need to share a Scope. To facilitate this, I refactored each module folder into two Fold structs, for example, CommonJs and CommonJsWorker. The worker is created in fold_module, given a &mut Scope to do its work, and then dropped afterward. This let me avoid adding borrow() and deref() calls all over the place.

@CLAassistant
Copy link

CLAassistant commented Jun 17, 2021

CLA assistant check
All committers have signed the CLA.

@cspotcode
Copy link
Contributor Author

I have fixed the merge and the test; everything is passing now.

Copy link
Member

@kdy1 kdy1 left a comment

Choose a reason for hiding this comment

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

Thanks!

src/builder.rs Outdated Show resolved Hide resolved
ecmascript/transforms/module/tests/common_js.rs Outdated Show resolved Hide resolved
ecmascript/transforms/module/src/util.rs Show resolved Hide resolved
ecmascript/transforms/module/src/umd.rs Outdated Show resolved Hide resolved
ecmascript/transforms/module/src/amd.rs Outdated Show resolved Hide resolved
ecmascript/transforms/module/src/common_js.rs Outdated Show resolved Hide resolved
ecmascript/transforms/module/src/umd.rs Outdated Show resolved Hide resolved
@cspotcode
Copy link
Contributor Author

cspotcode commented Jun 19, 2021 via email

@kdy1
Copy link
Member

kdy1 commented Jun 19, 2021

Is there a good way to avoid this?

No. As far as I know, runtime-borrows are cumbersome because they should be (in rust).

Can I change chain() to accept a smaller visitor factory, and then teach chain to invoke the factory and use the value it returns? This would avoid the messy borrowing refactor and also avoid creating new visitors.

I think you should create an alternative maco like chain_factory! instead of modifying it.

But this is a complex problem. You want to pass down RefMut or &mut instead of Rc<RefCell>, right?
If then, it would require creating a new visitor from the macro and it becomes even worse.
I already tried something similar.

This is because you can't pass down RefMut to the second one until the first one finishes. So you can't create a chained visitor with shared data.

@kdy1
Copy link
Member

kdy1 commented Jun 19, 2021

I think this will conflict with #1834
I'll postpone #1834 if you are going to resolve issues soon.

@cspotcode
Copy link
Contributor Author

cspotcode commented Jun 19, 2021 via email

@kdy1
Copy link
Member

kdy1 commented Jun 19, 2021

Great, thanks!

@kdy1 kdy1 added this to the v1.2.62 milestone Jun 20, 2021
@cspotcode
Copy link
Contributor Author

I was so obsessed with learning Rust, I attempted something slightly different than merging the visitors. I implemented a FoldFactory which can give you a dyn Fold when you need to run the visitor. For backwards-compatibility, every Fold also implements FoldFactory by returning a reference to itself. Chains can be a mix of FoldFactory and Fold. The chain logic has been update to expect FoldFactory and to create Folds when the visitor runs, not sooner.

This allows CommonJsFactory to be a FoldFactory, not a full visitor. When it runs, it creates a CommonJs visitor with a mutable borrow of Scope. This borrow expires when the visitor finishes, but for the entire duration, CommonJs does not need to do extra work to dereference or borrow Scope.

This change adds dyn Fold, and I'm not sure if that will be bad for binary size. Is dyn Fold adding another visitor?

I noticed that the sourcemap tests require node 12 or older. Node 14 and 16 changed their stack trace output. Should I make a PR adding this requirement to CONTRIBUTING.md?

@cspotcode
Copy link
Contributor Author

Sorry, I forgot to change the other Fold visitors, I'll push that code soon...

@kdy1
Copy link
Member

kdy1 commented Jun 22, 2021

I'm not sure about such change.
Can you compare the size and performance of master and your branch?

@kdy1
Copy link
Member

kdy1 commented Jun 22, 2021

I looked at the code of amd pass, and it's two visitor and it's not related to dyn Fold nor FoldFactory.
Did you patch amd pass?

@kdy1
Copy link
Member

kdy1 commented Jun 22, 2021

I profiled the size on mac os.

master:

21550312  6 22 14:48 ./target/release/libnode.dylib

It's 21045 KB

pr:

58555296  6 22 15:00 ./target/release/libnode.dylib

It's 57182 KB

More than triple.

I also found that this pr makes compilation much slower (14m -> 27m)
Seems reasonable as there are much more code to generate.

@cspotcode
Copy link
Contributor Author

Yeah I accidentally forgot to change some of the visitors, I'm still working on that.

.entry(($i.sym.clone(), $i.span.ctxt()))
};
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This macro began raising an error that I did not understand, and I could not figure out how to fix it unless I stopped using the macro. I think the error was caused by folder.scope_mut() returning a RefMut<Scope>.

@@ -20,8 +21,8 @@ use swc_ecma_visit::{Fold, FoldWith, VisitWith};

pub(super) trait ModulePass: Fold {
fn config(&self) -> &Config;
fn scope(&self) -> &Scope;
fn scope_mut(&mut self) -> &mut Scope;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

As far as I can tell, this change is necessary because we cannot return a &Scope without also passing ownership of the Ref that it comes from.

@cspotcode
Copy link
Contributor Author

I've removed all the *Workers and FoldFactory. ImportAnalyzer and CommonJs borrow and deref the scope as necessary. Tests are passing locally, so I think this is ready for another review.

Copy link
Member

@kdy1 kdy1 left a comment

Choose a reason for hiding this comment

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

Mostly LGMT. Thanks a lot!

});
drop(scope);
Copy link
Member

Choose a reason for hiding this comment

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

Why is this required?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Without it I get this error:

error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
   --> ecmascript/transforms/module/src/amd.rs:361:54
    |
308 |                             let mut scope_ref_mut = self.scope.borrow_mut();
    |                                                     ---------- immutable borrow occurs here
...
361 |                                     None => Box::new(Expr::Ident(orig.clone()).fold_with(self)),
    |                                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
409 |                         }
    |                         - immutable borrow might be used here, when `scope_ref_mut` is dropped and runs the destructor for type `RefMut<'_, Scope>`

As far as I understand, scope and scope_ref_mut constitute an immutable borrow of self which will not be dropped till near the bottom of this function. This conflicts with mutable borrows made by fold_with(self). But if I drop scope and scope_ref_mut earlier, there is no conflict.

.import_types
.entry(src.value.clone())
.or_insert(false);
}
}

drop(scope);
Copy link
Member

Choose a reason for hiding this comment

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

Ditto

}
_ => {}
}

drop(scope);
Copy link
Member

Choose a reason for hiding this comment

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

Same as above

});

stmts.reserve(export.specifiers.len());

drop(scope);
Copy link
Member

Choose a reason for hiding this comment

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

Same as above

Copy link
Member

@kdy1 kdy1 left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks!

@kdy1 kdy1 merged commit a31ca40 into swc-project:master Jun 24, 2021
@swc-project swc-project locked as resolved and limited conversation to collaborators Nov 9, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
3 participants