Super Dev Mode: faster sourcemap loading
Instead of parsing the sourcemap as json and writing it out again,
replace a template variable while streaming the file.
To support this, I gave the GWT compiler the ability to set the
base URL in the sourcemap. (There's an option for this but it's
not exposed as a flag yet.)
Also, cleaned up the code server's internals and sourcemap
generation. (We no longer need to subclass SourceMapRecorder
to populate the "names" field in the sourcemap.)
Change-Id: I51ff3f0970aadb832b8f430175b103b104e8fd62
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/CompilerOptionsImpl.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/CompilerOptionsImpl.java
index 07a9c06..9bea351 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/CompilerOptionsImpl.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/CompilerOptionsImpl.java
@@ -35,24 +35,20 @@
class CompilerOptionsImpl extends UnmodifiableCompilerOptions {
private final CompileDir compileDir;
private final boolean failOnError;
- private final List<String> libraryPaths;
private final TreeLogger.Type logLevel;
private final List<String> moduleNames;
private final SourceLevel sourceLevel;
private final boolean strictPublicResources;
private final boolean strictSourceResources;
- CompilerOptionsImpl(CompileDir compileDir, List<String> moduleNames, SourceLevel sourceLevel,
- boolean failOnError, boolean strictSourceResources, boolean strictPublicResources,
- TreeLogger.Type logLevel) {
+ CompilerOptionsImpl(CompileDir compileDir, String moduleName, Options options) {
this.compileDir = compileDir;
- this.libraryPaths = ImmutableList.<String> of();
- this.moduleNames = Lists.newArrayList(moduleNames);
- this.sourceLevel = sourceLevel;
- this.failOnError = failOnError;
- this.strictSourceResources = strictSourceResources;
- this.strictPublicResources = strictPublicResources;
- this.logLevel = logLevel;
+ this.moduleNames = Lists.newArrayList(moduleName);
+ this.sourceLevel = options.getSourceLevel();
+ this.failOnError = options.isFailOnError();
+ this.strictSourceResources = options.enforceStrictResources();
+ this.strictPublicResources = options.enforceStrictResources();
+ this.logLevel = options.getLogLevel();
}
@Override
@@ -97,7 +93,7 @@
@Override
public List<String> getLibraryPaths() {
- return libraryPaths;
+ return ImmutableList.of();
}
/**
@@ -251,7 +247,7 @@
@Override
public boolean shouldAddRuntimeChecks() {
- // TODO set to true in a separate patch
+ // Not needed since no optimizations are on.
return false;
}
@@ -291,6 +287,11 @@
}
@Override
+ public String getSourceMapFilePrefix() {
+ return SourceHandler.SOURCEROOT_TEMPLATE_VARIABLE;
+ }
+
+ @Override
public boolean warnOverlappingSource() {
return false;
}
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/PageUtil.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/PageUtil.java
index bf67484..6ec0a5d 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/PageUtil.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/PageUtil.java
@@ -18,8 +18,11 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.dev.json.JsonObject;
+import com.google.gwt.thirdparty.guava.common.base.Charsets;
+import com.google.gwt.thirdparty.guava.common.io.Files;
import java.io.BufferedInputStream;
+import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -29,6 +32,8 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Reader;
import java.io.Writer;
import java.net.URL;
import java.util.Date;
@@ -127,6 +132,33 @@
}
/**
+ * Sends a text file, substituting one variable. (Doesn't preserve line endings.)
+ * @param templateVariable the string to replace
+ * @param replacement the replacement
+ */
+ static void sendTemplateFile(String mimeType, File file, String templateVariable,
+ String replacement, HttpServletResponse response) throws IOException {
+
+ BufferedReader reader = Files.newReader(file, Charsets.UTF_8);
+ try {
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.setContentType(mimeType);
+ PrintWriter out = response.getWriter();
+ while (true) {
+ String line = reader.readLine();
+ if (line == null) {
+ break;
+ }
+ line = line.replace(templateVariable, replacement);
+ out.println(line);
+ }
+ } finally {
+ reader.close();
+ }
+ }
+
+
+ /**
* Sends a page. Closes pageBytes when done.
*/
static void sendStream(String mimeType, InputStream pageBytes, HttpServletResponse response)
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java
index 3db96af..48c0ff3 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java
@@ -38,7 +38,6 @@
import com.google.gwt.dev.util.log.CompositeTreeLogger;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
import com.google.gwt.thirdparty.guava.common.base.Joiner;
-import com.google.gwt.thirdparty.guava.common.collect.Lists;
import java.io.File;
import java.io.IOException;
@@ -205,22 +204,19 @@
private boolean compileMonolithic(TreeLogger compileLogger, Map<String, String> bindingProperties,
CompileDir compileDir) throws UnableToCompleteException {
- CompilerOptions compilerOptions = new CompilerOptionsImpl(compileDir,
- options.getModuleNames(), options.getSourceLevel(), options.isFailOnError(),
- options.enforceStrictResources(), options.enforceStrictResources(),
- options.getLogLevel());
- compilerContext = compilerContextBuilder.options(compilerOptions).build();
+
+ CompilerOptions loadOptions = new CompilerOptionsImpl(compileDir, originalModuleName, options);
+ compilerContext = compilerContextBuilder.options(loadOptions).build();
ModuleDef module = loadModule(compileLogger, bindingProperties);
// Propagates module rename.
String newModuleName = module.getName();
moduleName.set(newModuleName);
- compilerOptions = new CompilerOptionsImpl(compileDir, Lists.newArrayList(newModuleName),
- options.getSourceLevel(), options.isFailOnError(), options.enforceStrictResources(),
- options.enforceStrictResources(), options.getLogLevel());
- compilerContext = compilerContextBuilder.options(compilerOptions).build();
- boolean success = new Compiler(compilerOptions).run(compileLogger, module);
+ CompilerOptions runOptions = new CompilerOptionsImpl(compileDir, newModuleName, options);
+ compilerContext = compilerContextBuilder.options(runOptions).build();
+
+ boolean success = new Compiler(runOptions).run(compileLogger, module);
if (success) {
publishedCompileDir = compileDir;
}
@@ -345,13 +341,12 @@
logger = logger.branch(TreeLogger.Type.INFO, "binding: " + propName + "=" + newValue);
- BindingProperty prop = module.getProperties().findBindingProp(propName);
- if (prop == null) {
+ BindingProperty binding = module.getProperties().findBindingProp(propName);
+ if (binding == null) {
logger.log(TreeLogger.Type.WARN, "undefined property: '" + propName + "'");
return;
}
- BindingProperty binding = (BindingProperty) prop;
if (!binding.isAllowedValue(newValue)) {
String[] allowedValues = binding.getAllowedValues(binding.getRootCondition());
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/SourceHandler.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/SourceHandler.java
index e3bc45b..afe5795 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/SourceHandler.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/SourceHandler.java
@@ -47,6 +47,8 @@
*/
static final String SOURCEMAP_PATH = "/sourcemaps/";
+ static final String SOURCEROOT_TEMPLATE_VARIABLE = "$sourceroot_goes_here$";
+
private Modules modules;
private final TreeLogger logger;
@@ -109,15 +111,29 @@
private void sendSourceMap(String moduleName, HttpServletRequest request,
HttpServletResponse response) throws IOException {
- SourceMap map = loadSourceMap(moduleName);
+ long startTime = System.currentTimeMillis();
- // hack: rewrite the source map so that each filename is a URL
- String serverPrefix = String.format("http://%s:%d/sourcemaps/%s/", request.getServerName(),
+ ModuleState moduleState = modules.get(moduleName);
+ File sourceMap = moduleState.findSourceMap();
+
+ // Stream the file, substituting the sourceroot variable with the filename.
+ // (This is more efficient than parsing the file as JSON.)
+
+ // We need to do this at runtime because we don't know what the hostname will be
+ // until we get a request. (For example, some people run the Code Server behind
+ // a reverse proxy to support https.)
+
+ String sourceRoot = String.format("http://%s:%d/sourcemaps/%s/", request.getServerName(),
request.getServerPort(), moduleName);
- map.addPrefixToEachSourceFile(serverPrefix);
- PageUtil.sendString("application/json", map.serialize(), response);
- logger.log(TreeLogger.WARN, "sent source map for module: " + moduleName);
+ PageUtil.sendTemplateFile("application/json", sourceMap,
+ "\"" + SOURCEROOT_TEMPLATE_VARIABLE + "\"",
+ "\"" + sourceRoot + "\"", response);
+
+ long elapsedTime = System.currentTimeMillis() - startTime;
+
+ logger.log(TreeLogger.WARN, "sent source map for module '" + moduleName +
+ "' in " + elapsedTime + " ms");
}
private void sendDirectoryListPage(String moduleName, HttpServletResponse response)
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/SourceMap.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/SourceMap.java
index 0ca184c..f48610a 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/SourceMap.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/SourceMap.java
@@ -24,7 +24,6 @@
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
-import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
@@ -60,19 +59,6 @@
}
/**
- * Adds the given prefix to each source filename in the source map.
- */
- void addPrefixToEachSourceFile(String serverPrefix) {
- JsonArray sources = (JsonArray) json.get("sources");
- JsonArray newSources = new JsonArray();
- for (int i = 0; i < sources.getLength(); i++) {
- String filename = sources.get(i).asString().getString();
- newSources.add(serverPrefix + filename);
- }
- json.put("sources", newSources);
- }
-
- /**
* Returns a sorted list of all the directories containing at least one filename
* in the source map.
*/
@@ -115,14 +101,4 @@
return result;
}
-
- String serialize() {
- StringWriter buffer = new StringWriter();
- try {
- json.write(buffer);
- } catch (IOException e) {
- throw new RuntimeException("can't convert sourcemap to json");
- }
- return buffer.toString();
- }
}
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/UnmodifiableCompilerOptions.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/UnmodifiableCompilerOptions.java
index 0990d69..516126e 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/UnmodifiableCompilerOptions.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/UnmodifiableCompilerOptions.java
@@ -235,6 +235,11 @@
}
@Override
+ public void setSourceMapFilePrefix(String path) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public final void setSoycEnabled(boolean enabled) {
throw new UnsupportedOperationException();
}
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/dev_mode_on.js b/dev/codeserver/java/com/google/gwt/dev/codeserver/dev_mode_on.js
index 7481833..6948cd0 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/dev_mode_on.js
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/dev_mode_on.js
@@ -94,7 +94,7 @@
overlay.style.left = 0;
overlay.style.bottom = 0;
overlay.style.right = 0;
- overlay.style.background = 'white';
+ overlay.style.background = 'black'; // darken background
overlay.style.opacity = '0.5';
return overlay;
}
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/SourceMapRecorder.java b/dev/core/src/com/google/gwt/core/ext/soyc/SourceMapRecorder.java
index 564c88f..0c744ae 100644
--- a/dev/core/src/com/google/gwt/core/ext/soyc/SourceMapRecorder.java
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/SourceMapRecorder.java
@@ -17,9 +17,11 @@
import com.google.gwt.core.ext.linker.SyntheticArtifact;
import com.google.gwt.core.linker.SymbolMapsLinker;
+import com.google.gwt.dev.jjs.Correlation;
import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.jjs.JsSourceMap;
import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.jjs.SourceInfoCorrelation;
import com.google.gwt.dev.jjs.SourceOrigin;
import com.google.gwt.thirdparty.debugging.sourcemap.SourceMapGeneratorV3;
import com.google.gwt.thirdparty.debugging.sourcemap.SourceMapParseException;
@@ -39,63 +41,81 @@
*/
public class SourceMapRecorder {
- public static List<SyntheticArtifact> makeSourceMapArtifacts(int permutationId,
- List<JsSourceMap> sourceInfoMaps) {
+ /**
+ * Generates a sourcemap for each fragment in the list.
+ *
+ * @param sourceFilePrefix the prefix that a debugger should add to the beginning of each
+ * filename in a sourcemap to determine the file's full URL.
+ * If null, filenames are relative to the sourcemap's URL.
+ */
+ public static List<SyntheticArtifact> exec(int permutationId,
+ List<JsSourceMap> fragmentMaps, String sourceFilePrefix) {
try {
- return (new SourceMapRecorder(permutationId)).recordSourceMap(sourceInfoMaps);
+ return new SourceMapRecorder(permutationId, fragmentMaps, sourceFilePrefix).createArtifacts();
} catch (Exception e) {
throw new InternalCompilerException(e.toString(), e);
}
}
- protected final int permutationId;
-
- protected SourceMapRecorder(int permutationId) {
- this.permutationId = permutationId;
+ /**
+ * Generates a sourcemap for each fragment in the list, with JavaScript-to-Java
+ * name mappings included.
+ */
+ public static List<SyntheticArtifact> execWithJavaNames(int permutationId,
+ List<JsSourceMap> fragmentMaps, String sourceFilePrefix) {
+ try {
+ SourceMapRecorder recorder = new SourceMapRecorder(permutationId, fragmentMaps,
+ sourceFilePrefix);
+ recorder.wantJavaNames = true;
+ return recorder.createArtifacts();
+ } catch (Exception e) {
+ throw new InternalCompilerException(e.toString(), e);
+ }
}
- protected List<SyntheticArtifact> recordSourceMap(List<JsSourceMap> sourceInfoMaps)
+ private final int permutationId;
+ private final List<JsSourceMap> fragmentMaps;
+ private final String sourceRoot;
+ private boolean wantJavaNames;
+
+ private SourceMapRecorder(int permutationId, List<JsSourceMap> fragmentMaps, String sourceRoot) {
+ this.permutationId = permutationId;
+ this.fragmentMaps = fragmentMaps;
+ this.sourceRoot = sourceRoot;
+ }
+
+ private List<SyntheticArtifact> createArtifacts()
throws IOException, JSONException, SourceMapParseException {
List<SyntheticArtifact> toReturn = Lists.newArrayList();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
SourceMapGeneratorV3 generator = new SourceMapGeneratorV3();
int fragment = 0;
- if (!sourceInfoMaps.isEmpty()) {
- for (JsSourceMap sourceMap : sourceInfoMaps) {
- generator.reset();
- addMappings(new SourceMappingWriter(generator), sourceMap);
- updateSourceMap(generator, fragment);
+ for (JsSourceMap sourceMap : fragmentMaps) {
+ generator.reset();
- baos.reset();
- OutputStreamWriter out = new OutputStreamWriter(baos);
- generator.appendTo(out, "sourceMap" + fragment);
- out.flush();
- toReturn.add(new SymbolMapsLinker.SourceMapArtifact(permutationId, fragment,
- baos.toByteArray()));
- fragment++;
+ if (sourceRoot != null) {
+ generator.setSourceRoot(sourceRoot);
}
+ addExtensions(generator, fragment);
+ addMappings(new SourceMappingWriter(generator), sourceMap);
+
+ baos.reset();
+ OutputStreamWriter out = new OutputStreamWriter(baos);
+ generator.appendTo(out, "sourceMap" + fragment);
+ out.flush();
+ toReturn.add(new SymbolMapsLinker.SourceMapArtifact(permutationId, fragment,
+ baos.toByteArray(), sourceRoot));
+ fragment++;
}
return toReturn;
}
- /**
- * A hook allowing a subclass to add more info to the sourcemap for a given fragment.
- */
- protected void updateSourceMap(SourceMapGeneratorV3 generator, int fragment)
- throws SourceMapParseException { }
-
- /**
- * A hook allowing a subclass to populate the "names" field in the sourcemap.
- *
- * <p>The name is currently always a Java identifier, but in theory may be any Java expression.
- * For example, a compiler-introduced temporary variable could be annotated with the expression
- * that produced it.
- *
- * <p>The name should only be set if the JavaScript range covers one JavaScript identifier.
- * (Otherwise return null.)
- */
- protected String getJavaName(SourceInfo sourceInfo) {
- return null;
+ private void addExtensions(SourceMapGeneratorV3 generator, int fragment)
+ throws SourceMapParseException {
+ // We don't convert to a string here so that the values will be added
+ // to the JSON as a number instead of a string.
+ generator.addExtension("x_gwt_permutation", permutationId);
+ generator.addExtension("x_gwt_fragment", fragment);
}
/**
@@ -126,4 +146,35 @@
}
output.flush();
}
+
+ /**
+ * Returns the name to be added to the "names" field in the sourcemap.
+ *
+ * <p>The name is currently always a Java identifier, but in theory may be any Java expression.
+ * For example, a compiler-introduced temporary variable could be annotated with the expression
+ * that produced it.
+ *
+ * <p>The name should only be set if the JavaScript range covers one JavaScript identifier.
+ * (Otherwise return null.)
+ */
+ private String getJavaName(SourceInfo sourceInfo) {
+
+ if (!wantJavaNames) {
+ return null;
+ }
+
+ if (!(sourceInfo instanceof SourceInfoCorrelation)) {
+ return null;
+ }
+
+ Correlation correlation = ((SourceInfoCorrelation) sourceInfo).getPrimaryCorrelation();
+ if (correlation == null) {
+ return null;
+ }
+
+ // Conserve space by not recording the package name. The sourcemap already contains the full
+ // path of the Java file (in the "sources" field), which is usually enough to identify
+ // the package. (The name may be a synthetic method name.)
+ return correlation.getIdent();
+ }
}
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/SourceMapRecorderExt.java b/dev/core/src/com/google/gwt/core/ext/soyc/SourceMapRecorderExt.java
deleted file mode 100644
index 0a4934c..0000000
--- a/dev/core/src/com/google/gwt/core/ext/soyc/SourceMapRecorderExt.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.core.ext.soyc;
-
-import com.google.gwt.core.ext.linker.SyntheticArtifact;
-import com.google.gwt.dev.jjs.Correlation;
-import com.google.gwt.dev.jjs.InternalCompilerException;
-import com.google.gwt.dev.jjs.JsSourceMap;
-import com.google.gwt.dev.jjs.SourceInfo;
-import com.google.gwt.dev.jjs.SourceInfoCorrelation;
-import com.google.gwt.thirdparty.debugging.sourcemap.SourceMapGeneratorV3;
-import com.google.gwt.thirdparty.debugging.sourcemap.SourceMapParseException;
-
-import java.util.List;
-
-/**
- * Creates Closure Compatible SourceMaps with named ranges.
- */
-public class SourceMapRecorderExt extends SourceMapRecorder {
-
- public static final String PERMUTATION_EXT = "x_gwt_permutation";
-
- public static List<SyntheticArtifact> makeSourceMapArtifacts(int permutationId,
- List<JsSourceMap> sourceInfoMaps) {
- try {
- return (new SourceMapRecorderExt(permutationId)).recordSourceMap(sourceInfoMaps);
- } catch (Exception e) {
- throw new InternalCompilerException(e.toString(), e);
- }
- }
-
- protected SourceMapRecorderExt(int permutationId) {
- super(permutationId);
- }
-
- @Override
- protected void updateSourceMap(SourceMapGeneratorV3 generator, int fragment)
- throws SourceMapParseException {
- generator.addExtension(PERMUTATION_EXT, new Integer(permutationId));
- generator.addExtension("x_gwt_fragment", new Integer(fragment));
- }
-
- @Override
- protected String getJavaName(SourceInfo sourceInfo) {
- // We can discard Unknown or not-so-valid (eg. com.google.gwt.dev.js.ast.JsProgram)
- // sourceInfo
- String rangeName = null;
- if (sourceInfo instanceof SourceInfoCorrelation) {
- Correlation correlation = ((SourceInfoCorrelation) sourceInfo).getPrimaryCorrelation();
- if (correlation != null) {
- // We can reduce name sizes by removing the left part corresponding to the
- // package name, eg. com.google.gwt.client. Because this is already in the file name.
- // This name includes static/synth method names
- rangeName = correlation.getIdent();
- }
- }
- return rangeName;
- }
-}
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/coderef/EntityRecorder.java b/dev/core/src/com/google/gwt/core/ext/soyc/coderef/EntityRecorder.java
index d54f20e..69d6daa 100644
--- a/dev/core/src/com/google/gwt/core/ext/soyc/coderef/EntityRecorder.java
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/coderef/EntityRecorder.java
@@ -17,7 +17,7 @@
import com.google.gwt.core.ext.linker.EmittedArtifact.Visibility;
import com.google.gwt.core.ext.linker.SyntheticArtifact;
-import com.google.gwt.core.ext.soyc.SourceMapRecorderExt;
+import com.google.gwt.core.ext.soyc.SourceMapRecorder;
import com.google.gwt.core.ext.soyc.coderef.EntityDescriptor.Fragment;
import com.google.gwt.core.linker.SoycReportLinker;
import com.google.gwt.dev.jjs.InternalCompilerException;
@@ -63,21 +63,22 @@
public static final String INITIAL_SEQUENCE = "initialSequence";
public static List<SyntheticArtifact> makeSoycArtifacts(int permutationId,
- List<JsSourceMap> sourceInfoMaps, JavaToJavaScriptMap jjsmap,
+ List<JsSourceMap> sourceInfoMaps, String sourceMapFilePrefix, JavaToJavaScriptMap jjsmap,
SizeBreakdown[] sizeBreakdowns, DependencyGraphRecorder codeGraph, JProgram jprogram) {
- EntityRecorder recorder = new EntityRecorder(sizeBreakdowns, permutationId);
+ List<SyntheticArtifact> artifacts = Lists.newArrayList();
try {
+ EntityRecorder recorder = new EntityRecorder(sizeBreakdowns, permutationId);
recorder.recordCodeReferences(codeGraph, sizeBreakdowns, jjsmap);
recorder.recordFragments(jprogram);
- // record source map with named ranges
- recorder.toReturn.addAll(SourceMapRecorderExt.makeSourceMapArtifacts(
- permutationId, sourceInfoMaps));
+ artifacts.addAll(recorder.toReturn);
+ artifacts.addAll(SourceMapRecorder.execWithJavaNames(permutationId, sourceInfoMaps,
+ sourceMapFilePrefix));
} catch (Exception e) {
throw new InternalCompilerException(e.toString(), e);
}
- return recorder.toReturn;
+ return artifacts;
}
private final List<SyntheticArtifact> toReturn = Lists.newArrayList();
diff --git a/dev/core/src/com/google/gwt/core/linker/SymbolMapsLinker.java b/dev/core/src/com/google/gwt/core/linker/SymbolMapsLinker.java
index 6ba1bd1..8b50d17 100644
--- a/dev/core/src/com/google/gwt/core/linker/SymbolMapsLinker.java
+++ b/dev/core/src/com/google/gwt/core/linker/SymbolMapsLinker.java
@@ -174,11 +174,14 @@
private int fragment;
private byte[] js;
- public SourceMapArtifact(int permutationId, int fragment, byte[] js) {
+ private final String sourceRoot;
+
+ public SourceMapArtifact(int permutationId, int fragment, byte[] js, String sourceRoot) {
super(SymbolMapsLinker.class, permutationId + '/' + sourceMapFilenameForFragment(fragment), js);
this.permutationId = permutationId;
this.fragment = fragment;
this.js = js;
+ this.sourceRoot = sourceRoot;
}
public int getFragment() {
@@ -189,6 +192,14 @@
return permutationId;
}
+ /**
+ * The base URL for Java filenames in the sourcemap.
+ * (We need to reapply this after edits.)
+ */
+ public String getSourceRoot() {
+ return sourceRoot;
+ }
+
public static String sourceMapFilenameForFragment(int fragment) {
// If this changes, update isSourceMapFile.
return "sourceMap" + fragment + ".json";
@@ -298,6 +309,12 @@
emArt = emitSourceMapString(logger, sourceMapString, partialPath);
} else {
SourceMapGeneratorV3 sourceMapGenerator = new SourceMapGeneratorV3();
+
+ if (se.getSourceRoot() != null) {
+ // Reapply source root since mergeMapSection() will not copy it.
+ sourceMapGenerator.setSourceRoot(se.getSourceRoot());
+ }
+
try {
int totalPrefixLines = 0;
for (ScriptFragmentEditsArtifact.EditOperation op : editArtifact.editOperations) {
diff --git a/dev/core/src/com/google/gwt/dev/PrecompileTaskOptions.java b/dev/core/src/com/google/gwt/dev/PrecompileTaskOptions.java
index fc58bfd..8475edf 100644
--- a/dev/core/src/com/google/gwt/dev/PrecompileTaskOptions.java
+++ b/dev/core/src/com/google/gwt/dev/PrecompileTaskOptions.java
@@ -22,6 +22,7 @@
import com.google.gwt.dev.util.arg.OptionMaxPermsPerPrecompile;
import com.google.gwt.dev.util.arg.OptionMissingDepsFile;
import com.google.gwt.dev.util.arg.OptionSaveSource;
+import com.google.gwt.dev.util.arg.OptionSourceMapFilePrefix;
import com.google.gwt.dev.util.arg.OptionValidateOnly;
import com.google.gwt.dev.util.arg.OptionWarnMissingDeps;
import com.google.gwt.dev.util.arg.OptionWarnOverlappingSource;
@@ -30,7 +31,7 @@
* The set of options for the Precompiler.
*/
public interface PrecompileTaskOptions extends JJSOptions, CompileTaskOptions, OptionGenDir,
- OptionSaveSource, OptionValidateOnly, OptionDisableUpdateCheck, OptionEnableGeneratingOnShards,
- OptionMaxPermsPerPrecompile, OptionMissingDepsFile, OptionWarnOverlappingSource,
- OptionWarnMissingDeps, PrecompilationResult {
+ OptionSaveSource, OptionSourceMapFilePrefix, OptionValidateOnly, OptionDisableUpdateCheck,
+ OptionEnableGeneratingOnShards, OptionMaxPermsPerPrecompile, OptionMissingDepsFile,
+ OptionWarnOverlappingSource, OptionWarnMissingDeps, PrecompilationResult {
}
diff --git a/dev/core/src/com/google/gwt/dev/PrecompileTaskOptionsImpl.java b/dev/core/src/com/google/gwt/dev/PrecompileTaskOptionsImpl.java
index e39b11d..ea13197 100644
--- a/dev/core/src/com/google/gwt/dev/PrecompileTaskOptionsImpl.java
+++ b/dev/core/src/com/google/gwt/dev/PrecompileTaskOptionsImpl.java
@@ -36,6 +36,7 @@
private int maxPermsPerPrecompile;
private File missingDepsFile;
private boolean saveSource;
+ private String sourceMapFilePrefix;
private boolean validateOnly;
private boolean warnOverlappingSource;
private boolean warnMissingDeps;
@@ -67,6 +68,7 @@
setDisableUpdateCheck(other.isUpdateCheckDisabled());
setGenDir(other.getGenDir());
setSaveSource(other.shouldSaveSource());
+ setSourceMapFilePrefix(other.getSourceMapFilePrefix());
setMaxPermsPerPrecompile(other.getMaxPermsPerPrecompile());
setWarnOverlappingSource(other.warnOverlappingSource());
setWarnMissingDeps(other.warnMissingDeps());
@@ -132,6 +134,11 @@
}
@Override
+ public String getSourceMapFilePrefix() {
+ return sourceMapFilePrefix;
+ }
+
+ @Override
@Deprecated
public boolean isAggressivelyOptimize() {
return jjsOptions.isAggressivelyOptimize();
@@ -363,6 +370,11 @@
}
@Override
+ public void setSourceMapFilePrefix(String path) {
+ sourceMapFilePrefix = path;
+ }
+
+ @Override
public void setSoycEnabled(boolean enabled) {
jjsOptions.setSoycEnabled(enabled);
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
index cdd6e94..c4a96df 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -392,7 +392,8 @@
} else {
// Is a super set of SourceMapRecorder.makeSourceMapArtifacts().
permutationResult.addArtifacts(EntityRecorder.makeSoycArtifacts(
- permutationId, sourceInfoMaps, jjsmap, sizeBreakdowns,
+ permutationId, sourceInfoMaps, options.getSourceMapFilePrefix(),
+ jjsmap, sizeBreakdowns,
((DependencyGraphRecorder) dependenciesAndRecorder.getRight()), jprogram));
}
} else if (isSourceMapsEnabled) {
@@ -402,8 +403,8 @@
+ "compiler.useSourceMaps=true; ignoring compiler.useSourceMaps=true.");
} else {
logger.log(TreeLogger.INFO, "Source Maps Enabled");
- permutationResult.addArtifacts(
- SourceMapRecorder.makeSourceMapArtifacts(permutationId, sourceInfoMaps));
+ permutationResult.addArtifacts(SourceMapRecorder.exec(permutationId, sourceInfoMaps,
+ options.getSourceMapFilePrefix()));
}
}
}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionSourceMapFilePrefix.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionSourceMapFilePrefix.java
new file mode 100644
index 0000000..42d4d45
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionSourceMapFilePrefix.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.util.arg;
+
+/**
+ * Specifies a prefix that a debugger should add to the beginning of each
+ * filename in a sourcemap to determine the file's full URL.
+ * (It's saved to the sourceRoot field in SourceMap spec.)
+ * If null, no prefix is saved and Java filenames are relative
+ * to the sourcemap's URL.
+ */
+public interface OptionSourceMapFilePrefix {
+
+ /**
+ * Returns the prefix to be added (or null for no prefix).
+ */
+ String getSourceMapFilePrefix();
+
+ /**
+ * Sets the prefix. (Null will disable it.)
+ */
+ void setSourceMapFilePrefix(String path);
+}
diff --git a/dev/core/test/com/google/gwt/core/ext/linker/SourceMapTest.java b/dev/core/test/com/google/gwt/core/ext/linker/SourceMapTest.java
index fdce59e..aafe4a6 100644
--- a/dev/core/test/com/google/gwt/core/ext/linker/SourceMapTest.java
+++ b/dev/core/test/com/google/gwt/core/ext/linker/SourceMapTest.java
@@ -16,7 +16,6 @@
package com.google.gwt.core.ext.linker;
import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.soyc.SourceMapRecorderExt;
import com.google.gwt.core.ext.soyc.coderef.ClassDescriptor;
import com.google.gwt.core.ext.soyc.coderef.EntityDescriptor;
import com.google.gwt.core.ext.soyc.coderef.EntityDescriptor.Fragment;
@@ -239,8 +238,9 @@
SourceMapConsumerV3 sourceMap = new SourceMapConsumerV3();
sourceMap.parse(stringContent(sourceMapFile));
if (firstIteration) {
- mapping.put((Integer) sourceMap.getExtensions().get(SourceMapRecorderExt.PERMUTATION_EXT),
- symbolTable);
+ Integer permutationId = (Integer) sourceMap.getExtensions().get("x_gwt_permutation");
+ assertNotNull(permutationId);
+ mapping.put(permutationId, symbolTable);
firstIteration = false;
}
sourceMap.visitMappings(new SourceMapConsumerV3.EntryVisitor() {
@@ -544,4 +544,4 @@
Util.recursiveDelete(work, false);
}
}
-}
\ No newline at end of file
+}