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

dead_branch_remover turns indirect eval into direct eval #2465

Closed
mischnic opened this issue Oct 18, 2021 · 1 comment · Fixed by #2564
Closed

dead_branch_remover turns indirect eval into direct eval #2465

mischnic opened this issue Oct 18, 2021 · 1 comment · Fixed by #2564
Labels
Milestone

Comments

@mischnic
Copy link
Contributor

Describe the bug

With eval, it makes a difference whether the callee is the literal identifier eval or just some expressions that is === eval. This is currently incorrectly optimized

Input code

const X = {
    run() {
        console.log(eval("this") === this);
        console.log((0, eval)("this") === globalThis);
    },
};

X.run();

Prints true, true

Config

Details
use swc_common::{
    chain, comments::SingleThreadedComments, sync::Lrc, FileName, Globals, Mark, SourceMap,
};
use swc_ecma_ast::Module;
use swc_ecma_codegen::{text_writer::JsWriter, Config, Emitter};
use swc_ecma_parser::{lexer::Lexer, EsConfig, PResult, Parser, StringInput, Syntax};
use swc_ecma_transforms::{
    compat::reserved_words::reserved_words, fixer, helpers, hygiene,
    optimization::simplify::dead_branch_remover, resolver::resolver_with_mark,
};
use swc_ecma_visit::FoldWith;

fn main() {
    let cm = Lrc::<SourceMap>::default();
    let src = r#"
    const X = {
        run() {
            console.log(eval("this") === this);
            console.log((0, eval)("this") === globalThis);
        },
    };
    
    X.run();
"#;
    let (module, comments) = parse(src, "test.js", &cm).unwrap();

    swc_common::GLOBALS.set(&Globals::new(), || {
        helpers::HELPERS.set(&helpers::Helpers::default(), || {
            let global_mark = Mark::fresh(Mark::root());
            let module = module.fold_with(&mut resolver_with_mark(global_mark));

            let transform = &mut dead_branch_remover();
            let module = module.fold_with(transform);

            let module = module.fold_with(&mut chain!(
                reserved_words(),
                hygiene(),
                fixer(Some(&comments))
            ));

            let code = emit(&module, &comments, cm);
            println!("{}", code);
        });
    });
}

fn parse(
    code: &str,
    filename: &str,
    cm: &Lrc<SourceMap>,
) -> PResult<(Module, SingleThreadedComments)> {
    let source_file = cm.new_source_file(FileName::Real(filename.into()), code.into());
    let comments = SingleThreadedComments::default();

    let lexer = Lexer::new(
        Syntax::Es(EsConfig {
            jsx: true,
            ..Default::default()
        }),
        // Syntax::Typescript(TsConfig {
        //     tsx: true,
        //     ..Default::default()
        // }),
        Default::default(),
        StringInput::from(&*source_file),
        Some(&comments),
    );
    let mut parser = Parser::new_from(lexer);
    match parser.parse_module() {
        Err(err) => Err(err),
        Ok(module) => Ok((module, comments)),
    }
}

fn emit(module: &Module, comments: &SingleThreadedComments, cm: Lrc<SourceMap>) -> String {
    let mut buf = vec![];
    {
        let writer = Box::new(JsWriter::new(cm.clone(), "\n", &mut buf, None));
        let config = Config { minify: false };
        let mut emitter = Emitter {
            cfg: config,
            comments: Some(&comments),
            cm,
            wr: writer,
        };
        emitter.emit_module(&module).unwrap();
    }

    String::from_utf8(buf).unwrap()
}

Current output

const X = {
    run() {
        console.log(eval("this") === this);
        console.log(eval("this") === globalThis);
    },
};

X.run();

Prints true, false

Expected behavior
Output should be the same as the input

Version
98a18e3

Additional context
parcel-bundler/parcel#7116

@mischnic mischnic added the C-bug label Oct 18, 2021
@kdy1 kdy1 modified the milestones: v1.2.101, v1.2.102, v1.2.103 Oct 19, 2021
ondrejmirtes added a commit to phpstan/phpstan that referenced this issue Oct 24, 2021
@kdy1 kdy1 modified the milestones: v1.2.103, v1.2.104, v1.2.105, v1.2.106 Oct 25, 2021
kdy1 added a commit that referenced this issue Oct 28, 2021
swc_ecma_minifier:
 - Don't change depth of function while negating if statements. (#2558)

swc_ecma_transforms_optimization:
 - `dead_branch_remover`: Preserve `this`. (#2465, #2466)

swc:
 - Make `toplevel` default to true if `module` is true. (#2254)
@swc-bot
Copy link
Collaborator

swc-bot commented Oct 21, 2022

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@swc-project swc-project locked as resolved and limited conversation to collaborators Oct 21, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Development

Successfully merging a pull request may close this issue.

3 participants