blob: dc2f3c3c9ada79378033ba3da59534f267d3b834 [file] [log] [blame]
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library dart2js.js_emitter.full_emitter.interceptor_emitter;
import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames;
import '../../elements/entities.dart';
import '../../js/js.dart' as jsAst;
import '../../js/js.dart' show js;
import '../../world.dart' show JClosedWorld;
import '../js_emitter.dart' hide Emitter, EmitterFactory;
import '../model.dart';
import 'emitter.dart';
class InterceptorEmitter extends CodeEmitterHelper {
final JClosedWorld closedWorld;
final Set<jsAst.Name> interceptorInvocationNames = new Set<jsAst.Name>();
InterceptorEmitter(this.closedWorld);
void recordMangledNameOfMemberMethod(MemberEntity member, jsAst.Name name) {
if (closedWorld.interceptorData.isInterceptedMethod(member)) {
interceptorInvocationNames.add(name);
}
}
jsAst.Expression buildGetInterceptorMethod(
jsAst.Name key, Set<ClassEntity> classes) {
InterceptorStubGenerator stubGenerator = new InterceptorStubGenerator(
compiler.options,
closedWorld.commonElements,
backend.emitter,
backend.nativeCodegenEnqueuer,
namer,
backend.oneShotInterceptorData,
backend.customElementsCodegenAnalysis,
compiler.codegenWorldBuilder,
closedWorld);
jsAst.Expression function =
stubGenerator.generateGetInterceptorMethod(classes);
return function;
}
/**
* Emit all versions of the [:getInterceptor:] method.
*/
jsAst.Statement buildGetInterceptorMethods() {
List<jsAst.Statement> parts = <jsAst.Statement>[];
parts.add(js.comment('getInterceptor methods'));
Iterable<jsAst.Name> names =
backend.oneShotInterceptorData.specializedGetInterceptorNames;
for (jsAst.Name name in names) {
Set<ClassEntity> classes =
backend.oneShotInterceptorData.getSpecializedGetInterceptorsFor(name);
parts.add(js.statement('#.# = #', [
namer.globalObjectForLibrary(
closedWorld.commonElements.interceptorsLibrary),
name,
buildGetInterceptorMethod(name, classes)
]));
}
return new jsAst.Block(parts);
}
jsAst.Statement buildOneShotInterceptors() {
List<jsAst.Statement> parts = <jsAst.Statement>[];
Iterable<jsAst.Name> names =
backend.oneShotInterceptorData.oneShotInterceptorNames;
InterceptorStubGenerator stubGenerator = new InterceptorStubGenerator(
compiler.options,
closedWorld.commonElements,
backend.emitter,
backend.nativeCodegenEnqueuer,
namer,
backend.oneShotInterceptorData,
backend.customElementsCodegenAnalysis,
compiler.codegenWorldBuilder,
closedWorld);
String globalObject = namer
.globalObjectForLibrary(closedWorld.commonElements.interceptorsLibrary);
for (jsAst.Name name in names) {
jsAst.Expression function =
stubGenerator.generateOneShotInterceptor(name);
parts.add(js.statement('${globalObject}.# = #', [name, function]));
}
return new jsAst.Block(parts);
}
/**
* If [JSInvocationMirror._invokeOn] has been compiled, emit all the
* possible selector names that are intercepted into the
* [interceptedNames] embedded global. The implementation of
* [_invokeOn] will use it to determine whether it should call the
* method with an extra parameter.
*/
jsAst.ObjectInitializer generateInterceptedNamesSet() {
// We could also generate the list of intercepted names at
// runtime, by running through the subclasses of Interceptor
// (which can easily be identified).
if (!closedWorld.backendUsage.isInvokeOnUsed) return null;
Iterable<jsAst.Name> invocationNames = interceptorInvocationNames.toList()
..sort();
;
List<jsAst.Property> properties = invocationNames.map((jsAst.Name name) {
return new jsAst.Property(js.quoteName(name), js.number(1));
}).toList();
return new jsAst.ObjectInitializer(properties, isOneLiner: true);
}
/**
* Emit initializer for `typeToInterceptorMap` data structure used by
* `findInterceptorForType`. See declaration of `typeToInterceptor` in
* `interceptors.dart`.
*/
jsAst.Statement buildTypeToInterceptorMap(Program program) {
jsAst.Expression array = program.typeToInterceptorMap;
if (array == null) return js.comment("Empty type-to-interceptor map.");
jsAst.Expression typeToInterceptorMap = emitter
.generateEmbeddedGlobalAccess(embeddedNames.TYPE_TO_INTERCEPTOR_MAP);
return js.statement('# = #', [typeToInterceptorMap, array]);
}
}