summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2019-09-14 18:05:00 +0200
committerRyan Dahl <ry@tinyclouds.org>2019-09-14 12:05:00 -0400
commit686b86edb1ee4cbac90ecb1c3931174879531207 (patch)
tree21dad4415c57260c4f4347db79c576e6f8097bc4
parent7e3296dad92cee2e8b77baedfbeca38aa297928e (diff)
feat: parallelize downloads from TS compiler (#2949)
-rw-r--r--cli/ops/compiler.rs46
-rw-r--r--cli/ops/mod.rs6
-rw-r--r--js/compiler.ts135
-rw-r--r--js/dispatch.ts2
-rw-r--r--tests/error_004_missing_module.ts.out6
-rw-r--r--tests/error_005_missing_dynamic_import.ts.out5
-rw-r--r--tests/error_006_import_ext_failure.ts.out5
-rw-r--r--tests/error_011_bad_module_specifier.ts.out5
-rw-r--r--tests/error_012_bad_dynamic_import_specifier.ts.out5
9 files changed, 137 insertions, 78 deletions
diff --git a/cli/ops/compiler.rs b/cli/ops/compiler.rs
index 40d25aa74..975e01ee1 100644
--- a/cli/ops/compiler.rs
+++ b/cli/ops/compiler.rs
@@ -33,39 +33,49 @@ pub fn op_cache(
}
#[derive(Deserialize)]
-struct FetchSourceFileArgs {
- specifier: String,
+struct FetchSourceFilesArgs {
+ specifiers: Vec<String>,
referrer: String,
}
-pub fn op_fetch_source_file(
+pub fn op_fetch_source_files(
state: &ThreadSafeState,
args: Value,
_zero_copy: Option<PinnedBuf>,
) -> Result<JsonOp, ErrBox> {
- let args: FetchSourceFileArgs = serde_json::from_value(args)?;
+ let args: FetchSourceFilesArgs = serde_json::from_value(args)?;
// TODO(ry) Maybe a security hole. Only the compiler worker should have access
// to this. Need a test to demonstrate the hole.
let is_dyn_import = false;
- let resolved_specifier =
- state.resolve(&args.specifier, &args.referrer, false, is_dyn_import)?;
-
- let fut = state
- .file_fetcher
- .fetch_source_file_async(&resolved_specifier);
+ let mut futures = vec![];
+ for specifier in &args.specifiers {
+ let resolved_specifier =
+ state.resolve(specifier, &args.referrer, false, is_dyn_import)?;
+ let fut = state
+ .file_fetcher
+ .fetch_source_file_async(&resolved_specifier);
+ futures.push(fut);
+ }
// WARNING: Here we use tokio_util::block_on() which starts a new Tokio
- // runtime for executing the future. This is so we don't inadvernently run
+ // runtime for executing the future. This is so we don't inadvertently run
// out of threads in the main runtime.
- let out = tokio_util::block_on(fut)?;
- Ok(JsonOp::Sync(json!({
- "moduleName": out.url.to_string(),
- "filename": out.filename.to_str().unwrap(),
- "mediaType": out.media_type as i32,
- "sourceCode": String::from_utf8(out.source_code).unwrap(),
- })))
+ let files = tokio_util::block_on(futures::future::join_all(futures))?;
+ let res: Vec<serde_json::value::Value> = files
+ .into_iter()
+ .map(|file| {
+ json!({
+ "moduleName": file.url.to_string(),
+ "filename": file.filename.to_str().unwrap(),
+ "mediaType": file.media_type as i32,
+ "sourceCode": String::from_utf8(file.source_code).unwrap(),
+ })
+ })
+ .collect();
+
+ Ok(JsonOp::Sync(json!(res)))
}
#[derive(Deserialize)]
diff --git a/cli/ops/mod.rs b/cli/ops/mod.rs
index 1f07acc65..7a2e9c9f4 100644
--- a/cli/ops/mod.rs
+++ b/cli/ops/mod.rs
@@ -37,7 +37,7 @@ pub const OP_START: OpId = 10;
pub const OP_APPLY_SOURCE_MAP: OpId = 11;
pub const OP_FORMAT_ERROR: OpId = 12;
pub const OP_CACHE: OpId = 13;
-pub const OP_FETCH_SOURCE_FILE: OpId = 14;
+pub const OP_FETCH_SOURCE_FILES: OpId = 14;
pub const OP_OPEN: OpId = 15;
pub const OP_CLOSE: OpId = 16;
pub const OP_SEEK: OpId = 17;
@@ -133,8 +133,8 @@ pub fn dispatch(
OP_CACHE => {
dispatch_json::dispatch(compiler::op_cache, state, control, zero_copy)
}
- OP_FETCH_SOURCE_FILE => dispatch_json::dispatch(
- compiler::op_fetch_source_file,
+ OP_FETCH_SOURCE_FILES => dispatch_json::dispatch(
+ compiler::op_fetch_source_files,
state,
control,
zero_copy,
diff --git a/js/compiler.ts b/js/compiler.ts
index 41f23bcd2..1e1fe3dd3 100644
--- a/js/compiler.ts
+++ b/js/compiler.ts
@@ -136,18 +136,25 @@ function fetchAsset(name: string): string {
return sendSync(dispatch.OP_FETCH_ASSET, { name });
}
-/** Ops to Rust to resolve and fetch a modules meta data. */
-function fetchSourceFile(specifier: string, referrer: string): SourceFile {
- util.log("compiler.fetchSourceFile", { specifier, referrer });
- const res = sendSync(dispatch.OP_FETCH_SOURCE_FILE, {
- specifier,
+/** Ops to Rust to resolve and fetch modules meta data. */
+function fetchSourceFiles(
+ specifiers: string[],
+ referrer: string
+): SourceFile[] {
+ util.log("compiler.fetchSourceFiles", { specifiers, referrer });
+ const res = sendSync(dispatch.OP_FETCH_SOURCE_FILES, {
+ specifiers,
referrer
});
- return {
- ...res,
- typeDirectives: parseTypeDirectives(res.sourceCode)
- };
+ return res.map(
+ (sourceFile: SourceFile): SourceFile => {
+ return {
+ ...sourceFile,
+ typeDirectives: parseTypeDirectives(sourceFile.sourceCode)
+ };
+ }
+ );
}
/** Utility function to turn the number of bytes into a human readable
@@ -219,34 +226,69 @@ class Host implements ts.CompilerHost {
private _sourceFileCache: Record<string, SourceFile> = {};
+ private _getAsset(specifier: string): SourceFile {
+ const moduleName = specifier.split("/").pop()!;
+ if (moduleName in this._sourceFileCache) {
+ return this._sourceFileCache[moduleName];
+ }
+ const assetName = moduleName.includes(".")
+ ? moduleName
+ : `${moduleName}.d.ts`;
+ const sourceCode = fetchAsset(assetName);
+ const sourceFile = {
+ moduleName,
+ filename: specifier,
+ mediaType: MediaType.TypeScript,
+ sourceCode
+ };
+ this._sourceFileCache[moduleName] = sourceFile;
+ return sourceFile;
+ }
+
private _resolveModule(specifier: string, referrer: string): SourceFile {
- util.log("host._resolveModule", { specifier, referrer });
- // Handle built-in assets specially.
- if (specifier.startsWith(ASSETS)) {
- const moduleName = specifier.split("/").pop()!;
- if (moduleName in this._sourceFileCache) {
- return this._sourceFileCache[moduleName];
+ return this._resolveModules([specifier], referrer)[0];
+ }
+
+ private _resolveModules(
+ specifiers: string[],
+ referrer: string
+ ): SourceFile[] {
+ util.log("host._resolveModules", { specifiers, referrer });
+ const resolvedModules: Array<SourceFile | undefined> = [];
+ const modulesToRequest = [];
+
+ for (const specifier of specifiers) {
+ // Firstly built-in assets are handled specially, so they should
+ // be removed from array of files that we'll be requesting from Rust.
+ if (specifier.startsWith(ASSETS)) {
+ const assetFile = this._getAsset(specifier);
+ resolvedModules.push(assetFile);
+ } else if (specifier in this._sourceFileCache) {
+ const module = this._sourceFileCache[specifier];
+ resolvedModules.push(module);
+ } else {
+ // Temporarily fill with undefined, after fetching file from
+ // Rust it will be filled with proper value.
+ resolvedModules.push(undefined);
+ modulesToRequest.push(specifier);
}
- const assetName = moduleName.includes(".")
- ? moduleName
- : `${moduleName}.d.ts`;
- const sourceCode = fetchAsset(assetName);
- const sourceFile = {
- moduleName,
- filename: specifier,
- mediaType: MediaType.TypeScript,
- sourceCode
- };
- this._sourceFileCache[moduleName] = sourceFile;
- return sourceFile;
}
- const sourceFile = fetchSourceFile(specifier, referrer);
- assert(sourceFile.moduleName != null);
- const { moduleName } = sourceFile;
- if (!(moduleName! in this._sourceFileCache)) {
- this._sourceFileCache[moduleName!] = sourceFile;
+
+ // Now get files from Rust.
+ const sourceFiles = fetchSourceFiles(modulesToRequest, referrer);
+
+ for (const sourceFile of sourceFiles) {
+ assert(sourceFile.moduleName != null);
+ const { moduleName } = sourceFile;
+ if (!(moduleName! in this._sourceFileCache)) {
+ this._sourceFileCache[moduleName!] = sourceFile;
+ }
+ // And fill temporary `undefined`s with actual files.
+ const index = resolvedModules.indexOf(undefined);
+ resolvedModules[index] = sourceFile;
}
- return sourceFile;
+
+ return resolvedModules as SourceFile[];
}
/* Deno specific APIs */
@@ -371,22 +413,25 @@ class Host implements ts.CompilerHost {
containingFile in this._sourceFileCache
? this._sourceFileCache[containingFile].typeDirectives
: undefined;
- return moduleNames.map(
- (moduleName): ts.ResolvedModuleFull | undefined => {
- const mappedModuleName = getMappedModuleName(
- moduleName,
- containingFile,
- typeDirectives
- );
- const sourceFile = this._resolveModule(
- mappedModuleName,
- containingFile
- );
+
+ const mappedModuleNames = moduleNames.map(
+ (moduleName: string): string => {
+ return getMappedModuleName(moduleName, containingFile, typeDirectives);
+ }
+ );
+
+ return this._resolveModules(mappedModuleNames, containingFile).map(
+ (
+ sourceFile: SourceFile,
+ index: number
+ ): ts.ResolvedModuleFull | undefined => {
if (sourceFile.moduleName) {
const resolvedFileName = sourceFile.moduleName;
// This flags to the compiler to not go looking to transpile functional
// code, anything that is in `/$asset$/` is just library code
- const isExternalLibraryImport = moduleName.startsWith(ASSETS);
+ const isExternalLibraryImport = mappedModuleNames[index].startsWith(
+ ASSETS
+ );
const extension = getExtension(
resolvedFileName,
sourceFile.mediaType
diff --git a/js/dispatch.ts b/js/dispatch.ts
index 1a60a5363..a15da69f4 100644
--- a/js/dispatch.ts
+++ b/js/dispatch.ts
@@ -16,7 +16,7 @@ export const OP_START = 10;
export const OP_APPLY_SOURCE_MAP = 11;
export const OP_FORMAT_ERROR = 12;
export const OP_CACHE = 13;
-export const OP_FETCH_SOURCE_FILE = 14;
+export const OP_FETCH_SOURCE_FILES = 14;
export const OP_OPEN = 15;
export const OP_CLOSE = 16;
export const OP_SEEK = 17;
diff --git a/tests/error_004_missing_module.ts.out b/tests/error_004_missing_module.ts.out
index db56f51a5..c2a0d0208 100644
--- a/tests/error_004_missing_module.ts.out
+++ b/tests/error_004_missing_module.ts.out
@@ -3,10 +3,10 @@
at DenoError ([WILDCARD]errors.ts:[WILDCARD])
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
at sendSync[WILDCARD] ([WILDCARD]dispatch_json.ts:[WILDCARD])
- at fetchSourceFile ([WILDCARD]compiler.ts:[WILDCARD])
- at _resolveModule ([WILDCARD]compiler.ts:[WILDCARD])
- at [WILDCARD]compiler.ts:[WILDCARD]
+ at fetchSourceFiles ([WILDCARD]compiler.ts:[WILDCARD])
+ at _resolveModules ([WILDCARD]compiler.ts:[WILDCARD])
at resolveModuleNames ([WILDCARD]compiler.ts:[WILDCARD])
at resolveModuleNamesWorker ([WILDCARD]typescript.js:[WILDCARD])
at resolveModuleNamesReusingOldState ([WILDCARD]typescript.js:[WILDCARD])
at processImportedModules ([WILDCARD]typescript.js:[WILDCARD])
+ at findSourceFile ([WILDCARD]typescript.js:[WILDCARD])
diff --git a/tests/error_005_missing_dynamic_import.ts.out b/tests/error_005_missing_dynamic_import.ts.out
index eb1d7b7b1..ec1468b09 100644
--- a/tests/error_005_missing_dynamic_import.ts.out
+++ b/tests/error_005_missing_dynamic_import.ts.out
@@ -3,9 +3,10 @@
at DenoError ([WILDCARD]errors.ts:[WILDCARD])
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
at sendSync[WILDCARD] ([WILDCARD]dispatch_json.ts:[WILDCARD])
- at fetchSourceFile ([WILDCARD]compiler.ts:[WILDCARD])
- at _resolveModule ([WILDCARD]compiler.ts:[WILDCARD])
+ at fetchSourceFiles ([WILDCARD]compiler.ts:[WILDCARD])
+ at _resolveModules ([WILDCARD]compiler.ts:[WILDCARD])
at [WILDCARD]compiler.ts:[WILDCARD]
at resolveModuleNamesWorker ([WILDCARD])
at resolveModuleNamesReusingOldState ([WILDCARD]typescript.js:[WILDCARD])
at processImportedModules ([WILDCARD]typescript.js:[WILDCARD])
+ at findSourceFile ([WILDCARD]typescript.js:[WILDCARD])
diff --git a/tests/error_006_import_ext_failure.ts.out b/tests/error_006_import_ext_failure.ts.out
index d0e14520b..aa82c10aa 100644
--- a/tests/error_006_import_ext_failure.ts.out
+++ b/tests/error_006_import_ext_failure.ts.out
@@ -3,9 +3,10 @@
at DenoError ([WILDCARD]errors.ts:[WILDCARD])
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
at sendSync[WILDCARD] ([WILDCARD]dispatch_json.ts:[WILDCARD])
- at fetchSourceFile ([WILDCARD]compiler.ts:[WILDCARD])
- at _resolveModule ([WILDCARD]compiler.ts:[WILDCARD])
+ at fetchSourceFiles ([WILDCARD]compiler.ts:[WILDCARD])
+ at _resolveModules ([WILDCARD]compiler.ts:[WILDCARD])
at [WILDCARD]compiler.ts:[WILDCARD]
at resolveModuleNamesWorker ([WILDCARD])
at resolveModuleNamesReusingOldState ([WILDCARD]typescript.js:[WILDCARD])
at processImportedModules ([WILDCARD]typescript.js:[WILDCARD])
+ at findSourceFile ([WILDCARD]typescript.js:[WILDCARD])
diff --git a/tests/error_011_bad_module_specifier.ts.out b/tests/error_011_bad_module_specifier.ts.out
index 9918c503c..97f59f2ca 100644
--- a/tests/error_011_bad_module_specifier.ts.out
+++ b/tests/error_011_bad_module_specifier.ts.out
@@ -3,9 +3,10 @@
at DenoError ([WILDCARD]errors.ts:[WILDCARD])
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
at sendSync[WILDCARD] ([WILDCARD]dispatch_json.ts:[WILDCARD])
- at fetchSourceFile ([WILDCARD]compiler.ts:[WILDCARD])
- at _resolveModule ([WILDCARD]compiler.ts:[WILDCARD])
+ at fetchSourceFiles ([WILDCARD]compiler.ts:[WILDCARD])
+ at _resolveModules ([WILDCARD]compiler.ts:[WILDCARD])
at [WILDCARD]compiler.ts:[WILDCARD]
at resolveModuleNamesWorker ([WILDCARD])
at resolveModuleNamesReusingOldState ([WILDCARD]typescript.js:[WILDCARD])
at processImportedModules ([WILDCARD]typescript.js:[WILDCARD])
+ at findSourceFile ([WILDCARD]typescript.js:[WILDCARD])
diff --git a/tests/error_012_bad_dynamic_import_specifier.ts.out b/tests/error_012_bad_dynamic_import_specifier.ts.out
index 9918c503c..97f59f2ca 100644
--- a/tests/error_012_bad_dynamic_import_specifier.ts.out
+++ b/tests/error_012_bad_dynamic_import_specifier.ts.out
@@ -3,9 +3,10 @@
at DenoError ([WILDCARD]errors.ts:[WILDCARD])
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
at sendSync[WILDCARD] ([WILDCARD]dispatch_json.ts:[WILDCARD])
- at fetchSourceFile ([WILDCARD]compiler.ts:[WILDCARD])
- at _resolveModule ([WILDCARD]compiler.ts:[WILDCARD])
+ at fetchSourceFiles ([WILDCARD]compiler.ts:[WILDCARD])
+ at _resolveModules ([WILDCARD]compiler.ts:[WILDCARD])
at [WILDCARD]compiler.ts:[WILDCARD]
at resolveModuleNamesWorker ([WILDCARD])
at resolveModuleNamesReusingOldState ([WILDCARD]typescript.js:[WILDCARD])
at processImportedModules ([WILDCARD]typescript.js:[WILDCARD])
+ at findSourceFile ([WILDCARD]typescript.js:[WILDCARD])