提交 3fbe07bc 编写于 作者: J Johannes Rieken

some gc sync'ing between main and ext host

上级 50487cf2
declare module 'gc-signals' {
export interface GCSignal {
}
/**
* Create a new GC signal. When being garbage collected the passed
* value is stored for later consumption.
*/
export const GCSignal: {
new (id: number): GCSignal;
};
/**
* Consume ids of garbage collected signals.
*/
export function consumeSignals(): number[];
export function onDidGarbageCollectSignals(callback: (ids: number[]) => any): {
dispose(): void;
};
export function trackGarbageCollection(obj: any, id: number): number;
}
\ No newline at end of file
......@@ -17,6 +17,7 @@ import {ExtHostConfiguration} from 'vs/workbench/api/node/extHostConfiguration';
import {ExtHostDiagnostics} from 'vs/workbench/api/node/extHostDiagnostics';
import {ExtHostWorkspace} from 'vs/workbench/api/node/extHostWorkspace';
import {ExtHostQuickOpen} from 'vs/workbench/api/node/extHostQuickOpen';
import {ExtHostHeapMonitor} from 'vs/workbench/api/node/extHostHeapMonitor';
import {ExtHostStatusBar} from 'vs/workbench/api/node/extHostStatusBar';
import {ExtHostCommands} from 'vs/workbench/api/node/extHostCommands';
import {ExtHostOutputService} from 'vs/workbench/api/node/extHostOutputService';
......@@ -99,12 +100,13 @@ export class ExtHostAPIImplementation {
// Addressable instances
const col = new InstanceCollection();
const extHostHeapMonitor = col.define(ExtHostContext.ExtHostHeapMonitor).set<ExtHostHeapMonitor>(new ExtHostHeapMonitor());
const extHostDocuments = col.define(ExtHostContext.ExtHostDocuments).set<ExtHostDocuments>(new ExtHostDocuments(threadService));
const extHostEditors = col.define(ExtHostContext.ExtHostEditors).set<ExtHostEditors>(new ExtHostEditors(threadService, extHostDocuments));
const extHostCommands = col.define(ExtHostContext.ExtHostCommands).set<ExtHostCommands>(new ExtHostCommands(threadService, extHostEditors));
const extHostConfiguration = col.define(ExtHostContext.ExtHostConfiguration).set<ExtHostConfiguration>(new ExtHostConfiguration(threadService.get(MainContext.MainThreadConfiguration)));
const extHostDiagnostics = col.define(ExtHostContext.ExtHostDiagnostics).set<ExtHostDiagnostics>(new ExtHostDiagnostics(threadService));
const languageFeatures = col.define(ExtHostContext.ExtHostLanguageFeatures).set<ExtHostLanguageFeatures>(new ExtHostLanguageFeatures(threadService, extHostDocuments, extHostCommands, extHostDiagnostics));
const languageFeatures = col.define(ExtHostContext.ExtHostLanguageFeatures).set<ExtHostLanguageFeatures>(new ExtHostLanguageFeatures(threadService, extHostDocuments, extHostCommands, extHostHeapMonitor, extHostDiagnostics));
const extHostFileSystemEvent = col.define(ExtHostContext.ExtHostFileSystemEventService).set<ExtHostFileSystemEventService>(new ExtHostFileSystemEventService());
const extHostQuickOpen = col.define(ExtHostContext.ExtHostQuickOpen).set<ExtHostQuickOpen>(new ExtHostQuickOpen(threadService));
col.define(ExtHostContext.ExtHostExtensionService).set(extensionService);
......
......@@ -32,6 +32,7 @@ import {MainThreadTerminalService} from './mainThreadTerminalService';
import {MainThreadWorkspace} from './mainThreadWorkspace';
import {MainProcessExtensionService} from './mainThreadExtensionService';
import {MainThreadFileSystemEventService} from './mainThreadFileSystemEventService';
import {MainThreadHeapMonitor} from './mainThreadHeapMonitor';
// --- other interested parties
import {MainProcessTextMateSyntax} from 'vs/editor/node/textMate/TMSyntax';
......@@ -87,6 +88,7 @@ export class ExtHostContribution implements IWorkbenchContribution {
create(JSONValidationExtensionPoint);
create(LanguageConfigurationFileHandler);
create(MainThreadFileSystemEventService);
create(MainThreadHeapMonitor);
}
}
......
......@@ -265,6 +265,10 @@ export abstract class ExtHostFileSystemEventServiceShape {
$onFileEvent(events: FileSystemEvents) { throw ni(); }
}
export abstract class ExtHostHeapMonitorShape {
$onGarbageCollection(ids: number[]): void { throw ni(); }
}
export abstract class ExtHostLanguageFeaturesShape {
$provideDocumentSymbols(handle: number, resource: URI): TPromise<modes.SymbolInformation[]> { throw ni(); }
$provideCodeLenses(handle: number, resource: URI): TPromise<modes.ICodeLensSymbol[]> { throw ni(); }
......@@ -321,6 +325,7 @@ export const ExtHostContext = {
ExtHostDocuments: createExtId<ExtHostDocumentsShape>('ExtHostDocuments', ExtHostDocumentsShape),
ExtHostEditors: createExtId<ExtHostEditorsShape>('ExtHostEditors', ExtHostEditorsShape),
ExtHostFileSystemEventService: createExtId<ExtHostFileSystemEventServiceShape>('ExtHostFileSystemEventService', ExtHostFileSystemEventServiceShape),
ExtHostHeapMonitor: createExtId<ExtHostHeapMonitorShape>('ExtHostHeapMonitor', ExtHostHeapMonitorShape),
ExtHostLanguageFeatures: createExtId<ExtHostLanguageFeaturesShape>('ExtHostLanguageFeatures', ExtHostLanguageFeaturesShape),
ExtHostQuickOpen: createExtId<ExtHostQuickOpenShape>('ExtHostQuickOpen', ExtHostQuickOpenShape),
ExtHostExtensionService: createExtId<ExtHostExtensionServiceShape>('ExtHostExtensionService', ExtHostExtensionServiceShape),
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {ExtHostHeapMonitorShape} from './extHost.protocol';
export class ExtHostHeapMonitor extends ExtHostHeapMonitorShape {
private static _idPool = 0;
private _data: { [n: number]: any } = Object.create(null);
private _callbacks: { [n: number]: Function } = Object.create(null);
private _mixinObjectIdentifier(obj: any): number {
const id = ExtHostHeapMonitor._idPool++;
Object.defineProperties(obj, {
'$heap_ident': {
value: id,
enumerable: true,
configurable: false,
writable: false
},
'$mid': {
value: 3,
enumerable: true,
configurable: false,
writable: false
}
});
return id;
}
linkObjects(external: any, internal: any, callback?: () => any) {
const id = this._mixinObjectIdentifier(external);
this._data[id] = internal;
if (typeof callback === 'function') {
this._callbacks[id] = callback;
}
}
getInternalObject<T>(external: any): T {
const id = external.$heap_ident;
if (typeof id === 'number') {
return this._data[id];
}
}
$onGarbageCollection(ids: number[]): void {
for (const id of ids) {
delete this._data[id];
const callback = this._callbacks[id];
if (callback) {
delete this._callbacks[id];
setTimeout(callback);
}
}
}
}
\ No newline at end of file
......@@ -10,9 +10,10 @@ 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';
import {Range, Disposable, CompletionList} from 'vs/workbench/api/node/extHostTypes';
import {Range, Disposable, CompletionList, CompletionItem} from 'vs/workbench/api/node/extHostTypes';
import {IPosition, IRange, ISingleEditOperation} from 'vs/editor/common/editorCommon';
import * as modes from 'vs/editor/common/modes';
import {ExtHostHeapMonitor} from 'vs/workbench/api/node/extHostHeapMonitor';
import {ExtHostDocuments} from 'vs/workbench/api/node/extHostDocuments';
import {ExtHostCommands} from 'vs/workbench/api/node/extHostCommands';
import {ExtHostDiagnostics} from 'vs/workbench/api/node/extHostDiagnostics';
......@@ -503,11 +504,12 @@ interface ISuggestion2 extends modes.ISuggestion {
class SuggestAdapter {
private _documents: ExtHostDocuments;
private _heapMonitor: ExtHostHeapMonitor;
private _provider: vscode.CompletionItemProvider;
private _cache: { [key: string]: { list: CompletionList; disposables: IDisposable[]; } } = Object.create(null);
constructor(documents: ExtHostDocuments, provider: vscode.CompletionItemProvider) {
constructor(documents: ExtHostDocuments, heapMonitor: ExtHostHeapMonitor, provider: vscode.CompletionItemProvider) {
this._documents = documents;
this._heapMonitor = heapMonitor;
this._provider = provider;
}
......@@ -516,12 +518,6 @@ class SuggestAdapter {
const doc = this._documents.getDocumentData(resource).document;
const pos = TypeConverters.toPosition(position);
const key = resource.toString();
if (this._cache[key]) {
dispose(this._cache[key].disposables);
delete this._cache[key];
}
return asWinJsPromise<vscode.CompletionItem[]|vscode.CompletionList>(token => this._provider.provideCompletionItems(doc, pos, token)).then(value => {
const result: modes.ISuggestResult = {
......@@ -533,7 +529,6 @@ class SuggestAdapter {
const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) || new Range(pos, pos))
.with({ end: pos });
const disposables: IDisposable[] = [];
let list: CompletionList;
if (!value) {
// undefined and null are valid results
......@@ -550,8 +545,11 @@ class SuggestAdapter {
for (let i = 0; i < list.items.length; i++) {
const item = list.items[i];
const disposables: IDisposable[] = [];
const suggestion = <ISuggestion2> TypeConverters.Suggest.from(item, disposables);
this._heapMonitor.linkObjects(suggestion, item, () => dispose(disposables));
if (item.textEdit) {
const editRange = item.textEdit.range;
......@@ -581,25 +579,22 @@ class SuggestAdapter {
result.suggestions.push(suggestion);
}
// cache for details call
this._cache[key] = { list, disposables };
return result;
});
}
resolveCompletionItem(resource: URI, position: IPosition, suggestion: modes.ISuggestion): TPromise<modes.ISuggestion> {
if (typeof this._provider.resolveCompletionItem !== 'function' || !this._cache[resource.toString()]) {
if (typeof this._provider.resolveCompletionItem !== 'function') {
return TPromise.as(suggestion);
}
const {list, disposables} = this._cache[resource.toString()];
const item = list.items[Number((<ISuggestion2> suggestion).id)];
const item = this._heapMonitor.getInternalObject<CompletionItem>(suggestion);
if (!item) {
return TPromise.as(suggestion);
}
return asWinJsPromise(token => this._provider.resolveCompletionItem(item, token)).then(resolvedItem => {
return TypeConverters.Suggest.from(resolvedItem || item, disposables);
return <ISuggestion2> TypeConverters.Suggest.from(resolvedItem || item, []);
});
}
}
......@@ -670,6 +665,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
private _proxy: MainThreadLanguageFeaturesShape;
private _documents: ExtHostDocuments;
private _commands: ExtHostCommands;
private _heapMonitor: ExtHostHeapMonitor;
private _diagnostics: ExtHostDiagnostics;
private _adapter: { [handle: number]: Adapter } = Object.create(null);
......@@ -677,12 +673,14 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
threadService: IThreadService,
documents: ExtHostDocuments,
commands: ExtHostCommands,
heapMonitor: ExtHostHeapMonitor,
diagnostics: ExtHostDiagnostics
) {
super();
this._proxy = threadService.get(MainContext.MainThreadLanguageFeatures);
this._documents = documents;
this._commands = commands;
this._heapMonitor = heapMonitor;
this._diagnostics = diagnostics;
}
......@@ -869,7 +867,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, provider);
this._adapter[handle] = new SuggestAdapter(this._documents, this._heapMonitor, provider);
this._proxy.$registerSuggestSupport(handle, selector, triggerCharacters);
return this._createDisposable(handle);
}
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {IDisposable} from 'vs/base/common/lifecycle';
import {IThreadService} from 'vs/workbench/services/thread/common/threadService';
import {ExtHostContext} from './extHost.protocol';
import {onDidGarbageCollectSignals, consumeSignals, trackGarbageCollection} from 'gc-signals';
export class MainThreadHeapMonitor {
private _subscription: IDisposable;
private _consumeHandle: number;
constructor( @IThreadService threadService: IThreadService) {
const proxy = threadService.get(ExtHostContext.ExtHostHeapMonitor);
this._subscription = onDidGarbageCollectSignals(ids => {
proxy.$onGarbageCollection(ids);
});
this._consumeHandle = setInterval(consumeSignals, 15 * 1000);
}
dispose() {
clearInterval(this._consumeHandle);
this._subscription.dispose();
}
trackObject(obj: any) {
if (typeof obj.$heap_ident === 'number') {
trackGarbageCollection(obj, obj.$heap_ident);
}
}
}
\ No newline at end of file
......@@ -17,6 +17,7 @@ import {Position as EditorPosition} from 'vs/editor/common/core/position';
import {Range as EditorRange} from 'vs/editor/common/core/range';
import {ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape} from './extHost.protocol';
import {LanguageConfigurationRegistry, LanguageConfiguration} from 'vs/editor/common/modes/languageConfigurationRegistry';
import {trackGarbageCollection} from 'gc-signals';
export class MainThreadLanguageFeatures extends MainThreadLanguageFeaturesShape {
......@@ -180,7 +181,12 @@ export class MainThreadLanguageFeatures extends MainThreadLanguageFeaturesShape
this._registrations[handle] = modes.SuggestRegistry.register(selector, <modes.ISuggestSupport>{
triggerCharacters: triggerCharacters,
provideCompletionItems: (model:IReadOnlyModel, position:EditorPosition, token:CancellationToken): Thenable<modes.ISuggestResult> => {
return wireCancellationToken(token, this._proxy.$provideCompletionItems(handle, model.uri, position));
return wireCancellationToken(token, this._proxy.$provideCompletionItems(handle, model.uri, position)).then(result => {
for (const suggestion of result.suggestions) {
trackGarbageCollection(suggestion, (<any>suggestion).$heap_ident);
}
return result;
});
},
resolveCompletionItem: (model:IReadOnlyModel, position:EditorPosition, suggestion: modes.ISuggestion, token: CancellationToken): Thenable<modes.ISuggestion> => {
return wireCancellationToken(token, this._proxy.$resolveCompletionItem(handle, model.uri, position, suggestion));
......
......@@ -23,6 +23,7 @@ import {ExtHostLanguageFeatures} from 'vs/workbench/api/node/extHostLanguageFeat
import {MainThreadLanguageFeatures} from 'vs/workbench/api/node/mainThreadLanguageFeatures';
import {registerApiCommands} from 'vs/workbench/api/node/extHostApiCommands';
import {ExtHostCommands} from 'vs/workbench/api/node/extHostCommands';
import {ExtHostHeapMonitor} from 'vs/workbench/api/node/extHostHeapMonitor';
import {MainThreadCommands} from 'vs/workbench/api/node/mainThreadCommands';
import {ExtHostDocuments} from 'vs/workbench/api/node/extHostDocuments';
import * as ExtHostTypeConverters from 'vs/workbench/api/node/extHostTypeConverters';
......@@ -108,7 +109,7 @@ suite('ExtHostLanguageFeatureCommands', function() {
const diagnostics = new ExtHostDiagnostics(threadService);
threadService.set(ExtHostContext.ExtHostDiagnostics, diagnostics);
extHost = new ExtHostLanguageFeatures(threadService, extHostDocuments, commands, diagnostics);
extHost = new ExtHostLanguageFeatures(threadService, extHostDocuments, commands, new ExtHostHeapMonitor(), diagnostics);
threadService.set(ExtHostContext.ExtHostLanguageFeatures, extHost);
mainThread = threadService.setTestInstance(MainContext.MainThreadLanguageFeatures, instantiationService.createInstance(MainThreadLanguageFeatures));
......
......@@ -39,6 +39,7 @@ import {getLinks} from 'vs/editor/contrib/links/common/links';
import {asWinJsPromise} from 'vs/base/common/async';
import {MainContext, ExtHostContext} from 'vs/workbench/api/node/extHost.protocol';
import {ExtHostDiagnostics} from 'vs/workbench/api/node/extHostDiagnostics';
import {ExtHostHeapMonitor} from 'vs/workbench/api/node/extHostHeapMonitor';
const defaultSelector = { scheme: 'far' };
const model: EditorCommon.IModel = EditorModel.createFromString(
......@@ -97,7 +98,7 @@ suite('ExtHostLanguageFeatures', function() {
const diagnostics = new ExtHostDiagnostics(threadService);
threadService.set(ExtHostContext.ExtHostDiagnostics, diagnostics);
extHost = new ExtHostLanguageFeatures(threadService, extHostDocuments, commands, diagnostics);
extHost = new ExtHostLanguageFeatures(threadService, extHostDocuments, commands, new ExtHostHeapMonitor(), diagnostics);
threadService.set(ExtHostContext.ExtHostLanguageFeatures, extHost);
mainThread = <MainThreadLanguageFeatures>threadService.setTestInstance(MainContext.MainThreadLanguageFeatures, instantiationService.createInstance(MainThreadLanguageFeatures));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册