From 4f65a5796b2a724bdf99e76fdb50763840c53632 Mon Sep 17 00:00:00 2001 From: moz Date: Tue, 6 Dec 2016 13:44:18 -0800 Subject: [PATCH] Make ClosureBundler thread-safe by making mutable instance variables final Using mutable instance variables is not thread-safe, and some race conditions have caused sourceMaps to be empty. This change makes the mutable instance variables final and makes the with*() methods copy-on-write. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=141220397 --- .../jscomp/deps/ClosureBundler.java | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/com/google/javascript/jscomp/deps/ClosureBundler.java b/src/com/google/javascript/jscomp/deps/ClosureBundler.java index ee416c1082b..46052c742a1 100644 --- a/src/com/google/javascript/jscomp/deps/ClosureBundler.java +++ b/src/com/google/javascript/jscomp/deps/ClosureBundler.java @@ -29,40 +29,48 @@ /** * A utility class to assist in creating JS bundle files. */ -public class ClosureBundler { +public final class ClosureBundler { private final Transpiler transpiler; - private EvalMode mode = EvalMode.NORMAL; - private String sourceUrl = null; - private String path = "unknown_source"; + private final EvalMode mode; + private final String sourceUrl; + private final String path; // TODO(sdh): This cache should be moved out into a higher level, but is // currently required due to the API that source maps must be accessible // via just a path (and not the file contents). - private final Map sourceMapCache = new ConcurrentHashMap<>(); + private final Map sourceMapCache; public ClosureBundler() { this(Transpiler.NULL); } public ClosureBundler(Transpiler transpiler) { + this(transpiler, EvalMode.NORMAL, null, "unknown_source", + new ConcurrentHashMap()); + } + + private ClosureBundler(Transpiler transpiler, EvalMode mode, String sourceUrl, String path, + Map sourceMapCache) { this.transpiler = transpiler; + this.mode = mode; + this.sourceUrl = sourceUrl; + this.path = path; + this.sourceMapCache = sourceMapCache; } public final ClosureBundler useEval(boolean useEval) { - this.mode = useEval ? EvalMode.EVAL : EvalMode.NORMAL; - return this; + EvalMode newMode = useEval ? EvalMode.EVAL : EvalMode.NORMAL; + return new ClosureBundler(transpiler, newMode, sourceUrl, path, sourceMapCache); } - public final ClosureBundler withSourceUrl(String sourceUrl) { - this.sourceUrl = sourceUrl; - return this; + public final ClosureBundler withSourceUrl(String newSourceUrl) { + return new ClosureBundler(transpiler, mode, newSourceUrl, path, sourceMapCache); } - public final ClosureBundler withPath(String path) { - this.path = path; - return this; + public final ClosureBundler withPath(String newPath) { + return new ClosureBundler(transpiler, mode, sourceUrl, newPath, sourceMapCache); } /** Append the contents of the string to the supplied appendable. */