debt - no guessing-caching, better use of gc-signals, command converter using gc-signals, main side heap service

This commit is contained in:
Johannes Rieken
2016-10-21 18:53:05 +02:00
parent c57c31abc9
commit fbacd65e2a
13 changed files with 292 additions and 256 deletions

View File

@@ -6,7 +6,6 @@
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import * as vscode from 'vscode';
import * as TypeConverters from 'vs/workbench/api/node/extHostTypeConverters';
@@ -15,10 +14,10 @@ import { IPosition, IRange, ISingleEditOperation } from 'vs/editor/common/editor
import * as modes from 'vs/editor/common/modes';
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands';
import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics';
import { IWorkspaceSymbolProvider, IWorkspaceSymbol } from 'vs/workbench/parts/search/common/search';
import { asWinJsPromise, ShallowCancelThenPromise } from 'vs/base/common/async';
import { asWinJsPromise } from 'vs/base/common/async';
import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier } from './extHost.protocol';
import { regExpLeadsToEndlessLoop } from 'vs/base/common/strings';
@@ -44,112 +43,57 @@ class OutlineAdapter {
}
}
interface CachedCodeLens {
symbols: modes.ICodeLensSymbol[];
lenses: vscode.CodeLens[];
disposables: IDisposable[];
}
class CodeLensAdapter {
private static _badCmd: vscode.Command = { command: 'missing', title: '<<MISSING COMMAND>>' };
private _documents: ExtHostDocuments;
private _commands: ExtHostCommands;
private _commands: CommandsConverter;
private _heapService: ExtHostHeapService;
private _provider: vscode.CodeLensProvider;
private _cache: { [uri: string]: { version: number; data: TPromise<CachedCodeLens>; } } = Object.create(null);
constructor(documents: ExtHostDocuments, commands: ExtHostCommands, provider: vscode.CodeLensProvider) {
constructor(documents: ExtHostDocuments, commands: CommandsConverter, heapService: ExtHostHeapService, provider: vscode.CodeLensProvider) {
this._documents = documents;
this._commands = commands;
this._heapService = heapService;
this._provider = provider;
}
provideCodeLenses(resource: URI): TPromise<modes.ICodeLensSymbol[]> {
const doc = this._documents.getDocumentData(resource).document;
const version = doc.version;
const key = resource.toString();
// from cache
let entry = this._cache[key];
if (entry && entry.version === version) {
return new ShallowCancelThenPromise(entry.data.then(cached => cached.symbols));
}
return asWinJsPromise(token => this._provider.provideCodeLenses(doc, token)).then(lenses => {
const newCodeLensData = asWinJsPromise(token => this._provider.provideCodeLenses(doc, token)).then(lenses => {
if (!Array.isArray(lenses)) {
return;
}
const data: CachedCodeLens = {
lenses,
symbols: [],
disposables: [],
};
lenses.forEach((lens, i) => {
data.symbols.push(<modes.ICodeLensSymbol>{
id: String(i),
range: TypeConverters.fromRange(lens.range),
command: TypeConverters.Command.from(lens.command, data.disposables)
if (Array.isArray(lenses)) {
return lenses.map(lens => {
const id = this._heapService.keep(lens);
return ObjectIdentifier.mixin({
range: TypeConverters.fromRange(lens.range),
command: this._commands.toInternal(lens.command)
}, id);
});
});
return data;
});
this._cache[key] = {
version,
data: newCodeLensData
};
return new ShallowCancelThenPromise(newCodeLensData.then(newCached => {
if (entry) {
// only now dispose old commands et al
entry.data.then(oldCached => dispose(oldCached.disposables));
}
return newCached && newCached.symbols;
}));
});
}
resolveCodeLens(resource: URI, symbol: modes.ICodeLensSymbol): TPromise<modes.ICodeLensSymbol> {
const entry = this._cache[resource.toString()];
if (!entry) {
const lens = this._heapService.get<vscode.CodeLens>(ObjectIdentifier.of(symbol));
if (!lens) {
return;
}
return entry.data.then(cachedData => {
let resolve: TPromise<vscode.CodeLens>;
if (typeof this._provider.resolveCodeLens !== 'function' || lens.isResolved) {
resolve = TPromise.as(lens);
} else {
resolve = asWinJsPromise(token => this._provider.resolveCodeLens(lens, token));
}
if (!cachedData) {
return;
}
let lens = cachedData.lenses[Number(symbol.id)];
if (!lens) {
return;
}
let resolve: TPromise<vscode.CodeLens>;
if (typeof this._provider.resolveCodeLens !== 'function' || lens.isResolved) {
resolve = TPromise.as(lens);
} else {
resolve = asWinJsPromise(token => this._provider.resolveCodeLens(lens, token));
}
return resolve.then(newLens => {
lens = newLens || lens;
let command = lens.command;
if (!command) {
command = {
title: '<<MISSING COMMAND>>',
command: 'missing',
};
}
symbol.command = TypeConverters.Command.from(command, cachedData.disposables);
return symbol;
});
return resolve.then(newLens => {
newLens = newLens || lens;
symbol.command = this._commands.toInternal(newLens.command || CodeLensAdapter._badCmd);
return symbol;
});
}
}
@@ -280,13 +224,11 @@ class ReferenceAdapter {
class QuickFixAdapter {
private _documents: ExtHostDocuments;
private _commands: ExtHostCommands;
private _commands: CommandsConverter;
private _diagnostics: ExtHostDiagnostics;
private _provider: vscode.CodeActionProvider;
private _cachedCommands: IDisposable[][] = [];
constructor(documents: ExtHostDocuments, commands: ExtHostCommands, diagnostics: ExtHostDiagnostics, provider: vscode.CodeActionProvider) {
constructor(documents: ExtHostDocuments, commands: CommandsConverter, diagnostics: ExtHostDiagnostics, heapService: ExtHostHeapService, provider: vscode.CodeActionProvider) {
this._documents = documents;
this._commands = commands;
this._diagnostics = diagnostics;
@@ -309,23 +251,13 @@ class QuickFixAdapter {
}
});
// we cache the last 10 commands that might have been
// created during type conversion. when as have more
// than 10 we drop the first three
const cachedCommands: IDisposable[] = [];
if (this._cachedCommands.push(cachedCommands) > 10) {
dispose(...this._cachedCommands.shift());
dispose(...this._cachedCommands.shift());
dispose(...this._cachedCommands.shift());
}
return asWinJsPromise(token => this._provider.provideCodeActions(doc, ran, { diagnostics: allDiagnostics }, token)).then(commands => {
if (!Array.isArray(commands)) {
return;
}
return commands.map((command, i) => {
return <modes.CodeAction>{
command: TypeConverters.Command.from(command, cachedCommands),
command: this._commands.toInternal(command),
score: i
};
});
@@ -433,7 +365,7 @@ class NavigateTypeAdapter implements IWorkspaceSymbolProvider {
return TPromise.as(item);
}
const symbolInfo = this._heapService.get<vscode.SymbolInformation>(ObjectIdentifier.get(item));
const symbolInfo = this._heapService.get<vscode.SymbolInformation>(ObjectIdentifier.of(item));
if (symbolInfo) {
return asWinJsPromise(token => this._provider.resolveWorkspaceSymbol(symbolInfo, token)).then(value => {
return value && TypeConverters.fromSymbolInformation(value);
@@ -494,12 +426,13 @@ class RenameAdapter {
class SuggestAdapter {
private _documents: ExtHostDocuments;
private _commands: CommandsConverter;
private _heapService: ExtHostHeapService;
private _provider: vscode.CompletionItemProvider;
private _disposables: { [id: number]: IDisposable[] } = [];
constructor(documents: ExtHostDocuments, heapService: ExtHostHeapService, provider: vscode.CompletionItemProvider) {
constructor(documents: ExtHostDocuments, commands: CommandsConverter, heapService: ExtHostHeapService, provider: vscode.CompletionItemProvider) {
this._documents = documents;
this._commands = commands;
this._heapService = heapService;
this._provider = provider;
}
@@ -535,11 +468,9 @@ class SuggestAdapter {
for (let i = 0; i < list.items.length; i++) {
const item = list.items[i];
const disposables: IDisposable[] = [];
const suggestion = TypeConverters.Suggest.from(item, disposables);
const id = this._heapService.keep(item, () => dispose(this._disposables[id]));
this._disposables[id] = disposables;
ObjectIdentifier.mixin(suggestion, id);
const suggestion = TypeConverters.Suggest.from(item);
suggestion.command = this._commands.toInternal(item.command);
ObjectIdentifier.mixin(suggestion, this._heapService.keep(item));
if (item.textEdit) {
@@ -577,13 +508,16 @@ class SuggestAdapter {
return TPromise.as(suggestion);
}
const id = ObjectIdentifier.get(suggestion);
const id = ObjectIdentifier.of(suggestion);
const item = this._heapService.get<CompletionItem>(id);
if (!item) {
return TPromise.as(suggestion);
}
return asWinJsPromise(token => this._provider.resolveCompletionItem(item, token)).then(resolvedItem => {
return TypeConverters.Suggest.from(resolvedItem || item, this._disposables[id]);
resolvedItem = resolvedItem || item;
const suggestion = TypeConverters.Suggest.from(resolvedItem);
suggestion.command = this._commands.toInternal(resolvedItem.command);
return suggestion;
});
}
}
@@ -709,7 +643,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter[handle] = new CodeLensAdapter(this._documents, this._commands, provider);
this._adapter[handle] = new CodeLensAdapter(this._documents, this._commands.converter, this._heapService, provider);
this._proxy.$registerCodeLensSupport(handle, selector);
return this._createDisposable(handle);
}
@@ -778,7 +712,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
registerCodeActionProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter[handle] = new QuickFixAdapter(this._documents, this._commands, this._diagnostics, provider);
this._adapter[handle] = new QuickFixAdapter(this._documents, this._commands.converter, this._diagnostics, this._heapService, provider);
this._proxy.$registerQuickFixSupport(handle, selector);
return this._createDisposable(handle);
}
@@ -856,7 +790,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
registerCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, triggerCharacters: string[]): vscode.Disposable {
const handle = this._nextHandle();
this._adapter[handle] = new SuggestAdapter(this._documents, this._heapService, provider);
this._adapter[handle] = new SuggestAdapter(this._documents, this._commands.converter, this._heapService, provider);
this._proxy.$registerSuggestSupport(handle, selector, triggerCharacters);
return this._createDisposable(handle);
}