feat: implement web-tracing-framework support
This includes implementation and minimal instrumentation Closes #2610
This commit is contained in:
parent
6d272cc5f9
commit
77875a270d
|
@ -15,3 +15,4 @@ export * from './directives';
|
||||||
export * from './http';
|
export * from './http';
|
||||||
export * from './forms';
|
export * from './forms';
|
||||||
export * from './render';
|
export * from './render';
|
||||||
|
export * from './profile';
|
||||||
|
|
|
@ -6,3 +6,4 @@ export * from './directives';
|
||||||
export * from './http';
|
export * from './http';
|
||||||
export * from './forms';
|
export * from './forms';
|
||||||
export * from './render';
|
export * from './render';
|
||||||
|
export * from './profile';
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
export {
|
||||||
|
wtfCreateScope,
|
||||||
|
wtfLeave,
|
||||||
|
wtfStartTimeRange,
|
||||||
|
wtfEndTimeRange,
|
||||||
|
WtfScopeFn
|
||||||
|
} from './src/profile/profile';
|
|
@ -14,6 +14,9 @@ import {BindingRecord} from './binding_record';
|
||||||
import {Locals} from './parser/locals';
|
import {Locals} from './parser/locals';
|
||||||
import {Pipes} from './pipes/pipes';
|
import {Pipes} from './pipes/pipes';
|
||||||
import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants';
|
import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants';
|
||||||
|
import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../profile/profile';
|
||||||
|
|
||||||
|
var _scope_check: WtfScopeFn = wtfCreateScope(`ChangeDetector#check(ascii id, bool throwOnChange)`);
|
||||||
|
|
||||||
class _Context {
|
class _Context {
|
||||||
constructor(public element: any, public componentElement: any, public instance: any,
|
constructor(public element: any, public componentElement: any, public instance: any,
|
||||||
|
@ -69,16 +72,13 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||||
|
|
||||||
runDetectChanges(throwOnChange: boolean): void {
|
runDetectChanges(throwOnChange: boolean): void {
|
||||||
if (this.mode === DETACHED || this.mode === CHECKED) return;
|
if (this.mode === DETACHED || this.mode === CHECKED) return;
|
||||||
|
var s = _scope_check(this.id, throwOnChange);
|
||||||
this.detectChangesInRecords(throwOnChange);
|
this.detectChangesInRecords(throwOnChange);
|
||||||
|
|
||||||
this._detectChangesInLightDomChildren(throwOnChange);
|
this._detectChangesInLightDomChildren(throwOnChange);
|
||||||
|
|
||||||
if (throwOnChange === false) this.callOnAllChangesDone();
|
if (throwOnChange === false) this.callOnAllChangesDone();
|
||||||
|
|
||||||
this._detectChangesInShadowDomChildren(throwOnChange);
|
this._detectChangesInShadowDomChildren(throwOnChange);
|
||||||
|
|
||||||
if (this.mode === CHECK_ONCE) this.mode = CHECKED;
|
if (this.mode === CHECK_ONCE) this.mode = CHECKED;
|
||||||
|
wtfLeave(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method is not intended to be overridden. Subclasses should instead provide an
|
// This method is not intended to be overridden. Subclasses should instead provide an
|
||||||
|
|
|
@ -71,6 +71,7 @@ import {
|
||||||
} from 'angular2/src/render/dom/view/shared_styles_host';
|
} from 'angular2/src/render/dom/view/shared_styles_host';
|
||||||
import {internalView} from 'angular2/src/core/compiler/view_ref';
|
import {internalView} from 'angular2/src/core/compiler/view_ref';
|
||||||
import {appComponentRefPromiseToken, appComponentTypeToken} from './application_tokens';
|
import {appComponentRefPromiseToken, appComponentTypeToken} from './application_tokens';
|
||||||
|
import {wtfInit} from '../profile/wtf_init';
|
||||||
|
|
||||||
var _rootInjector: Injector;
|
var _rootInjector: Injector;
|
||||||
|
|
||||||
|
@ -290,6 +291,7 @@ export function commonBootstrap(
|
||||||
appComponentType: /*Type*/ any,
|
appComponentType: /*Type*/ any,
|
||||||
componentInjectableBindings: List<Type | Binding | List<any>> = null): Promise<ApplicationRef> {
|
componentInjectableBindings: List<Type | Binding | List<any>> = null): Promise<ApplicationRef> {
|
||||||
BrowserDomAdapter.makeCurrent();
|
BrowserDomAdapter.makeCurrent();
|
||||||
|
wtfInit();
|
||||||
var bootstrapProcess = PromiseWrapper.completer();
|
var bootstrapProcess = PromiseWrapper.completer();
|
||||||
var zone = createNgZone(new ExceptionHandler(DOM, isDart ? false : true));
|
var zone = createNgZone(new ExceptionHandler(DOM, isDart ? false : true));
|
||||||
zone.run(() => {
|
zone.run(() => {
|
||||||
|
|
|
@ -25,6 +25,7 @@ import {ProtoViewFactory} from './proto_view_factory';
|
||||||
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
||||||
import {AppRootUrl} from 'angular2/src/services/app_root_url';
|
import {AppRootUrl} from 'angular2/src/services/app_root_url';
|
||||||
import {ElementBinder} from './element_binder';
|
import {ElementBinder} from './element_binder';
|
||||||
|
import {wtfStartTimeRange, wtfEndTimeRange} from '../../profile/profile';
|
||||||
|
|
||||||
import * as renderApi from 'angular2/src/render/api';
|
import * as renderApi from 'angular2/src/render/api';
|
||||||
|
|
||||||
|
@ -127,6 +128,7 @@ export class Compiler {
|
||||||
compileInHost(componentTypeOrBinding: Type | Binding): Promise<ProtoViewRef> {
|
compileInHost(componentTypeOrBinding: Type | Binding): Promise<ProtoViewRef> {
|
||||||
var componentType = isType(componentTypeOrBinding) ? componentTypeOrBinding :
|
var componentType = isType(componentTypeOrBinding) ? componentTypeOrBinding :
|
||||||
(<Binding>componentTypeOrBinding).token;
|
(<Binding>componentTypeOrBinding).token;
|
||||||
|
var r = wtfStartTimeRange('Compiler#compile()', stringify(componentType));
|
||||||
|
|
||||||
var hostAppProtoView = this._compilerCache.getHost(componentType);
|
var hostAppProtoView = this._compilerCache.getHost(componentType);
|
||||||
var hostPvPromise;
|
var hostPvPromise;
|
||||||
|
@ -149,7 +151,10 @@ export class Compiler {
|
||||||
return appProtoView;
|
return appProtoView;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return hostPvPromise.then(hostAppProtoView => hostAppProtoView.ref);
|
return hostPvPromise.then((hostAppProtoView) => {
|
||||||
|
wtfEndTimeRange(r);
|
||||||
|
return hostAppProtoView.ref;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _compile(componentBinding: DirectiveBinding,
|
private _compile(componentBinding: DirectiveBinding,
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {
|
||||||
import {AppViewManagerUtils} from './view_manager_utils';
|
import {AppViewManagerUtils} from './view_manager_utils';
|
||||||
import {AppViewPool} from './view_pool';
|
import {AppViewPool} from './view_pool';
|
||||||
import {AppViewListener} from './view_listener';
|
import {AppViewListener} from './view_listener';
|
||||||
|
import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../../profile/profile';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entry point for creating, moving views in the view hierarchy and destroying views.
|
* Entry point for creating, moving views in the view hierarchy and destroying views.
|
||||||
|
@ -83,6 +84,7 @@ export class AppViewManager {
|
||||||
return this._utils.getComponentInstance(hostView, boundElementIndex);
|
return this._utils.getComponentInstance(hostView, boundElementIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_scope_createRootHostView: WtfScopeFn = wtfCreateScope('AppViewManager#createRootHostView()');
|
||||||
/**
|
/**
|
||||||
* Load component view into existing element.
|
* Load component view into existing element.
|
||||||
*
|
*
|
||||||
|
@ -139,6 +141,7 @@ export class AppViewManager {
|
||||||
*/
|
*/
|
||||||
createRootHostView(hostProtoViewRef: ProtoViewRef, overrideSelector: string,
|
createRootHostView(hostProtoViewRef: ProtoViewRef, overrideSelector: string,
|
||||||
injector: Injector): HostViewRef {
|
injector: Injector): HostViewRef {
|
||||||
|
var s = this._scope_createRootHostView();
|
||||||
var hostProtoView: viewModule.AppProtoView = internalProtoView(hostProtoViewRef);
|
var hostProtoView: viewModule.AppProtoView = internalProtoView(hostProtoViewRef);
|
||||||
var hostElementSelector = overrideSelector;
|
var hostElementSelector = overrideSelector;
|
||||||
if (isBlank(hostElementSelector)) {
|
if (isBlank(hostElementSelector)) {
|
||||||
|
@ -151,38 +154,45 @@ export class AppViewManager {
|
||||||
|
|
||||||
this._renderer.hydrateView(hostView.render);
|
this._renderer.hydrateView(hostView.render);
|
||||||
this._utils.hydrateRootHostView(hostView, injector);
|
this._utils.hydrateRootHostView(hostView, injector);
|
||||||
|
return wtfLeave(s, hostView.ref);
|
||||||
return hostView.ref;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_scope_destroyRootHostView: WtfScopeFn = wtfCreateScope('AppViewManager#destroyRootHostView()');
|
||||||
/**
|
/**
|
||||||
* Remove the View created with {@link AppViewManager#createRootHostView}.
|
* Remove the View created with {@link AppViewManager#createRootHostView}.
|
||||||
*/
|
*/
|
||||||
destroyRootHostView(hostViewRef: HostViewRef) {
|
destroyRootHostView(hostViewRef: HostViewRef) {
|
||||||
// Note: Don't put the hostView into the view pool
|
// Note: Don't put the hostView into the view pool
|
||||||
// as it is depending on the element for which it was created.
|
// as it is depending on the element for which it was created.
|
||||||
|
var s = this._scope_destroyRootHostView();
|
||||||
var hostView = internalView(<ViewRef>hostViewRef);
|
var hostView = internalView(<ViewRef>hostViewRef);
|
||||||
this._renderer.detachFragment(hostView.renderFragment);
|
this._renderer.detachFragment(hostView.renderFragment);
|
||||||
this._renderer.dehydrateView(hostView.render);
|
this._renderer.dehydrateView(hostView.render);
|
||||||
this._viewDehydrateRecurse(hostView);
|
this._viewDehydrateRecurse(hostView);
|
||||||
this._viewListener.viewDestroyed(hostView);
|
this._viewListener.viewDestroyed(hostView);
|
||||||
this._renderer.destroyView(hostView.render);
|
this._renderer.destroyView(hostView.render);
|
||||||
|
wtfLeave(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_scope_createEmbeddedViewInContainer: WtfScopeFn =
|
||||||
|
wtfCreateScope('AppViewManager#createEmbeddedViewInContainer()');
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* See {@link AppViewManager#destroyViewInContainer}.
|
* See {@link AppViewManager#destroyViewInContainer}.
|
||||||
*/
|
*/
|
||||||
createEmbeddedViewInContainer(viewContainerLocation: ElementRef, atIndex: number,
|
createEmbeddedViewInContainer(viewContainerLocation: ElementRef, atIndex: number,
|
||||||
templateRef: TemplateRef): ViewRef {
|
templateRef: TemplateRef): ViewRef {
|
||||||
|
var s = this._scope_createEmbeddedViewInContainer();
|
||||||
var protoView = internalProtoView(templateRef.protoViewRef);
|
var protoView = internalProtoView(templateRef.protoViewRef);
|
||||||
if (protoView.type !== ViewType.EMBEDDED) {
|
if (protoView.type !== ViewType.EMBEDDED) {
|
||||||
throw new BaseException('This method can only be called with embedded ProtoViews!');
|
throw new BaseException('This method can only be called with embedded ProtoViews!');
|
||||||
}
|
}
|
||||||
return this._createViewInContainer(viewContainerLocation, atIndex, protoView,
|
return wtfLeave(s, this._createViewInContainer(viewContainerLocation, atIndex, protoView,
|
||||||
templateRef.elementRef, null);
|
templateRef.elementRef, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_scope_createHostViewInContainer: WtfScopeFn =
|
||||||
|
wtfCreateScope('AppViewManager#createHostViewInContainer()');
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* See {@link AppViewManager#destroyViewInContainer}.
|
* See {@link AppViewManager#destroyViewInContainer}.
|
||||||
|
@ -190,12 +200,14 @@ export class AppViewManager {
|
||||||
createHostViewInContainer(viewContainerLocation: ElementRef, atIndex: number,
|
createHostViewInContainer(viewContainerLocation: ElementRef, atIndex: number,
|
||||||
protoViewRef: ProtoViewRef,
|
protoViewRef: ProtoViewRef,
|
||||||
imperativelyCreatedInjector: ResolvedBinding[]): HostViewRef {
|
imperativelyCreatedInjector: ResolvedBinding[]): HostViewRef {
|
||||||
|
var s = this._scope_createHostViewInContainer();
|
||||||
var protoView = internalProtoView(protoViewRef);
|
var protoView = internalProtoView(protoViewRef);
|
||||||
if (protoView.type !== ViewType.HOST) {
|
if (protoView.type !== ViewType.HOST) {
|
||||||
throw new BaseException('This method can only be called with host ProtoViews!');
|
throw new BaseException('This method can only be called with host ProtoViews!');
|
||||||
}
|
}
|
||||||
return this._createViewInContainer(viewContainerLocation, atIndex, protoView,
|
return wtfLeave(
|
||||||
viewContainerLocation, imperativelyCreatedInjector);
|
s, this._createViewInContainer(viewContainerLocation, atIndex, protoView,
|
||||||
|
viewContainerLocation, imperativelyCreatedInjector));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -243,22 +255,27 @@ export class AppViewManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_scope_destroyViewInContainer = wtfCreateScope('AppViewMananger#destroyViewInContainer()');
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* See {@link AppViewManager#createViewInContainer}.
|
* See {@link AppViewManager#createViewInContainer}.
|
||||||
*/
|
*/
|
||||||
destroyViewInContainer(viewContainerLocation: ElementRef, atIndex: number) {
|
destroyViewInContainer(viewContainerLocation: ElementRef, atIndex: number) {
|
||||||
|
var s = this._scope_destroyViewInContainer();
|
||||||
var parentView = internalView(viewContainerLocation.parentView);
|
var parentView = internalView(viewContainerLocation.parentView);
|
||||||
var boundElementIndex = viewContainerLocation.boundElementIndex;
|
var boundElementIndex = viewContainerLocation.boundElementIndex;
|
||||||
this._destroyViewInContainer(parentView, boundElementIndex, atIndex);
|
this._destroyViewInContainer(parentView, boundElementIndex, atIndex);
|
||||||
|
wtfLeave(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_scope_attachViewInContainer = wtfCreateScope('AppViewMananger#attachViewInContainer()');
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* See {@link AppViewManager#detachViewInContainer}.
|
* See {@link AppViewManager#detachViewInContainer}.
|
||||||
*/
|
*/
|
||||||
attachViewInContainer(viewContainerLocation: ElementRef, atIndex: number,
|
attachViewInContainer(viewContainerLocation: ElementRef, atIndex: number,
|
||||||
viewRef: ViewRef): ViewRef {
|
viewRef: ViewRef): ViewRef {
|
||||||
|
var s = this._scope_attachViewInContainer();
|
||||||
var view = internalView(viewRef);
|
var view = internalView(viewRef);
|
||||||
var parentView = internalView(viewContainerLocation.parentView);
|
var parentView = internalView(viewContainerLocation.parentView);
|
||||||
var boundElementIndex = viewContainerLocation.boundElementIndex;
|
var boundElementIndex = viewContainerLocation.boundElementIndex;
|
||||||
|
@ -270,21 +287,23 @@ export class AppViewManager {
|
||||||
// context view that might have been used.
|
// context view that might have been used.
|
||||||
this._utils.attachViewInContainer(parentView, boundElementIndex, null, null, atIndex, view);
|
this._utils.attachViewInContainer(parentView, boundElementIndex, null, null, atIndex, view);
|
||||||
this._attachRenderView(parentView, boundElementIndex, atIndex, view);
|
this._attachRenderView(parentView, boundElementIndex, atIndex, view);
|
||||||
return viewRef;
|
return wtfLeave(s, viewRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_scope_detachViewInContainer = wtfCreateScope('AppViewMananger#detachViewInContainer()');
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* See {@link AppViewManager#attachViewInContainer}.
|
* See {@link AppViewManager#attachViewInContainer}.
|
||||||
*/
|
*/
|
||||||
detachViewInContainer(viewContainerLocation: ElementRef, atIndex: number): ViewRef {
|
detachViewInContainer(viewContainerLocation: ElementRef, atIndex: number): ViewRef {
|
||||||
|
var s = this._scope_detachViewInContainer();
|
||||||
var parentView = internalView(viewContainerLocation.parentView);
|
var parentView = internalView(viewContainerLocation.parentView);
|
||||||
var boundElementIndex = viewContainerLocation.boundElementIndex;
|
var boundElementIndex = viewContainerLocation.boundElementIndex;
|
||||||
var viewContainer = parentView.viewContainers[boundElementIndex];
|
var viewContainer = parentView.viewContainers[boundElementIndex];
|
||||||
var view = viewContainer.views[atIndex];
|
var view = viewContainer.views[atIndex];
|
||||||
this._utils.detachViewInContainer(parentView, boundElementIndex, atIndex);
|
this._utils.detachViewInContainer(parentView, boundElementIndex, atIndex);
|
||||||
this._renderer.detachFragment(view.renderFragment);
|
this._renderer.detachFragment(view.renderFragment);
|
||||||
return view.ref;
|
return wtfLeave(s, view.ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
_createMainView(protoView: viewModule.AppProtoView,
|
_createMainView(protoView: viewModule.AppProtoView,
|
||||||
|
|
|
@ -2,6 +2,7 @@ import {Injectable} from 'angular2/di';
|
||||||
import {ChangeDetector} from 'angular2/src/change_detection/change_detection';
|
import {ChangeDetector} from 'angular2/src/change_detection/change_detection';
|
||||||
import {NgZone} from 'angular2/src/core/zone/ng_zone';
|
import {NgZone} from 'angular2/src/core/zone/ng_zone';
|
||||||
import {isPresent, BaseException} from 'angular2/src/facade/lang';
|
import {isPresent, BaseException} from 'angular2/src/facade/lang';
|
||||||
|
import {wtfLeave, wtfCreateScope, WtfScopeFn} from '../../profile/profile';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides access to explicitly trigger change detection in an application.
|
* Provides access to explicitly trigger change detection in an application.
|
||||||
|
@ -31,6 +32,8 @@ import {isPresent, BaseException} from 'angular2/src/facade/lang';
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class LifeCycle {
|
export class LifeCycle {
|
||||||
|
static _scope_tick: WtfScopeFn = wtfCreateScope('LifeCycle#tick()');
|
||||||
|
|
||||||
_changeDetector: ChangeDetector;
|
_changeDetector: ChangeDetector;
|
||||||
_enforceNoNewChanges: boolean;
|
_enforceNoNewChanges: boolean;
|
||||||
_runningTick: boolean = false;
|
_runningTick: boolean = false;
|
||||||
|
@ -71,6 +74,7 @@ export class LifeCycle {
|
||||||
throw new BaseException("LifeCycle.tick is called recursively");
|
throw new BaseException("LifeCycle.tick is called recursively");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var s = LifeCycle._scope_tick();
|
||||||
try {
|
try {
|
||||||
this._runningTick = true;
|
this._runningTick = true;
|
||||||
this._changeDetector.detectChanges();
|
this._changeDetector.detectChanges();
|
||||||
|
@ -79,6 +83,7 @@ export class LifeCycle {
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
this._runningTick = false;
|
this._runningTick = false;
|
||||||
|
wtfLeave(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import {List, ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
import {List, ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||||
import {normalizeBlank, isPresent, global} from 'angular2/src/facade/lang';
|
import {normalizeBlank, isPresent, global} from 'angular2/src/facade/lang';
|
||||||
|
import {wtfLeave, wtfCreateScope, WtfScopeFn} from '../../profile/profile';
|
||||||
|
|
||||||
|
|
||||||
export interface NgZoneZone extends Zone { _innerZone: boolean; }
|
export interface NgZoneZone extends Zone { _innerZone: boolean; }
|
||||||
|
|
||||||
|
@ -13,6 +15,9 @@ export interface NgZoneZone extends Zone { _innerZone: boolean; }
|
||||||
* `Zone`. The default `onTurnDone` runs the Angular change detection.
|
* `Zone`. The default `onTurnDone` runs the Angular change detection.
|
||||||
*/
|
*/
|
||||||
export class NgZone {
|
export class NgZone {
|
||||||
|
_zone_run_scope: WtfScopeFn = wtfCreateScope(`NgZone#run()`);
|
||||||
|
_zone_microtask: WtfScopeFn = wtfCreateScope(`NgZone#microtask()`);
|
||||||
|
|
||||||
// Code executed in _mountZone does not trigger the onTurnDone.
|
// Code executed in _mountZone does not trigger the onTurnDone.
|
||||||
_mountZone;
|
_mountZone;
|
||||||
// _innerZone is the child of _mountZone. Any code executed in this zone will trigger the
|
// _innerZone is the child of _mountZone. Any code executed in this zone will trigger the
|
||||||
|
@ -134,7 +139,12 @@ export class NgZone {
|
||||||
*/
|
*/
|
||||||
run(fn: () => any): any {
|
run(fn: () => any): any {
|
||||||
if (this._disabled) {
|
if (this._disabled) {
|
||||||
return fn();
|
var s = this._zone_run_scope();
|
||||||
|
try {
|
||||||
|
return fn();
|
||||||
|
} finally {
|
||||||
|
wtfLeave(s);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return this._innerZone.run(fn);
|
return this._innerZone.run(fn);
|
||||||
}
|
}
|
||||||
|
@ -165,6 +175,7 @@ export class NgZone {
|
||||||
}
|
}
|
||||||
|
|
||||||
_createInnerZone(zone, enableLongStackTrace) {
|
_createInnerZone(zone, enableLongStackTrace) {
|
||||||
|
var _zone_microtask = this._zone_microtask;
|
||||||
var ngZone = this;
|
var ngZone = this;
|
||||||
var errorHandling;
|
var errorHandling;
|
||||||
|
|
||||||
|
@ -217,10 +228,12 @@ export class NgZone {
|
||||||
return function(fn) {
|
return function(fn) {
|
||||||
ngZone._pendingMicrotasks++;
|
ngZone._pendingMicrotasks++;
|
||||||
var microtask = function() {
|
var microtask = function() {
|
||||||
|
var s = _zone_microtask();
|
||||||
try {
|
try {
|
||||||
fn();
|
fn();
|
||||||
} finally {
|
} finally {
|
||||||
ngZone._pendingMicrotasks--;
|
ngZone._pendingMicrotasks--;
|
||||||
|
wtfLeave(s);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
parentScheduleMicrotask.call(this, microtask);
|
parentScheduleMicrotask.call(this, microtask);
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
export {WtfScopeFn} from './wtf_impl';
|
||||||
|
|
||||||
|
import * as impl from "./wtf_impl";
|
||||||
|
|
||||||
|
// Change exports to const once https://github.com/angular/ts2dart/issues/150
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if WTF is enabled.
|
||||||
|
*/
|
||||||
|
export var wtfEnabled = impl.detectWTF();
|
||||||
|
|
||||||
|
function noopScope(arg0?: any, arg1?: any): any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create trace scope.
|
||||||
|
*
|
||||||
|
* Scopes must be strictly nested and are analogous to stack frames, but
|
||||||
|
* do not have to follow the stack frames. Instead it is recommended that they follow logical
|
||||||
|
* nesting. You may want to use
|
||||||
|
* [Event
|
||||||
|
* Signatures](http://google.github.io/tracing-framework/instrumenting-code.html#custom-events)
|
||||||
|
* as they are defined in WTF.
|
||||||
|
*
|
||||||
|
* Used to mark scope entry. The return value is used to leave the scope.
|
||||||
|
*
|
||||||
|
* final myScope = wtfCreateScope('MyClass#myMethod(ascii someVal)');
|
||||||
|
*
|
||||||
|
* someMethod() {
|
||||||
|
* var s = myScope('Foo'); // 'Foo' gets stored in tracing UI
|
||||||
|
* // DO SOME WORK HERE
|
||||||
|
* return wtfLeave(s, 123); // Return value 123
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Note, adding try-finally block around the work to ensure that `wtfLeave` gets called can
|
||||||
|
* negatively impact the performance of your application. For this reason we recommend that
|
||||||
|
* you don't add them to ensure that `wtfLeave` gets called. In production `wtfLeave` is a noop and
|
||||||
|
* so try-finally block has no value. When debugging perf issues, skipping `wtfLeave`, do to
|
||||||
|
* exception, will produce incorrect trace, but presence of exception signifies logic error which
|
||||||
|
* needs to be fixed before the app should be profiled. Add try-finally only when you expect that
|
||||||
|
* an exception is expected during normal execution while profiling.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export var wtfCreateScope: (signature: string, flags?: any) => impl.WtfScopeFn =
|
||||||
|
wtfEnabled ? impl.createScope : (signature: string, flags?: any) => noopScope;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to mark end of Scope.
|
||||||
|
*
|
||||||
|
* - `scope` to end.
|
||||||
|
* - `returnValue` (optional) to be passed to the WTF.
|
||||||
|
*
|
||||||
|
* Returns the `returnValue for easy chaining.
|
||||||
|
*/
|
||||||
|
export var wtfLeave:<T>(scope: any, returnValue?: T) => T =
|
||||||
|
wtfEnabled ? impl.leave : (s: any, r?: any) => r;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to mark Async start. Async are similar to scope but they don't have to be strictly nested.
|
||||||
|
* The return value is used in the call to [endAsync]. Async ranges only work if WTF has been
|
||||||
|
* enabled.
|
||||||
|
*
|
||||||
|
* someMethod() {
|
||||||
|
* var s = wtfStartTimeRange('HTTP:GET', 'some.url');
|
||||||
|
* var future = new Future.delay(5).then((_) {
|
||||||
|
* wtfEndTimeRange(s);
|
||||||
|
* });
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export var wtfStartTimeRange: (rangeType: string, action: string) => any =
|
||||||
|
wtfEnabled ? impl.startTimeRange : (rangeType: string, action: string) => null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ends a async time range operation.
|
||||||
|
* [range] is the return value from [wtfStartTimeRange] Async ranges only work if WTF has been
|
||||||
|
* enabled.
|
||||||
|
*/
|
||||||
|
export var wtfEndTimeRange: (range: any) => void = wtfEnabled ? impl.endTimeRange : (r: any) =>
|
||||||
|
null;
|
|
@ -0,0 +1,96 @@
|
||||||
|
/**
|
||||||
|
* Tracing for Dart applications.
|
||||||
|
*
|
||||||
|
* The tracing API hooks up to either [WTF](http://google.github.io/tracing-framework/) or
|
||||||
|
* [Dart Observatory](https://www.dartlang.org/tools/observatory/).
|
||||||
|
*/
|
||||||
|
library angular2.src.core.wtf_impl;
|
||||||
|
|
||||||
|
typedef dynamic WtfScopeFn([arg0, arg1]);
|
||||||
|
|
||||||
|
var context = null;
|
||||||
|
var _trace;
|
||||||
|
var _events;
|
||||||
|
var _createScope;
|
||||||
|
var _leaveScope;
|
||||||
|
var _beginTimeRange;
|
||||||
|
var _endTimeRange;
|
||||||
|
final List _arg1 = [null];
|
||||||
|
final List _arg2 = [null, null];
|
||||||
|
|
||||||
|
bool detectWTF() {
|
||||||
|
if (context != null && context.hasProperty('wtf')) {
|
||||||
|
var wtf = context['wtf'];
|
||||||
|
if (wtf.hasProperty('trace')) {
|
||||||
|
_trace = wtf['trace'];
|
||||||
|
_events = _trace['events'];
|
||||||
|
_createScope = _events['createScope'];
|
||||||
|
_leaveScope = _trace['leaveScope'];
|
||||||
|
_beginTimeRange = _trace['beginTimeRange'];
|
||||||
|
_endTimeRange = _trace['endTimeRange'];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getArgSize(String signature) {
|
||||||
|
int start = signature.indexOf('(') + 1;
|
||||||
|
int end = signature.indexOf(')', start);
|
||||||
|
bool found = false;
|
||||||
|
int count = 0;
|
||||||
|
for(var i = start; i < end; i++) {
|
||||||
|
var ch = signature[i];
|
||||||
|
if (identical(ch, ',')) {
|
||||||
|
found = false;
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
found = true;
|
||||||
|
count ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic createScope(String signature, [flags]) {
|
||||||
|
_arg2[0] = signature;
|
||||||
|
_arg2[1] = flags;
|
||||||
|
var jsScope = _createScope.apply(_arg2, thisArg: _events);
|
||||||
|
switch(getArgSize(signature)) {
|
||||||
|
case 0:
|
||||||
|
return ([arg0, arg1]) {
|
||||||
|
return jsScope.apply(const []);
|
||||||
|
};
|
||||||
|
case 1:
|
||||||
|
return ([arg0, arg1]) {
|
||||||
|
_arg1[0] = arg0;
|
||||||
|
return jsScope.apply(_arg1);
|
||||||
|
};
|
||||||
|
case 2:
|
||||||
|
return ([arg0, arg1]) {
|
||||||
|
_arg2[0] = arg0;
|
||||||
|
_arg2[1] = arg1;
|
||||||
|
return jsScope.apply(_arg1);
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
throw "Max 2 arguments are supported.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void leave(scope, [returnValue]) {
|
||||||
|
_arg2[0] = scope;
|
||||||
|
_arg2[1] = returnValue;
|
||||||
|
_leaveScope.apply(_arg2, thisArg: _trace);
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic startTimeRange(String rangeType, String action) {
|
||||||
|
_arg2[0] = rangeType;
|
||||||
|
_arg2[1] = action;
|
||||||
|
return _beginTimeRange.apply(_arg2, thisArg: _trace);
|
||||||
|
}
|
||||||
|
|
||||||
|
void endTimeRange(dynamic range) {
|
||||||
|
_arg1[0] = range;
|
||||||
|
_endTimeRange.apply(_arg1, thisArg: _trace);
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
import {global} from '../facade/lang';
|
||||||
|
|
||||||
|
export interface WtfScopeFn { (arg0?: any, arg1?: any): any; }
|
||||||
|
|
||||||
|
interface WTF {
|
||||||
|
trace: Trace;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Trace {
|
||||||
|
events: Events;
|
||||||
|
leaveScope(scope: Scope, returnValue: any);
|
||||||
|
beginTimeRange(rangeType: string, action: string): Range;
|
||||||
|
endTimeRange(range: Range);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Range {}
|
||||||
|
|
||||||
|
interface Events {
|
||||||
|
createScope(signature: string, flags: any): Scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Scope {
|
||||||
|
(...args): any;
|
||||||
|
}
|
||||||
|
|
||||||
|
var trace: Trace;
|
||||||
|
var events: Events;
|
||||||
|
|
||||||
|
export function detectWTF(): boolean {
|
||||||
|
var wtf: WTF = global['wtf'];
|
||||||
|
if (wtf) {
|
||||||
|
trace = wtf['trace'];
|
||||||
|
if (trace) {
|
||||||
|
events = trace['events'];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createScope(signature: string, flags: any = null): any {
|
||||||
|
return events.createScope(signature, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function leave<T>(scope: Scope, returnValue?: T): T {
|
||||||
|
trace.leaveScope(scope, returnValue);
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function startTimeRange(rangeType: string, action: string): Range {
|
||||||
|
return trace.beginTimeRange(rangeType, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function endTimeRange(range: Range): void {
|
||||||
|
trace.endTimeRange(range);
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
library angular2.src.core.wtf_init;
|
||||||
|
|
||||||
|
import 'dart:js' as js;
|
||||||
|
import 'wtf_impl.dart' as impl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Must be executed explicitly in Dart to set the JS Context.
|
||||||
|
*
|
||||||
|
* NOTE: this is done explicitly to allow WTF api not to depend on
|
||||||
|
* JS context and possible to run the noop WTF stubs outside the browser.
|
||||||
|
*/
|
||||||
|
wtfInit() {
|
||||||
|
impl.context = js.context;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* This is here because DART requires it. It is noop in JS.
|
||||||
|
*/
|
||||||
|
export function wtfInit() {}
|
|
@ -16,6 +16,7 @@ import {XHR} from 'angular2/src/render/xhr';
|
||||||
|
|
||||||
import {StyleInliner} from './style_inliner';
|
import {StyleInliner} from './style_inliner';
|
||||||
import {StyleUrlResolver} from './style_url_resolver';
|
import {StyleUrlResolver} from './style_url_resolver';
|
||||||
|
import {wtfStartTimeRange, wtfEndTimeRange} from '../../../profile/profile';
|
||||||
|
|
||||||
export class TemplateAndStyles {
|
export class TemplateAndStyles {
|
||||||
constructor(public template: string, public styles: string[]) {}
|
constructor(public template: string, public styles: string[]) {}
|
||||||
|
@ -33,6 +34,7 @@ export class ViewLoader {
|
||||||
private _styleUrlResolver: StyleUrlResolver) {}
|
private _styleUrlResolver: StyleUrlResolver) {}
|
||||||
|
|
||||||
load(viewDef: ViewDefinition): Promise<TemplateAndStyles> {
|
load(viewDef: ViewDefinition): Promise<TemplateAndStyles> {
|
||||||
|
var r = wtfStartTimeRange('ViewLoader#load()', stringify(viewDef.componentId));
|
||||||
let tplAndStyles: List<Promise<TemplateAndStyles>| Promise<string>| string> =
|
let tplAndStyles: List<Promise<TemplateAndStyles>| Promise<string>| string> =
|
||||||
[this._loadHtml(viewDef.template, viewDef.templateAbsUrl)];
|
[this._loadHtml(viewDef.template, viewDef.templateAbsUrl)];
|
||||||
if (isPresent(viewDef.styles)) {
|
if (isPresent(viewDef.styles)) {
|
||||||
|
@ -56,8 +58,10 @@ export class ViewLoader {
|
||||||
let loadedTplAndStyles = <TemplateAndStyles>res[0];
|
let loadedTplAndStyles = <TemplateAndStyles>res[0];
|
||||||
let styles = <string[]>ListWrapper.slice(res, 1);
|
let styles = <string[]>ListWrapper.slice(res, 1);
|
||||||
|
|
||||||
return new TemplateAndStyles(loadedTplAndStyles.template,
|
var templateAndStyles = new TemplateAndStyles(loadedTplAndStyles.template,
|
||||||
loadedTplAndStyles.styles.concat(styles));
|
loadedTplAndStyles.styles.concat(styles));
|
||||||
|
wtfEndTimeRange(r);
|
||||||
|
return templateAndStyles;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import {
|
||||||
cloneAndQueryProtoView,
|
cloneAndQueryProtoView,
|
||||||
camelCaseToDashCase
|
camelCaseToDashCase
|
||||||
} from './util';
|
} from './util';
|
||||||
|
import {WtfScopeFn, wtfLeave, wtfCreateScope} from '../../profile/profile';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Renderer,
|
Renderer,
|
||||||
|
@ -38,6 +39,7 @@ import {DOCUMENT_TOKEN, DOM_REFLECT_PROPERTIES_AS_ATTRIBUTES} from './dom_tokens
|
||||||
|
|
||||||
const REFLECT_PREFIX: string = 'ng-reflect-';
|
const REFLECT_PREFIX: string = 'ng-reflect-';
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DomRenderer extends Renderer {
|
export class DomRenderer extends Renderer {
|
||||||
_document;
|
_document;
|
||||||
|
@ -53,19 +55,24 @@ export class DomRenderer extends Renderer {
|
||||||
this._document = document;
|
this._document = document;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_scope_createRootHostView: WtfScopeFn = wtfCreateScope('DomRenderer#createRootHostView()');
|
||||||
createRootHostView(hostProtoViewRef: RenderProtoViewRef, fragmentCount: number,
|
createRootHostView(hostProtoViewRef: RenderProtoViewRef, fragmentCount: number,
|
||||||
hostElementSelector: string): RenderViewWithFragments {
|
hostElementSelector: string): RenderViewWithFragments {
|
||||||
|
var s = this._scope_createRootHostView();
|
||||||
var hostProtoView = resolveInternalDomProtoView(hostProtoViewRef);
|
var hostProtoView = resolveInternalDomProtoView(hostProtoViewRef);
|
||||||
var element = DOM.querySelector(this._document, hostElementSelector);
|
var element = DOM.querySelector(this._document, hostElementSelector);
|
||||||
if (isBlank(element)) {
|
if (isBlank(element)) {
|
||||||
|
wtfLeave(s);
|
||||||
throw new BaseException(`The selector "${hostElementSelector}" did not match any elements`);
|
throw new BaseException(`The selector "${hostElementSelector}" did not match any elements`);
|
||||||
}
|
}
|
||||||
return this._createView(hostProtoView, element);
|
return wtfLeave(s, this._createView(hostProtoView, element));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_scope_createView = wtfCreateScope('DomRenderer#createView()');
|
||||||
createView(protoViewRef: RenderProtoViewRef, fragmentCount: number): RenderViewWithFragments {
|
createView(protoViewRef: RenderProtoViewRef, fragmentCount: number): RenderViewWithFragments {
|
||||||
|
var s = this._scope_createView();
|
||||||
var protoView = resolveInternalDomProtoView(protoViewRef);
|
var protoView = resolveInternalDomProtoView(protoViewRef);
|
||||||
return this._createView(protoView, null);
|
return wtfLeave(s, this._createView(protoView, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
destroyView(viewRef: RenderViewRef) {
|
destroyView(viewRef: RenderViewRef) {
|
||||||
|
@ -109,11 +116,14 @@ export class DomRenderer extends Renderer {
|
||||||
moveNodesAfterSibling(element, resolveInternalDomFragment(fragmentRef));
|
moveNodesAfterSibling(element, resolveInternalDomFragment(fragmentRef));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_scope_detachFragment = wtfCreateScope('DomRenderer#detachFragment()');
|
||||||
detachFragment(fragmentRef: RenderFragmentRef) {
|
detachFragment(fragmentRef: RenderFragmentRef) {
|
||||||
|
var s = this._scope_detachFragment();
|
||||||
var fragmentNodes = resolveInternalDomFragment(fragmentRef);
|
var fragmentNodes = resolveInternalDomFragment(fragmentRef);
|
||||||
for (var i = 0; i < fragmentNodes.length; i++) {
|
for (var i = 0; i < fragmentNodes.length; i++) {
|
||||||
DOM.remove(fragmentNodes[i]);
|
DOM.remove(fragmentNodes[i]);
|
||||||
}
|
}
|
||||||
|
wtfLeave(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
hydrateView(viewRef: RenderViewRef) {
|
hydrateView(viewRef: RenderViewRef) {
|
||||||
|
@ -203,9 +213,12 @@ export class DomRenderer extends Renderer {
|
||||||
DOM.setText(view.boundTextNodes[textNodeIndex], text);
|
DOM.setText(view.boundTextNodes[textNodeIndex], text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_scope_setEventDispatcher = wtfCreateScope('DomRenderer#setEventDispatcher()');
|
||||||
setEventDispatcher(viewRef: RenderViewRef, dispatcher: any /*api.EventDispatcher*/): void {
|
setEventDispatcher(viewRef: RenderViewRef, dispatcher: any /*api.EventDispatcher*/): void {
|
||||||
|
var s = this._scope_setEventDispatcher();
|
||||||
var view = resolveInternalDomView(viewRef);
|
var view = resolveInternalDomView(viewRef);
|
||||||
view.eventDispatcher = dispatcher;
|
view.eventDispatcher = dispatcher;
|
||||||
|
wtfLeave(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
_createView(protoView: DomProtoView, inplaceElement: HTMLElement): RenderViewWithFragments {
|
_createView(protoView: DomProtoView, inplaceElement: HTMLElement): RenderViewWithFragments {
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
/// This file contains tests that make sense only in Dart
|
||||||
|
library angular2.test.core.wtf_impl;
|
||||||
|
|
||||||
|
import 'package:angular2/test_lib.dart';
|
||||||
|
import 'package:angular2/src/profile/wtf_impl.dart' as impl;
|
||||||
|
|
||||||
|
main() {
|
||||||
|
describe('WTF', () {
|
||||||
|
describe('getArgSize', () {
|
||||||
|
it("should parse args", () {
|
||||||
|
expect(impl.getArgSize('foo#bar')).toBe(0);
|
||||||
|
expect(impl.getArgSize('foo#bar()')).toBe(0);
|
||||||
|
expect(impl.getArgSize('foo#bar(foo bar)')).toBe(1);
|
||||||
|
expect(impl.getArgSize('foo#bar(foo bar, baz q)')).toBe(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue